editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap, ShowScrollbar,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{
  164        DiagnosticSeverity, GitGutterSetting, GoToDiagnosticSeverityFilter, ProjectSettings,
  165    },
  166};
  167use rand::seq::SliceRandom;
  168use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  169use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  170use selections_collection::{
  171    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  172};
  173use serde::{Deserialize, Serialize};
  174use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  175use smallvec::{SmallVec, smallvec};
  176use snippet::Snippet;
  177use std::{
  178    any::TypeId,
  179    borrow::Cow,
  180    cell::OnceCell,
  181    cell::RefCell,
  182    cmp::{self, Ordering, Reverse},
  183    iter::Peekable,
  184    mem,
  185    num::NonZeroU32,
  186    ops::Not,
  187    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  188    path::{Path, PathBuf},
  189    rc::Rc,
  190    sync::Arc,
  191    time::{Duration, Instant},
  192};
  193use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  194use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  195use theme::{
  196    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  197    observe_buffer_font_size_adjustment,
  198};
  199use ui::{
  200    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  201    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  202};
  203use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  204use workspace::{
  205    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  206    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  207    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  208    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  209    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  210    searchable::SearchEvent,
  211};
  212
  213use crate::{
  214    code_context_menus::CompletionsMenuSource,
  215    editor_settings::MultiCursorModifier,
  216    hover_links::{find_url, find_url_from_range},
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  223const MAX_LINE_LEN: usize = 1024;
  224const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  225const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  226pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  227#[doc(hidden)]
  228pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  229pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  230
  231pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  234
  235pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  236pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  237pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  238
  239pub type RenderDiffHunkControlsFn = Arc<
  240    dyn Fn(
  241        u32,
  242        &DiffHunkStatus,
  243        Range<Anchor>,
  244        bool,
  245        Pixels,
  246        &Entity<Editor>,
  247        &mut Window,
  248        &mut App,
  249    ) -> AnyElement,
  250>;
  251
  252enum ReportEditorEvent {
  253    Saved { auto_saved: bool },
  254    EditorOpened,
  255    Closed,
  256}
  257
  258impl ReportEditorEvent {
  259    pub fn event_type(&self) -> &'static str {
  260        match self {
  261            Self::Saved { .. } => "Editor Saved",
  262            Self::EditorOpened => "Editor Opened",
  263            Self::Closed => "Editor Closed",
  264        }
  265    }
  266}
  267
  268struct InlineValueCache {
  269    enabled: bool,
  270    inlays: Vec<InlayId>,
  271    refresh_task: Task<Option<()>>,
  272}
  273
  274impl InlineValueCache {
  275    fn new(enabled: bool) -> Self {
  276        Self {
  277            enabled,
  278            inlays: Vec::new(),
  279            refresh_task: Task::ready(None),
  280        }
  281    }
  282}
  283
  284#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  285pub enum InlayId {
  286    EditPrediction(usize),
  287    DebuggerValue(usize),
  288    // LSP
  289    Hint(usize),
  290    Color(usize),
  291}
  292
  293impl InlayId {
  294    fn id(&self) -> usize {
  295        match self {
  296            Self::EditPrediction(id) => *id,
  297            Self::DebuggerValue(id) => *id,
  298            Self::Hint(id) => *id,
  299            Self::Color(id) => *id,
  300        }
  301    }
  302}
  303
  304pub enum ActiveDebugLine {}
  305pub enum DebugStackFrameLine {}
  306enum DocumentHighlightRead {}
  307enum DocumentHighlightWrite {}
  308enum InputComposition {}
  309pub enum PendingInput {}
  310enum SelectedTextHighlight {}
  311
  312pub enum ConflictsOuter {}
  313pub enum ConflictsOurs {}
  314pub enum ConflictsTheirs {}
  315pub enum ConflictsOursMarker {}
  316pub enum ConflictsTheirsMarker {}
  317
  318#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  319pub enum Navigated {
  320    Yes,
  321    No,
  322}
  323
  324impl Navigated {
  325    pub fn from_bool(yes: bool) -> Navigated {
  326        if yes { Navigated::Yes } else { Navigated::No }
  327    }
  328}
  329
  330#[derive(Debug, Clone, PartialEq, Eq)]
  331enum DisplayDiffHunk {
  332    Folded {
  333        display_row: DisplayRow,
  334    },
  335    Unfolded {
  336        is_created_file: bool,
  337        diff_base_byte_range: Range<usize>,
  338        display_row_range: Range<DisplayRow>,
  339        multi_buffer_range: Range<Anchor>,
  340        status: DiffHunkStatus,
  341    },
  342}
  343
  344pub enum HideMouseCursorOrigin {
  345    TypingAction,
  346    MovementAction,
  347}
  348
  349pub fn init_settings(cx: &mut App) {
  350    EditorSettings::register(cx);
  351}
  352
  353pub fn init(cx: &mut App) {
  354    init_settings(cx);
  355
  356    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  357
  358    workspace::register_project_item::<Editor>(cx);
  359    workspace::FollowableViewRegistry::register::<Editor>(cx);
  360    workspace::register_serializable_item::<Editor>(cx);
  361
  362    cx.observe_new(
  363        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  364            workspace.register_action(Editor::new_file);
  365            workspace.register_action(Editor::new_file_vertical);
  366            workspace.register_action(Editor::new_file_horizontal);
  367            workspace.register_action(Editor::cancel_language_server_work);
  368            workspace.register_action(Editor::toggle_focus);
  369        },
  370    )
  371    .detach();
  372
  373    cx.on_action(move |_: &workspace::NewFile, cx| {
  374        let app_state = workspace::AppState::global(cx);
  375        if let Some(app_state) = app_state.upgrade() {
  376            workspace::open_new(
  377                Default::default(),
  378                app_state,
  379                cx,
  380                |workspace, window, cx| {
  381                    Editor::new_file(workspace, &Default::default(), window, cx)
  382                },
  383            )
  384            .detach();
  385        }
  386    });
  387    cx.on_action(move |_: &workspace::NewWindow, cx| {
  388        let app_state = workspace::AppState::global(cx);
  389        if let Some(app_state) = app_state.upgrade() {
  390            workspace::open_new(
  391                Default::default(),
  392                app_state,
  393                cx,
  394                |workspace, window, cx| {
  395                    cx.activate(true);
  396                    Editor::new_file(workspace, &Default::default(), window, cx)
  397                },
  398            )
  399            .detach();
  400        }
  401    });
  402}
  403
  404pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  405    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  406}
  407
  408pub trait DiagnosticRenderer {
  409    fn render_group(
  410        &self,
  411        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  412        buffer_id: BufferId,
  413        snapshot: EditorSnapshot,
  414        editor: WeakEntity<Editor>,
  415        cx: &mut App,
  416    ) -> Vec<BlockProperties<Anchor>>;
  417
  418    fn render_hover(
  419        &self,
  420        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  421        range: Range<Point>,
  422        buffer_id: BufferId,
  423        cx: &mut App,
  424    ) -> Option<Entity<markdown::Markdown>>;
  425
  426    fn open_link(
  427        &self,
  428        editor: &mut Editor,
  429        link: SharedString,
  430        window: &mut Window,
  431        cx: &mut Context<Editor>,
  432    );
  433}
  434
  435pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  436
  437impl GlobalDiagnosticRenderer {
  438    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  439        cx.try_global::<Self>().map(|g| g.0.clone())
  440    }
  441}
  442
  443impl gpui::Global for GlobalDiagnosticRenderer {}
  444pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  445    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  446}
  447
  448pub struct SearchWithinRange;
  449
  450trait InvalidationRegion {
  451    fn ranges(&self) -> &[Range<Anchor>];
  452}
  453
  454#[derive(Clone, Debug, PartialEq)]
  455pub enum SelectPhase {
  456    Begin {
  457        position: DisplayPoint,
  458        add: bool,
  459        click_count: usize,
  460    },
  461    BeginColumnar {
  462        position: DisplayPoint,
  463        reset: bool,
  464        mode: ColumnarMode,
  465        goal_column: u32,
  466    },
  467    Extend {
  468        position: DisplayPoint,
  469        click_count: usize,
  470    },
  471    Update {
  472        position: DisplayPoint,
  473        goal_column: u32,
  474        scroll_delta: gpui::Point<f32>,
  475    },
  476    End,
  477}
  478
  479#[derive(Clone, Debug, PartialEq)]
  480pub enum ColumnarMode {
  481    FromMouse,
  482    FromSelection,
  483}
  484
  485#[derive(Clone, Debug)]
  486pub enum SelectMode {
  487    Character,
  488    Word(Range<Anchor>),
  489    Line(Range<Anchor>),
  490    All,
  491}
  492
  493#[derive(Clone, PartialEq, Eq, Debug)]
  494pub enum EditorMode {
  495    SingleLine,
  496    AutoHeight {
  497        min_lines: usize,
  498        max_lines: Option<usize>,
  499    },
  500    Full {
  501        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  502        scale_ui_elements_with_buffer_font_size: bool,
  503        /// When set to `true`, the editor will render a background for the active line.
  504        show_active_line_background: bool,
  505        /// When set to `true`, the editor's height will be determined by its content.
  506        sized_by_content: bool,
  507    },
  508    Minimap {
  509        parent: WeakEntity<Editor>,
  510    },
  511}
  512
  513impl EditorMode {
  514    pub fn full() -> Self {
  515        Self::Full {
  516            scale_ui_elements_with_buffer_font_size: true,
  517            show_active_line_background: true,
  518            sized_by_content: false,
  519        }
  520    }
  521
  522    #[inline]
  523    pub fn is_full(&self) -> bool {
  524        matches!(self, Self::Full { .. })
  525    }
  526
  527    #[inline]
  528    pub fn is_single_line(&self) -> bool {
  529        matches!(self, Self::SingleLine { .. })
  530    }
  531
  532    #[inline]
  533    fn is_minimap(&self) -> bool {
  534        matches!(self, Self::Minimap { .. })
  535    }
  536}
  537
  538#[derive(Copy, Clone, Debug)]
  539pub enum SoftWrap {
  540    /// Prefer not to wrap at all.
  541    ///
  542    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  543    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  544    GitDiff,
  545    /// Prefer a single line generally, unless an overly long line is encountered.
  546    None,
  547    /// Soft wrap lines that exceed the editor width.
  548    EditorWidth,
  549    /// Soft wrap lines at the preferred line length.
  550    Column(u32),
  551    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  552    Bounded(u32),
  553}
  554
  555#[derive(Clone)]
  556pub struct EditorStyle {
  557    pub background: Hsla,
  558    pub border: Hsla,
  559    pub local_player: PlayerColor,
  560    pub text: TextStyle,
  561    pub scrollbar_width: Pixels,
  562    pub syntax: Arc<SyntaxTheme>,
  563    pub status: StatusColors,
  564    pub inlay_hints_style: HighlightStyle,
  565    pub edit_prediction_styles: EditPredictionStyles,
  566    pub unnecessary_code_fade: f32,
  567    pub show_underlines: bool,
  568}
  569
  570impl Default for EditorStyle {
  571    fn default() -> Self {
  572        Self {
  573            background: Hsla::default(),
  574            border: Hsla::default(),
  575            local_player: PlayerColor::default(),
  576            text: TextStyle::default(),
  577            scrollbar_width: Pixels::default(),
  578            syntax: Default::default(),
  579            // HACK: Status colors don't have a real default.
  580            // We should look into removing the status colors from the editor
  581            // style and retrieve them directly from the theme.
  582            status: StatusColors::dark(),
  583            inlay_hints_style: HighlightStyle::default(),
  584            edit_prediction_styles: EditPredictionStyles {
  585                insertion: HighlightStyle::default(),
  586                whitespace: HighlightStyle::default(),
  587            },
  588            unnecessary_code_fade: Default::default(),
  589            show_underlines: true,
  590        }
  591    }
  592}
  593
  594pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  595    let show_background = language_settings::language_settings(None, None, cx)
  596        .inlay_hints
  597        .show_background;
  598
  599    HighlightStyle {
  600        color: Some(cx.theme().status().hint),
  601        background_color: show_background.then(|| cx.theme().status().hint_background),
  602        ..HighlightStyle::default()
  603    }
  604}
  605
  606pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  607    EditPredictionStyles {
  608        insertion: HighlightStyle {
  609            color: Some(cx.theme().status().predictive),
  610            ..HighlightStyle::default()
  611        },
  612        whitespace: HighlightStyle {
  613            background_color: Some(cx.theme().status().created_background),
  614            ..HighlightStyle::default()
  615        },
  616    }
  617}
  618
  619type CompletionId = usize;
  620
  621pub(crate) enum EditDisplayMode {
  622    TabAccept,
  623    DiffPopover,
  624    Inline,
  625}
  626
  627enum EditPrediction {
  628    Edit {
  629        edits: Vec<(Range<Anchor>, String)>,
  630        edit_preview: Option<EditPreview>,
  631        display_mode: EditDisplayMode,
  632        snapshot: BufferSnapshot,
  633    },
  634    Move {
  635        target: Anchor,
  636        snapshot: BufferSnapshot,
  637    },
  638}
  639
  640struct EditPredictionState {
  641    inlay_ids: Vec<InlayId>,
  642    completion: EditPrediction,
  643    completion_id: Option<SharedString>,
  644    invalidation_range: Range<Anchor>,
  645}
  646
  647enum EditPredictionSettings {
  648    Disabled,
  649    Enabled {
  650        show_in_menu: bool,
  651        preview_requires_modifier: bool,
  652    },
  653}
  654
  655enum EditPredictionHighlight {}
  656
  657#[derive(Debug, Clone)]
  658struct InlineDiagnostic {
  659    message: SharedString,
  660    group_id: usize,
  661    is_primary: bool,
  662    start: Point,
  663    severity: lsp::DiagnosticSeverity,
  664}
  665
  666pub enum MenuEditPredictionsPolicy {
  667    Never,
  668    ByProvider,
  669}
  670
  671pub enum EditPredictionPreview {
  672    /// Modifier is not pressed
  673    Inactive { released_too_fast: bool },
  674    /// Modifier pressed
  675    Active {
  676        since: Instant,
  677        previous_scroll_position: Option<ScrollAnchor>,
  678    },
  679}
  680
  681impl EditPredictionPreview {
  682    pub fn released_too_fast(&self) -> bool {
  683        match self {
  684            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  685            EditPredictionPreview::Active { .. } => false,
  686        }
  687    }
  688
  689    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  690        if let EditPredictionPreview::Active {
  691            previous_scroll_position,
  692            ..
  693        } = self
  694        {
  695            *previous_scroll_position = scroll_position;
  696        }
  697    }
  698}
  699
  700pub struct ContextMenuOptions {
  701    pub min_entries_visible: usize,
  702    pub max_entries_visible: usize,
  703    pub placement: Option<ContextMenuPlacement>,
  704}
  705
  706#[derive(Debug, Clone, PartialEq, Eq)]
  707pub enum ContextMenuPlacement {
  708    Above,
  709    Below,
  710}
  711
  712#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  713struct EditorActionId(usize);
  714
  715impl EditorActionId {
  716    pub fn post_inc(&mut self) -> Self {
  717        let answer = self.0;
  718
  719        *self = Self(answer + 1);
  720
  721        Self(answer)
  722    }
  723}
  724
  725// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  726// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  727
  728type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  729type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  730
  731#[derive(Default)]
  732struct ScrollbarMarkerState {
  733    scrollbar_size: Size<Pixels>,
  734    dirty: bool,
  735    markers: Arc<[PaintQuad]>,
  736    pending_refresh: Option<Task<Result<()>>>,
  737}
  738
  739impl ScrollbarMarkerState {
  740    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  741        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  742    }
  743}
  744
  745#[derive(Clone, Copy, PartialEq, Eq)]
  746pub enum MinimapVisibility {
  747    Disabled,
  748    Enabled {
  749        /// The configuration currently present in the users settings.
  750        setting_configuration: bool,
  751        /// Whether to override the currently set visibility from the users setting.
  752        toggle_override: bool,
  753    },
  754}
  755
  756impl MinimapVisibility {
  757    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  758        if mode.is_full() {
  759            Self::Enabled {
  760                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  761                toggle_override: false,
  762            }
  763        } else {
  764            Self::Disabled
  765        }
  766    }
  767
  768    fn hidden(&self) -> Self {
  769        match *self {
  770            Self::Enabled {
  771                setting_configuration,
  772                ..
  773            } => Self::Enabled {
  774                setting_configuration,
  775                toggle_override: setting_configuration,
  776            },
  777            Self::Disabled => Self::Disabled,
  778        }
  779    }
  780
  781    fn disabled(&self) -> bool {
  782        matches!(*self, Self::Disabled)
  783    }
  784
  785    fn settings_visibility(&self) -> bool {
  786        match *self {
  787            Self::Enabled {
  788                setting_configuration,
  789                ..
  790            } => setting_configuration,
  791            _ => false,
  792        }
  793    }
  794
  795    fn visible(&self) -> bool {
  796        match *self {
  797            Self::Enabled {
  798                setting_configuration,
  799                toggle_override,
  800            } => setting_configuration ^ toggle_override,
  801            _ => false,
  802        }
  803    }
  804
  805    fn toggle_visibility(&self) -> Self {
  806        match *self {
  807            Self::Enabled {
  808                toggle_override,
  809                setting_configuration,
  810            } => Self::Enabled {
  811                setting_configuration,
  812                toggle_override: !toggle_override,
  813            },
  814            Self::Disabled => Self::Disabled,
  815        }
  816    }
  817}
  818
  819#[derive(Clone, Debug)]
  820struct RunnableTasks {
  821    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  822    offset: multi_buffer::Anchor,
  823    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  824    column: u32,
  825    // Values of all named captures, including those starting with '_'
  826    extra_variables: HashMap<String, String>,
  827    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  828    context_range: Range<BufferOffset>,
  829}
  830
  831impl RunnableTasks {
  832    fn resolve<'a>(
  833        &'a self,
  834        cx: &'a task::TaskContext,
  835    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  836        self.templates.iter().filter_map(|(kind, template)| {
  837            template
  838                .resolve_task(&kind.to_id_base(), cx)
  839                .map(|task| (kind.clone(), task))
  840        })
  841    }
  842}
  843
  844#[derive(Clone)]
  845pub struct ResolvedTasks {
  846    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  847    position: Anchor,
  848}
  849
  850#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  851struct BufferOffset(usize);
  852
  853// Addons allow storing per-editor state in other crates (e.g. Vim)
  854pub trait Addon: 'static {
  855    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  856
  857    fn render_buffer_header_controls(
  858        &self,
  859        _: &ExcerptInfo,
  860        _: &Window,
  861        _: &App,
  862    ) -> Option<AnyElement> {
  863        None
  864    }
  865
  866    fn to_any(&self) -> &dyn std::any::Any;
  867
  868    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  869        None
  870    }
  871}
  872
  873struct ChangeLocation {
  874    current: Option<Vec<Anchor>>,
  875    original: Vec<Anchor>,
  876}
  877impl ChangeLocation {
  878    fn locations(&self) -> &[Anchor] {
  879        self.current.as_ref().unwrap_or(&self.original)
  880    }
  881}
  882
  883/// A set of caret positions, registered when the editor was edited.
  884pub struct ChangeList {
  885    changes: Vec<ChangeLocation>,
  886    /// Currently "selected" change.
  887    position: Option<usize>,
  888}
  889
  890impl ChangeList {
  891    pub fn new() -> Self {
  892        Self {
  893            changes: Vec::new(),
  894            position: None,
  895        }
  896    }
  897
  898    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  899    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  900    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  901        if self.changes.is_empty() {
  902            return None;
  903        }
  904
  905        let prev = self.position.unwrap_or(self.changes.len());
  906        let next = if direction == Direction::Prev {
  907            prev.saturating_sub(count)
  908        } else {
  909            (prev + count).min(self.changes.len() - 1)
  910        };
  911        self.position = Some(next);
  912        self.changes.get(next).map(|change| change.locations())
  913    }
  914
  915    /// Adds a new change to the list, resetting the change list position.
  916    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  917        self.position.take();
  918        if let Some(last) = self.changes.last_mut()
  919            && group
  920        {
  921            last.current = Some(new_positions)
  922        } else {
  923            self.changes.push(ChangeLocation {
  924                original: new_positions,
  925                current: None,
  926            });
  927        }
  928    }
  929
  930    pub fn last(&self) -> Option<&[Anchor]> {
  931        self.changes.last().map(|change| change.locations())
  932    }
  933
  934    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  935        self.changes.last().map(|change| change.original.as_slice())
  936    }
  937
  938    pub fn invert_last_group(&mut self) {
  939        if let Some(last) = self.changes.last_mut()
  940            && let Some(current) = last.current.as_mut()
  941        {
  942            mem::swap(&mut last.original, current);
  943        }
  944    }
  945}
  946
  947#[derive(Clone)]
  948struct InlineBlamePopoverState {
  949    scroll_handle: ScrollHandle,
  950    commit_message: Option<ParsedCommitMessage>,
  951    markdown: Entity<Markdown>,
  952}
  953
  954struct InlineBlamePopover {
  955    position: gpui::Point<Pixels>,
  956    hide_task: Option<Task<()>>,
  957    popover_bounds: Option<Bounds<Pixels>>,
  958    popover_state: InlineBlamePopoverState,
  959    keyboard_grace: bool,
  960}
  961
  962enum SelectionDragState {
  963    /// State when no drag related activity is detected.
  964    None,
  965    /// State when the mouse is down on a selection that is about to be dragged.
  966    ReadyToDrag {
  967        selection: Selection<Anchor>,
  968        click_position: gpui::Point<Pixels>,
  969        mouse_down_time: Instant,
  970    },
  971    /// State when the mouse is dragging the selection in the editor.
  972    Dragging {
  973        selection: Selection<Anchor>,
  974        drop_cursor: Selection<Anchor>,
  975        hide_drop_cursor: bool,
  976    },
  977}
  978
  979enum ColumnarSelectionState {
  980    FromMouse {
  981        selection_tail: Anchor,
  982        display_point: Option<DisplayPoint>,
  983    },
  984    FromSelection {
  985        selection_tail: Anchor,
  986    },
  987}
  988
  989/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  990/// a breakpoint on them.
  991#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  992struct PhantomBreakpointIndicator {
  993    display_row: DisplayRow,
  994    /// There's a small debounce between hovering over the line and showing the indicator.
  995    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  996    is_active: bool,
  997    collides_with_existing_breakpoint: bool,
  998}
  999
 1000/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1001///
 1002/// See the [module level documentation](self) for more information.
 1003pub struct Editor {
 1004    focus_handle: FocusHandle,
 1005    last_focused_descendant: Option<WeakFocusHandle>,
 1006    /// The text buffer being edited
 1007    buffer: Entity<MultiBuffer>,
 1008    /// Map of how text in the buffer should be displayed.
 1009    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1010    pub display_map: Entity<DisplayMap>,
 1011    pub selections: SelectionsCollection,
 1012    pub scroll_manager: ScrollManager,
 1013    /// When inline assist editors are linked, they all render cursors because
 1014    /// typing enters text into each of them, even the ones that aren't focused.
 1015    pub(crate) show_cursor_when_unfocused: bool,
 1016    columnar_selection_state: Option<ColumnarSelectionState>,
 1017    add_selections_state: Option<AddSelectionsState>,
 1018    select_next_state: Option<SelectNextState>,
 1019    select_prev_state: Option<SelectNextState>,
 1020    selection_history: SelectionHistory,
 1021    defer_selection_effects: bool,
 1022    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1023    autoclose_regions: Vec<AutocloseRegion>,
 1024    snippet_stack: InvalidationStack<SnippetState>,
 1025    select_syntax_node_history: SelectSyntaxNodeHistory,
 1026    ime_transaction: Option<TransactionId>,
 1027    pub diagnostics_max_severity: DiagnosticSeverity,
 1028    active_diagnostics: ActiveDiagnostic,
 1029    show_inline_diagnostics: bool,
 1030    inline_diagnostics_update: Task<()>,
 1031    inline_diagnostics_enabled: bool,
 1032    diagnostics_enabled: bool,
 1033    word_completions_enabled: bool,
 1034    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1035    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1036    hard_wrap: Option<usize>,
 1037    project: Option<Entity<Project>>,
 1038    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1039    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1040    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1041    blink_manager: Entity<BlinkManager>,
 1042    show_cursor_names: bool,
 1043    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1044    pub show_local_selections: bool,
 1045    mode: EditorMode,
 1046    show_breadcrumbs: bool,
 1047    show_gutter: bool,
 1048    show_scrollbars: ScrollbarAxes,
 1049    minimap_visibility: MinimapVisibility,
 1050    offset_content: bool,
 1051    disable_expand_excerpt_buttons: bool,
 1052    show_line_numbers: Option<bool>,
 1053    use_relative_line_numbers: Option<bool>,
 1054    show_git_diff_gutter: Option<bool>,
 1055    show_code_actions: Option<bool>,
 1056    show_runnables: Option<bool>,
 1057    show_breakpoints: Option<bool>,
 1058    show_wrap_guides: Option<bool>,
 1059    show_indent_guides: Option<bool>,
 1060    placeholder_text: Option<Arc<str>>,
 1061    highlight_order: usize,
 1062    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1063    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1064    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1065    scrollbar_marker_state: ScrollbarMarkerState,
 1066    active_indent_guides_state: ActiveIndentGuidesState,
 1067    nav_history: Option<ItemNavHistory>,
 1068    context_menu: RefCell<Option<CodeContextMenu>>,
 1069    context_menu_options: Option<ContextMenuOptions>,
 1070    mouse_context_menu: Option<MouseContextMenu>,
 1071    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1072    inline_blame_popover: Option<InlineBlamePopover>,
 1073    inline_blame_popover_show_task: Option<Task<()>>,
 1074    signature_help_state: SignatureHelpState,
 1075    auto_signature_help: Option<bool>,
 1076    find_all_references_task_sources: Vec<Anchor>,
 1077    next_completion_id: CompletionId,
 1078    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1079    code_actions_task: Option<Task<Result<()>>>,
 1080    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1081    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1082    document_highlights_task: Option<Task<()>>,
 1083    linked_editing_range_task: Option<Task<Option<()>>>,
 1084    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1085    pending_rename: Option<RenameState>,
 1086    searchable: bool,
 1087    cursor_shape: CursorShape,
 1088    current_line_highlight: Option<CurrentLineHighlight>,
 1089    collapse_matches: bool,
 1090    autoindent_mode: Option<AutoindentMode>,
 1091    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1092    input_enabled: bool,
 1093    use_modal_editing: bool,
 1094    read_only: bool,
 1095    leader_id: Option<CollaboratorId>,
 1096    remote_id: Option<ViewId>,
 1097    pub hover_state: HoverState,
 1098    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1099    gutter_hovered: bool,
 1100    hovered_link_state: Option<HoveredLinkState>,
 1101    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1102    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1103    active_edit_prediction: Option<EditPredictionState>,
 1104    /// Used to prevent flickering as the user types while the menu is open
 1105    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1106    edit_prediction_settings: EditPredictionSettings,
 1107    edit_predictions_hidden_for_vim_mode: bool,
 1108    show_edit_predictions_override: Option<bool>,
 1109    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1110    edit_prediction_preview: EditPredictionPreview,
 1111    edit_prediction_indent_conflict: bool,
 1112    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1113    inlay_hint_cache: InlayHintCache,
 1114    next_inlay_id: usize,
 1115    _subscriptions: Vec<Subscription>,
 1116    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1117    gutter_dimensions: GutterDimensions,
 1118    style: Option<EditorStyle>,
 1119    text_style_refinement: Option<TextStyleRefinement>,
 1120    next_editor_action_id: EditorActionId,
 1121    editor_actions: Rc<
 1122        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1123    >,
 1124    use_autoclose: bool,
 1125    use_auto_surround: bool,
 1126    auto_replace_emoji_shortcode: bool,
 1127    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1128    show_git_blame_gutter: bool,
 1129    show_git_blame_inline: bool,
 1130    show_git_blame_inline_delay_task: Option<Task<()>>,
 1131    git_blame_inline_enabled: bool,
 1132    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1133    serialize_dirty_buffers: bool,
 1134    show_selection_menu: Option<bool>,
 1135    blame: Option<Entity<GitBlame>>,
 1136    blame_subscription: Option<Subscription>,
 1137    custom_context_menu: Option<
 1138        Box<
 1139            dyn 'static
 1140                + Fn(
 1141                    &mut Self,
 1142                    DisplayPoint,
 1143                    &mut Window,
 1144                    &mut Context<Self>,
 1145                ) -> Option<Entity<ui::ContextMenu>>,
 1146        >,
 1147    >,
 1148    last_bounds: Option<Bounds<Pixels>>,
 1149    last_position_map: Option<Rc<PositionMap>>,
 1150    expect_bounds_change: Option<Bounds<Pixels>>,
 1151    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1152    tasks_update_task: Option<Task<()>>,
 1153    breakpoint_store: Option<Entity<BreakpointStore>>,
 1154    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1155    hovered_diff_hunk_row: Option<DisplayRow>,
 1156    pull_diagnostics_task: Task<()>,
 1157    in_project_search: bool,
 1158    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1159    breadcrumb_header: Option<String>,
 1160    focused_block: Option<FocusedBlock>,
 1161    next_scroll_position: NextScrollCursorCenterTopBottom,
 1162    addons: HashMap<TypeId, Box<dyn Addon>>,
 1163    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1164    load_diff_task: Option<Shared<Task<()>>>,
 1165    /// Whether we are temporarily displaying a diff other than git's
 1166    temporary_diff_override: bool,
 1167    selection_mark_mode: bool,
 1168    toggle_fold_multiple_buffers: Task<()>,
 1169    _scroll_cursor_center_top_bottom_task: Task<()>,
 1170    serialize_selections: Task<()>,
 1171    serialize_folds: Task<()>,
 1172    mouse_cursor_hidden: bool,
 1173    minimap: Option<Entity<Self>>,
 1174    hide_mouse_mode: HideMouseMode,
 1175    pub change_list: ChangeList,
 1176    inline_value_cache: InlineValueCache,
 1177    selection_drag_state: SelectionDragState,
 1178    next_color_inlay_id: usize,
 1179    colors: Option<LspColorData>,
 1180    folding_newlines: Task<()>,
 1181}
 1182
 1183#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1184enum NextScrollCursorCenterTopBottom {
 1185    #[default]
 1186    Center,
 1187    Top,
 1188    Bottom,
 1189}
 1190
 1191impl NextScrollCursorCenterTopBottom {
 1192    fn next(&self) -> Self {
 1193        match self {
 1194            Self::Center => Self::Top,
 1195            Self::Top => Self::Bottom,
 1196            Self::Bottom => Self::Center,
 1197        }
 1198    }
 1199}
 1200
 1201#[derive(Clone)]
 1202pub struct EditorSnapshot {
 1203    pub mode: EditorMode,
 1204    show_gutter: bool,
 1205    show_line_numbers: Option<bool>,
 1206    show_git_diff_gutter: Option<bool>,
 1207    show_code_actions: Option<bool>,
 1208    show_runnables: Option<bool>,
 1209    show_breakpoints: Option<bool>,
 1210    git_blame_gutter_max_author_length: Option<usize>,
 1211    pub display_snapshot: DisplaySnapshot,
 1212    pub placeholder_text: Option<Arc<str>>,
 1213    is_focused: bool,
 1214    scroll_anchor: ScrollAnchor,
 1215    ongoing_scroll: OngoingScroll,
 1216    current_line_highlight: CurrentLineHighlight,
 1217    gutter_hovered: bool,
 1218}
 1219
 1220#[derive(Default, Debug, Clone, Copy)]
 1221pub struct GutterDimensions {
 1222    pub left_padding: Pixels,
 1223    pub right_padding: Pixels,
 1224    pub width: Pixels,
 1225    pub margin: Pixels,
 1226    pub git_blame_entries_width: Option<Pixels>,
 1227}
 1228
 1229impl GutterDimensions {
 1230    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1231        Self {
 1232            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1233            ..Default::default()
 1234        }
 1235    }
 1236
 1237    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1238        -cx.text_system().descent(font_id, font_size)
 1239    }
 1240    /// The full width of the space taken up by the gutter.
 1241    pub fn full_width(&self) -> Pixels {
 1242        self.margin + self.width
 1243    }
 1244
 1245    /// The width of the space reserved for the fold indicators,
 1246    /// use alongside 'justify_end' and `gutter_width` to
 1247    /// right align content with the line numbers
 1248    pub fn fold_area_width(&self) -> Pixels {
 1249        self.margin + self.right_padding
 1250    }
 1251}
 1252
 1253struct CharacterDimensions {
 1254    em_width: Pixels,
 1255    em_advance: Pixels,
 1256    line_height: Pixels,
 1257}
 1258
 1259#[derive(Debug)]
 1260pub struct RemoteSelection {
 1261    pub replica_id: ReplicaId,
 1262    pub selection: Selection<Anchor>,
 1263    pub cursor_shape: CursorShape,
 1264    pub collaborator_id: CollaboratorId,
 1265    pub line_mode: bool,
 1266    pub user_name: Option<SharedString>,
 1267    pub color: PlayerColor,
 1268}
 1269
 1270#[derive(Clone, Debug)]
 1271struct SelectionHistoryEntry {
 1272    selections: Arc<[Selection<Anchor>]>,
 1273    select_next_state: Option<SelectNextState>,
 1274    select_prev_state: Option<SelectNextState>,
 1275    add_selections_state: Option<AddSelectionsState>,
 1276}
 1277
 1278#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1279enum SelectionHistoryMode {
 1280    Normal,
 1281    Undoing,
 1282    Redoing,
 1283    Skipping,
 1284}
 1285
 1286#[derive(Clone, PartialEq, Eq, Hash)]
 1287struct HoveredCursor {
 1288    replica_id: u16,
 1289    selection_id: usize,
 1290}
 1291
 1292impl Default for SelectionHistoryMode {
 1293    fn default() -> Self {
 1294        Self::Normal
 1295    }
 1296}
 1297
 1298#[derive(Debug)]
 1299/// SelectionEffects controls the side-effects of updating the selection.
 1300///
 1301/// The default behaviour does "what you mostly want":
 1302/// - it pushes to the nav history if the cursor moved by >10 lines
 1303/// - it re-triggers completion requests
 1304/// - it scrolls to fit
 1305///
 1306/// You might want to modify these behaviours. For example when doing a "jump"
 1307/// like go to definition, we always want to add to nav history; but when scrolling
 1308/// in vim mode we never do.
 1309///
 1310/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1311/// move.
 1312#[derive(Clone)]
 1313pub struct SelectionEffects {
 1314    nav_history: Option<bool>,
 1315    completions: bool,
 1316    scroll: Option<Autoscroll>,
 1317}
 1318
 1319impl Default for SelectionEffects {
 1320    fn default() -> Self {
 1321        Self {
 1322            nav_history: None,
 1323            completions: true,
 1324            scroll: Some(Autoscroll::fit()),
 1325        }
 1326    }
 1327}
 1328impl SelectionEffects {
 1329    pub fn scroll(scroll: Autoscroll) -> Self {
 1330        Self {
 1331            scroll: Some(scroll),
 1332            ..Default::default()
 1333        }
 1334    }
 1335
 1336    pub fn no_scroll() -> Self {
 1337        Self {
 1338            scroll: None,
 1339            ..Default::default()
 1340        }
 1341    }
 1342
 1343    pub fn completions(self, completions: bool) -> Self {
 1344        Self {
 1345            completions,
 1346            ..self
 1347        }
 1348    }
 1349
 1350    pub fn nav_history(self, nav_history: bool) -> Self {
 1351        Self {
 1352            nav_history: Some(nav_history),
 1353            ..self
 1354        }
 1355    }
 1356}
 1357
 1358struct DeferredSelectionEffectsState {
 1359    changed: bool,
 1360    effects: SelectionEffects,
 1361    old_cursor_position: Anchor,
 1362    history_entry: SelectionHistoryEntry,
 1363}
 1364
 1365#[derive(Default)]
 1366struct SelectionHistory {
 1367    #[allow(clippy::type_complexity)]
 1368    selections_by_transaction:
 1369        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1370    mode: SelectionHistoryMode,
 1371    undo_stack: VecDeque<SelectionHistoryEntry>,
 1372    redo_stack: VecDeque<SelectionHistoryEntry>,
 1373}
 1374
 1375impl SelectionHistory {
 1376    #[track_caller]
 1377    fn insert_transaction(
 1378        &mut self,
 1379        transaction_id: TransactionId,
 1380        selections: Arc<[Selection<Anchor>]>,
 1381    ) {
 1382        if selections.is_empty() {
 1383            log::error!(
 1384                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1385                std::panic::Location::caller()
 1386            );
 1387            return;
 1388        }
 1389        self.selections_by_transaction
 1390            .insert(transaction_id, (selections, None));
 1391    }
 1392
 1393    #[allow(clippy::type_complexity)]
 1394    fn transaction(
 1395        &self,
 1396        transaction_id: TransactionId,
 1397    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1398        self.selections_by_transaction.get(&transaction_id)
 1399    }
 1400
 1401    #[allow(clippy::type_complexity)]
 1402    fn transaction_mut(
 1403        &mut self,
 1404        transaction_id: TransactionId,
 1405    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1406        self.selections_by_transaction.get_mut(&transaction_id)
 1407    }
 1408
 1409    fn push(&mut self, entry: SelectionHistoryEntry) {
 1410        if !entry.selections.is_empty() {
 1411            match self.mode {
 1412                SelectionHistoryMode::Normal => {
 1413                    self.push_undo(entry);
 1414                    self.redo_stack.clear();
 1415                }
 1416                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1417                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1418                SelectionHistoryMode::Skipping => {}
 1419            }
 1420        }
 1421    }
 1422
 1423    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1424        if self
 1425            .undo_stack
 1426            .back()
 1427            .is_none_or(|e| e.selections != entry.selections)
 1428        {
 1429            self.undo_stack.push_back(entry);
 1430            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1431                self.undo_stack.pop_front();
 1432            }
 1433        }
 1434    }
 1435
 1436    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1437        if self
 1438            .redo_stack
 1439            .back()
 1440            .is_none_or(|e| e.selections != entry.selections)
 1441        {
 1442            self.redo_stack.push_back(entry);
 1443            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1444                self.redo_stack.pop_front();
 1445            }
 1446        }
 1447    }
 1448}
 1449
 1450#[derive(Clone, Copy)]
 1451pub struct RowHighlightOptions {
 1452    pub autoscroll: bool,
 1453    pub include_gutter: bool,
 1454}
 1455
 1456impl Default for RowHighlightOptions {
 1457    fn default() -> Self {
 1458        Self {
 1459            autoscroll: Default::default(),
 1460            include_gutter: true,
 1461        }
 1462    }
 1463}
 1464
 1465struct RowHighlight {
 1466    index: usize,
 1467    range: Range<Anchor>,
 1468    color: Hsla,
 1469    options: RowHighlightOptions,
 1470    type_id: TypeId,
 1471}
 1472
 1473#[derive(Clone, Debug)]
 1474struct AddSelectionsState {
 1475    groups: Vec<AddSelectionsGroup>,
 1476}
 1477
 1478#[derive(Clone, Debug)]
 1479struct AddSelectionsGroup {
 1480    above: bool,
 1481    stack: Vec<usize>,
 1482}
 1483
 1484#[derive(Clone)]
 1485struct SelectNextState {
 1486    query: AhoCorasick,
 1487    wordwise: bool,
 1488    done: bool,
 1489}
 1490
 1491impl std::fmt::Debug for SelectNextState {
 1492    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1493        f.debug_struct(std::any::type_name::<Self>())
 1494            .field("wordwise", &self.wordwise)
 1495            .field("done", &self.done)
 1496            .finish()
 1497    }
 1498}
 1499
 1500#[derive(Debug)]
 1501struct AutocloseRegion {
 1502    selection_id: usize,
 1503    range: Range<Anchor>,
 1504    pair: BracketPair,
 1505}
 1506
 1507#[derive(Debug)]
 1508struct SnippetState {
 1509    ranges: Vec<Vec<Range<Anchor>>>,
 1510    active_index: usize,
 1511    choices: Vec<Option<Vec<String>>>,
 1512}
 1513
 1514#[doc(hidden)]
 1515pub struct RenameState {
 1516    pub range: Range<Anchor>,
 1517    pub old_name: Arc<str>,
 1518    pub editor: Entity<Editor>,
 1519    block_id: CustomBlockId,
 1520}
 1521
 1522struct InvalidationStack<T>(Vec<T>);
 1523
 1524struct RegisteredEditPredictionProvider {
 1525    provider: Arc<dyn EditPredictionProviderHandle>,
 1526    _subscription: Subscription,
 1527}
 1528
 1529#[derive(Debug, PartialEq, Eq)]
 1530pub struct ActiveDiagnosticGroup {
 1531    pub active_range: Range<Anchor>,
 1532    pub active_message: String,
 1533    pub group_id: usize,
 1534    pub blocks: HashSet<CustomBlockId>,
 1535}
 1536
 1537#[derive(Debug, PartialEq, Eq)]
 1538
 1539pub(crate) enum ActiveDiagnostic {
 1540    None,
 1541    All,
 1542    Group(ActiveDiagnosticGroup),
 1543}
 1544
 1545#[derive(Serialize, Deserialize, Clone, Debug)]
 1546pub struct ClipboardSelection {
 1547    /// The number of bytes in this selection.
 1548    pub len: usize,
 1549    /// Whether this was a full-line selection.
 1550    pub is_entire_line: bool,
 1551    /// The indentation of the first line when this content was originally copied.
 1552    pub first_line_indent: u32,
 1553}
 1554
 1555// selections, scroll behavior, was newest selection reversed
 1556type SelectSyntaxNodeHistoryState = (
 1557    Box<[Selection<usize>]>,
 1558    SelectSyntaxNodeScrollBehavior,
 1559    bool,
 1560);
 1561
 1562#[derive(Default)]
 1563struct SelectSyntaxNodeHistory {
 1564    stack: Vec<SelectSyntaxNodeHistoryState>,
 1565    // disable temporarily to allow changing selections without losing the stack
 1566    pub disable_clearing: bool,
 1567}
 1568
 1569impl SelectSyntaxNodeHistory {
 1570    pub fn try_clear(&mut self) {
 1571        if !self.disable_clearing {
 1572            self.stack.clear();
 1573        }
 1574    }
 1575
 1576    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1577        self.stack.push(selection);
 1578    }
 1579
 1580    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1581        self.stack.pop()
 1582    }
 1583}
 1584
 1585enum SelectSyntaxNodeScrollBehavior {
 1586    CursorTop,
 1587    FitSelection,
 1588    CursorBottom,
 1589}
 1590
 1591#[derive(Debug)]
 1592pub(crate) struct NavigationData {
 1593    cursor_anchor: Anchor,
 1594    cursor_position: Point,
 1595    scroll_anchor: ScrollAnchor,
 1596    scroll_top_row: u32,
 1597}
 1598
 1599#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1600pub enum GotoDefinitionKind {
 1601    Symbol,
 1602    Declaration,
 1603    Type,
 1604    Implementation,
 1605}
 1606
 1607#[derive(Debug, Clone)]
 1608enum InlayHintRefreshReason {
 1609    ModifiersChanged(bool),
 1610    Toggle(bool),
 1611    SettingsChange(InlayHintSettings),
 1612    NewLinesShown,
 1613    BufferEdited(HashSet<Arc<Language>>),
 1614    RefreshRequested,
 1615    ExcerptsRemoved(Vec<ExcerptId>),
 1616}
 1617
 1618impl InlayHintRefreshReason {
 1619    fn description(&self) -> &'static str {
 1620        match self {
 1621            Self::ModifiersChanged(_) => "modifiers changed",
 1622            Self::Toggle(_) => "toggle",
 1623            Self::SettingsChange(_) => "settings change",
 1624            Self::NewLinesShown => "new lines shown",
 1625            Self::BufferEdited(_) => "buffer edited",
 1626            Self::RefreshRequested => "refresh requested",
 1627            Self::ExcerptsRemoved(_) => "excerpts removed",
 1628        }
 1629    }
 1630}
 1631
 1632pub enum FormatTarget {
 1633    Buffers(HashSet<Entity<Buffer>>),
 1634    Ranges(Vec<Range<MultiBufferPoint>>),
 1635}
 1636
 1637pub(crate) struct FocusedBlock {
 1638    id: BlockId,
 1639    focus_handle: WeakFocusHandle,
 1640}
 1641
 1642#[derive(Clone)]
 1643enum JumpData {
 1644    MultiBufferRow {
 1645        row: MultiBufferRow,
 1646        line_offset_from_top: u32,
 1647    },
 1648    MultiBufferPoint {
 1649        excerpt_id: ExcerptId,
 1650        position: Point,
 1651        anchor: text::Anchor,
 1652        line_offset_from_top: u32,
 1653    },
 1654}
 1655
 1656pub enum MultibufferSelectionMode {
 1657    First,
 1658    All,
 1659}
 1660
 1661#[derive(Clone, Copy, Debug, Default)]
 1662pub struct RewrapOptions {
 1663    pub override_language_settings: bool,
 1664    pub preserve_existing_whitespace: bool,
 1665}
 1666
 1667impl Editor {
 1668    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1669        let buffer = cx.new(|cx| Buffer::local("", cx));
 1670        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1671        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1672    }
 1673
 1674    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(EditorMode::full(), buffer, None, window, cx)
 1678    }
 1679
 1680    pub fn auto_height(
 1681        min_lines: usize,
 1682        max_lines: usize,
 1683        window: &mut Window,
 1684        cx: &mut Context<Self>,
 1685    ) -> Self {
 1686        let buffer = cx.new(|cx| Buffer::local("", cx));
 1687        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1688        Self::new(
 1689            EditorMode::AutoHeight {
 1690                min_lines,
 1691                max_lines: Some(max_lines),
 1692            },
 1693            buffer,
 1694            None,
 1695            window,
 1696            cx,
 1697        )
 1698    }
 1699
 1700    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1701    /// The editor grows as tall as needed to fit its content.
 1702    pub fn auto_height_unbounded(
 1703        min_lines: usize,
 1704        window: &mut Window,
 1705        cx: &mut Context<Self>,
 1706    ) -> Self {
 1707        let buffer = cx.new(|cx| Buffer::local("", cx));
 1708        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1709        Self::new(
 1710            EditorMode::AutoHeight {
 1711                min_lines,
 1712                max_lines: None,
 1713            },
 1714            buffer,
 1715            None,
 1716            window,
 1717            cx,
 1718        )
 1719    }
 1720
 1721    pub fn for_buffer(
 1722        buffer: Entity<Buffer>,
 1723        project: Option<Entity<Project>>,
 1724        window: &mut Window,
 1725        cx: &mut Context<Self>,
 1726    ) -> Self {
 1727        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1728        Self::new(EditorMode::full(), buffer, project, window, cx)
 1729    }
 1730
 1731    pub fn for_multibuffer(
 1732        buffer: Entity<MultiBuffer>,
 1733        project: Option<Entity<Project>>,
 1734        window: &mut Window,
 1735        cx: &mut Context<Self>,
 1736    ) -> Self {
 1737        Self::new(EditorMode::full(), buffer, project, window, cx)
 1738    }
 1739
 1740    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1741        let mut clone = Self::new(
 1742            self.mode.clone(),
 1743            self.buffer.clone(),
 1744            self.project.clone(),
 1745            window,
 1746            cx,
 1747        );
 1748        self.display_map.update(cx, |display_map, cx| {
 1749            let snapshot = display_map.snapshot(cx);
 1750            clone.display_map.update(cx, |display_map, cx| {
 1751                display_map.set_state(&snapshot, cx);
 1752            });
 1753        });
 1754        clone.folds_did_change(cx);
 1755        clone.selections.clone_state(&self.selections);
 1756        clone.scroll_manager.clone_state(&self.scroll_manager);
 1757        clone.searchable = self.searchable;
 1758        clone.read_only = self.read_only;
 1759        clone
 1760    }
 1761
 1762    pub fn new(
 1763        mode: EditorMode,
 1764        buffer: Entity<MultiBuffer>,
 1765        project: Option<Entity<Project>>,
 1766        window: &mut Window,
 1767        cx: &mut Context<Self>,
 1768    ) -> Self {
 1769        Editor::new_internal(mode, buffer, project, None, window, cx)
 1770    }
 1771
 1772    fn new_internal(
 1773        mode: EditorMode,
 1774        buffer: Entity<MultiBuffer>,
 1775        project: Option<Entity<Project>>,
 1776        display_map: Option<Entity<DisplayMap>>,
 1777        window: &mut Window,
 1778        cx: &mut Context<Self>,
 1779    ) -> Self {
 1780        debug_assert!(
 1781            display_map.is_none() || mode.is_minimap(),
 1782            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1783        );
 1784
 1785        let full_mode = mode.is_full();
 1786        let is_minimap = mode.is_minimap();
 1787        let diagnostics_max_severity = if full_mode {
 1788            EditorSettings::get_global(cx)
 1789                .diagnostics_max_severity
 1790                .unwrap_or(DiagnosticSeverity::Hint)
 1791        } else {
 1792            DiagnosticSeverity::Off
 1793        };
 1794        let style = window.text_style();
 1795        let font_size = style.font_size.to_pixels(window.rem_size());
 1796        let editor = cx.entity().downgrade();
 1797        let fold_placeholder = FoldPlaceholder {
 1798            constrain_width: false,
 1799            render: Arc::new(move |fold_id, fold_range, cx| {
 1800                let editor = editor.clone();
 1801                div()
 1802                    .id(fold_id)
 1803                    .bg(cx.theme().colors().ghost_element_background)
 1804                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1805                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1806                    .rounded_xs()
 1807                    .size_full()
 1808                    .cursor_pointer()
 1809                    .child("")
 1810                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1811                    .on_click(move |_, _window, cx| {
 1812                        editor
 1813                            .update(cx, |editor, cx| {
 1814                                editor.unfold_ranges(
 1815                                    &[fold_range.start..fold_range.end],
 1816                                    true,
 1817                                    false,
 1818                                    cx,
 1819                                );
 1820                                cx.stop_propagation();
 1821                            })
 1822                            .ok();
 1823                    })
 1824                    .into_any()
 1825            }),
 1826            merge_adjacent: true,
 1827            ..FoldPlaceholder::default()
 1828        };
 1829        let display_map = display_map.unwrap_or_else(|| {
 1830            cx.new(|cx| {
 1831                DisplayMap::new(
 1832                    buffer.clone(),
 1833                    style.font(),
 1834                    font_size,
 1835                    None,
 1836                    FILE_HEADER_HEIGHT,
 1837                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1838                    fold_placeholder,
 1839                    diagnostics_max_severity,
 1840                    cx,
 1841                )
 1842            })
 1843        });
 1844
 1845        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1846
 1847        let blink_manager = cx.new(|cx| {
 1848            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1849            if is_minimap {
 1850                blink_manager.disable(cx);
 1851            }
 1852            blink_manager
 1853        });
 1854
 1855        let soft_wrap_mode_override =
 1856            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1857
 1858        let mut project_subscriptions = Vec::new();
 1859        if full_mode && let Some(project) = project.as_ref() {
 1860            project_subscriptions.push(cx.subscribe_in(
 1861                project,
 1862                window,
 1863                |editor, _, event, window, cx| match event {
 1864                    project::Event::RefreshCodeLens => {
 1865                        // we always query lens with actions, without storing them, always refreshing them
 1866                    }
 1867                    project::Event::RefreshInlayHints => {
 1868                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1869                    }
 1870                    project::Event::LanguageServerAdded(..)
 1871                    | project::Event::LanguageServerRemoved(..) => {
 1872                        if editor.tasks_update_task.is_none() {
 1873                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1874                        }
 1875                    }
 1876                    project::Event::SnippetEdit(id, snippet_edits) => {
 1877                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1878                            let focus_handle = editor.focus_handle(cx);
 1879                            if focus_handle.is_focused(window) {
 1880                                let snapshot = buffer.read(cx).snapshot();
 1881                                for (range, snippet) in snippet_edits {
 1882                                    let editor_range =
 1883                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1884                                    editor
 1885                                        .insert_snippet(
 1886                                            &[editor_range],
 1887                                            snippet.clone(),
 1888                                            window,
 1889                                            cx,
 1890                                        )
 1891                                        .ok();
 1892                                }
 1893                            }
 1894                        }
 1895                    }
 1896                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1897                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1898                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1899                        }
 1900                    }
 1901
 1902                    project::Event::EntryRenamed(transaction) => {
 1903                        let Some(workspace) = editor.workspace() else {
 1904                            return;
 1905                        };
 1906                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1907                        else {
 1908                            return;
 1909                        };
 1910                        if active_editor.entity_id() == cx.entity_id() {
 1911                            let edited_buffers_already_open = {
 1912                                let other_editors: Vec<Entity<Editor>> = workspace
 1913                                    .read(cx)
 1914                                    .panes()
 1915                                    .iter()
 1916                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1917                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1918                                    .collect();
 1919
 1920                                transaction.0.keys().all(|buffer| {
 1921                                    other_editors.iter().any(|editor| {
 1922                                        let multi_buffer = editor.read(cx).buffer();
 1923                                        multi_buffer.read(cx).is_singleton()
 1924                                            && multi_buffer.read(cx).as_singleton().map_or(
 1925                                                false,
 1926                                                |singleton| {
 1927                                                    singleton.entity_id() == buffer.entity_id()
 1928                                                },
 1929                                            )
 1930                                    })
 1931                                })
 1932                            };
 1933
 1934                            if !edited_buffers_already_open {
 1935                                let workspace = workspace.downgrade();
 1936                                let transaction = transaction.clone();
 1937                                cx.defer_in(window, move |_, window, cx| {
 1938                                    cx.spawn_in(window, async move |editor, cx| {
 1939                                        Self::open_project_transaction(
 1940                                            &editor,
 1941                                            workspace,
 1942                                            transaction,
 1943                                            "Rename".to_string(),
 1944                                            cx,
 1945                                        )
 1946                                        .await
 1947                                        .ok()
 1948                                    })
 1949                                    .detach();
 1950                                });
 1951                            }
 1952                        }
 1953                    }
 1954
 1955                    _ => {}
 1956                },
 1957            ));
 1958            if let Some(task_inventory) = project
 1959                .read(cx)
 1960                .task_store()
 1961                .read(cx)
 1962                .task_inventory()
 1963                .cloned()
 1964            {
 1965                project_subscriptions.push(cx.observe_in(
 1966                    &task_inventory,
 1967                    window,
 1968                    |editor, _, window, cx| {
 1969                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1970                    },
 1971                ));
 1972            };
 1973
 1974            project_subscriptions.push(cx.subscribe_in(
 1975                &project.read(cx).breakpoint_store(),
 1976                window,
 1977                |editor, _, event, window, cx| match event {
 1978                    BreakpointStoreEvent::ClearDebugLines => {
 1979                        editor.clear_row_highlights::<ActiveDebugLine>();
 1980                        editor.refresh_inline_values(cx);
 1981                    }
 1982                    BreakpointStoreEvent::SetDebugLine => {
 1983                        if editor.go_to_active_debug_line(window, cx) {
 1984                            cx.stop_propagation();
 1985                        }
 1986
 1987                        editor.refresh_inline_values(cx);
 1988                    }
 1989                    _ => {}
 1990                },
 1991            ));
 1992            let git_store = project.read(cx).git_store().clone();
 1993            let project = project.clone();
 1994            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1995                if let GitStoreEvent::RepositoryUpdated(
 1996                    _,
 1997                    RepositoryEvent::Updated {
 1998                        new_instance: true, ..
 1999                    },
 2000                    _,
 2001                ) = event
 2002                {
 2003                    this.load_diff_task = Some(
 2004                        update_uncommitted_diff_for_buffer(
 2005                            cx.entity(),
 2006                            &project,
 2007                            this.buffer.read(cx).all_buffers(),
 2008                            this.buffer.clone(),
 2009                            cx,
 2010                        )
 2011                        .shared(),
 2012                    );
 2013                }
 2014            }));
 2015        }
 2016
 2017        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2018
 2019        let inlay_hint_settings =
 2020            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2021        let focus_handle = cx.focus_handle();
 2022        if !is_minimap {
 2023            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2024                .detach();
 2025            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2026                .detach();
 2027            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2028                .detach();
 2029            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2030                .detach();
 2031            cx.observe_pending_input(window, Self::observe_pending_input)
 2032                .detach();
 2033        }
 2034
 2035        let show_indent_guides =
 2036            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2037                Some(false)
 2038            } else {
 2039                None
 2040            };
 2041
 2042        let breakpoint_store = match (&mode, project.as_ref()) {
 2043            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2044            _ => None,
 2045        };
 2046
 2047        let mut code_action_providers = Vec::new();
 2048        let mut load_uncommitted_diff = None;
 2049        if let Some(project) = project.clone() {
 2050            load_uncommitted_diff = Some(
 2051                update_uncommitted_diff_for_buffer(
 2052                    cx.entity(),
 2053                    &project,
 2054                    buffer.read(cx).all_buffers(),
 2055                    buffer.clone(),
 2056                    cx,
 2057                )
 2058                .shared(),
 2059            );
 2060            code_action_providers.push(Rc::new(project) as Rc<_>);
 2061        }
 2062
 2063        let mut editor = Self {
 2064            focus_handle,
 2065            show_cursor_when_unfocused: false,
 2066            last_focused_descendant: None,
 2067            buffer: buffer.clone(),
 2068            display_map: display_map.clone(),
 2069            selections,
 2070            scroll_manager: ScrollManager::new(cx),
 2071            columnar_selection_state: None,
 2072            add_selections_state: None,
 2073            select_next_state: None,
 2074            select_prev_state: None,
 2075            selection_history: SelectionHistory::default(),
 2076            defer_selection_effects: false,
 2077            deferred_selection_effects_state: None,
 2078            autoclose_regions: Vec::new(),
 2079            snippet_stack: InvalidationStack::default(),
 2080            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2081            ime_transaction: None,
 2082            active_diagnostics: ActiveDiagnostic::None,
 2083            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2084            inline_diagnostics_update: Task::ready(()),
 2085            inline_diagnostics: Vec::new(),
 2086            soft_wrap_mode_override,
 2087            diagnostics_max_severity,
 2088            hard_wrap: None,
 2089            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2090            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2091            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2092            project,
 2093            blink_manager: blink_manager.clone(),
 2094            show_local_selections: true,
 2095            show_scrollbars: ScrollbarAxes {
 2096                horizontal: full_mode,
 2097                vertical: full_mode,
 2098            },
 2099            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2100            offset_content: !matches!(mode, EditorMode::SingleLine),
 2101            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2102            show_gutter: full_mode,
 2103            show_line_numbers: (!full_mode).then_some(false),
 2104            use_relative_line_numbers: None,
 2105            disable_expand_excerpt_buttons: !full_mode,
 2106            show_git_diff_gutter: None,
 2107            show_code_actions: None,
 2108            show_runnables: None,
 2109            show_breakpoints: None,
 2110            show_wrap_guides: None,
 2111            show_indent_guides,
 2112            placeholder_text: None,
 2113            highlight_order: 0,
 2114            highlighted_rows: HashMap::default(),
 2115            background_highlights: HashMap::default(),
 2116            gutter_highlights: HashMap::default(),
 2117            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2118            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2119            nav_history: None,
 2120            context_menu: RefCell::new(None),
 2121            context_menu_options: None,
 2122            mouse_context_menu: None,
 2123            completion_tasks: Vec::new(),
 2124            inline_blame_popover: None,
 2125            inline_blame_popover_show_task: None,
 2126            signature_help_state: SignatureHelpState::default(),
 2127            auto_signature_help: None,
 2128            find_all_references_task_sources: Vec::new(),
 2129            next_completion_id: 0,
 2130            next_inlay_id: 0,
 2131            code_action_providers,
 2132            available_code_actions: None,
 2133            code_actions_task: None,
 2134            quick_selection_highlight_task: None,
 2135            debounced_selection_highlight_task: None,
 2136            document_highlights_task: None,
 2137            linked_editing_range_task: None,
 2138            pending_rename: None,
 2139            searchable: !is_minimap,
 2140            cursor_shape: EditorSettings::get_global(cx)
 2141                .cursor_shape
 2142                .unwrap_or_default(),
 2143            current_line_highlight: None,
 2144            autoindent_mode: Some(AutoindentMode::EachLine),
 2145            collapse_matches: false,
 2146            workspace: None,
 2147            input_enabled: !is_minimap,
 2148            use_modal_editing: full_mode,
 2149            read_only: is_minimap,
 2150            use_autoclose: true,
 2151            use_auto_surround: true,
 2152            auto_replace_emoji_shortcode: false,
 2153            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2154            leader_id: None,
 2155            remote_id: None,
 2156            hover_state: HoverState::default(),
 2157            pending_mouse_down: None,
 2158            hovered_link_state: None,
 2159            edit_prediction_provider: None,
 2160            active_edit_prediction: None,
 2161            stale_edit_prediction_in_menu: None,
 2162            edit_prediction_preview: EditPredictionPreview::Inactive {
 2163                released_too_fast: false,
 2164            },
 2165            inline_diagnostics_enabled: full_mode,
 2166            diagnostics_enabled: full_mode,
 2167            word_completions_enabled: full_mode,
 2168            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2169            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2170            gutter_hovered: false,
 2171            pixel_position_of_newest_cursor: None,
 2172            last_bounds: None,
 2173            last_position_map: None,
 2174            expect_bounds_change: None,
 2175            gutter_dimensions: GutterDimensions::default(),
 2176            style: None,
 2177            show_cursor_names: false,
 2178            hovered_cursors: HashMap::default(),
 2179            next_editor_action_id: EditorActionId::default(),
 2180            editor_actions: Rc::default(),
 2181            edit_predictions_hidden_for_vim_mode: false,
 2182            show_edit_predictions_override: None,
 2183            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2184            edit_prediction_settings: EditPredictionSettings::Disabled,
 2185            edit_prediction_indent_conflict: false,
 2186            edit_prediction_requires_modifier_in_indent_conflict: true,
 2187            custom_context_menu: None,
 2188            show_git_blame_gutter: false,
 2189            show_git_blame_inline: false,
 2190            show_selection_menu: None,
 2191            show_git_blame_inline_delay_task: None,
 2192            git_blame_inline_enabled: full_mode
 2193                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2194            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2195            serialize_dirty_buffers: !is_minimap
 2196                && ProjectSettings::get_global(cx)
 2197                    .session
 2198                    .restore_unsaved_buffers,
 2199            blame: None,
 2200            blame_subscription: None,
 2201            tasks: BTreeMap::default(),
 2202
 2203            breakpoint_store,
 2204            gutter_breakpoint_indicator: (None, None),
 2205            hovered_diff_hunk_row: None,
 2206            _subscriptions: (!is_minimap)
 2207                .then(|| {
 2208                    vec![
 2209                        cx.observe(&buffer, Self::on_buffer_changed),
 2210                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2211                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2212                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2213                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2214                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2215                        cx.observe_window_activation(window, |editor, window, cx| {
 2216                            let active = window.is_window_active();
 2217                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2218                                if active {
 2219                                    blink_manager.enable(cx);
 2220                                } else {
 2221                                    blink_manager.disable(cx);
 2222                                }
 2223                            });
 2224                            if active {
 2225                                editor.show_mouse_cursor(cx);
 2226                            }
 2227                        }),
 2228                    ]
 2229                })
 2230                .unwrap_or_default(),
 2231            tasks_update_task: None,
 2232            pull_diagnostics_task: Task::ready(()),
 2233            colors: None,
 2234            next_color_inlay_id: 0,
 2235            linked_edit_ranges: Default::default(),
 2236            in_project_search: false,
 2237            previous_search_ranges: None,
 2238            breadcrumb_header: None,
 2239            focused_block: None,
 2240            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2241            addons: HashMap::default(),
 2242            registered_buffers: HashMap::default(),
 2243            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2244            selection_mark_mode: false,
 2245            toggle_fold_multiple_buffers: Task::ready(()),
 2246            serialize_selections: Task::ready(()),
 2247            serialize_folds: Task::ready(()),
 2248            text_style_refinement: None,
 2249            load_diff_task: load_uncommitted_diff,
 2250            temporary_diff_override: false,
 2251            mouse_cursor_hidden: false,
 2252            minimap: None,
 2253            hide_mouse_mode: EditorSettings::get_global(cx)
 2254                .hide_mouse
 2255                .unwrap_or_default(),
 2256            change_list: ChangeList::new(),
 2257            mode,
 2258            selection_drag_state: SelectionDragState::None,
 2259            folding_newlines: Task::ready(()),
 2260        };
 2261
 2262        if is_minimap {
 2263            return editor;
 2264        }
 2265
 2266        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2267            editor
 2268                ._subscriptions
 2269                .push(cx.observe(breakpoints, |_, _, cx| {
 2270                    cx.notify();
 2271                }));
 2272        }
 2273        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2274        editor._subscriptions.extend(project_subscriptions);
 2275
 2276        editor._subscriptions.push(cx.subscribe_in(
 2277            &cx.entity(),
 2278            window,
 2279            |editor, _, e: &EditorEvent, window, cx| match e {
 2280                EditorEvent::ScrollPositionChanged { local, .. } => {
 2281                    if *local {
 2282                        let new_anchor = editor.scroll_manager.anchor();
 2283                        let snapshot = editor.snapshot(window, cx);
 2284                        editor.update_restoration_data(cx, move |data| {
 2285                            data.scroll_position = (
 2286                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2287                                new_anchor.offset,
 2288                            );
 2289                        });
 2290                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2291                        editor.inline_blame_popover.take();
 2292                    }
 2293                }
 2294                EditorEvent::Edited { .. } => {
 2295                    if !vim_enabled(cx) {
 2296                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2297                        let pop_state = editor
 2298                            .change_list
 2299                            .last()
 2300                            .map(|previous| {
 2301                                previous.len() == selections.len()
 2302                                    && previous.iter().enumerate().all(|(ix, p)| {
 2303                                        p.to_display_point(&map).row()
 2304                                            == selections[ix].head().row()
 2305                                    })
 2306                            })
 2307                            .unwrap_or(false);
 2308                        let new_positions = selections
 2309                            .into_iter()
 2310                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2311                            .collect();
 2312                        editor
 2313                            .change_list
 2314                            .push_to_change_list(pop_state, new_positions);
 2315                    }
 2316                }
 2317                _ => (),
 2318            },
 2319        ));
 2320
 2321        if let Some(dap_store) = editor
 2322            .project
 2323            .as_ref()
 2324            .map(|project| project.read(cx).dap_store())
 2325        {
 2326            let weak_editor = cx.weak_entity();
 2327
 2328            editor
 2329                ._subscriptions
 2330                .push(
 2331                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2332                        let session_entity = cx.entity();
 2333                        weak_editor
 2334                            .update(cx, |editor, cx| {
 2335                                editor._subscriptions.push(
 2336                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2337                                );
 2338                            })
 2339                            .ok();
 2340                    }),
 2341                );
 2342
 2343            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2344                editor
 2345                    ._subscriptions
 2346                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2347            }
 2348        }
 2349
 2350        // skip adding the initial selection to selection history
 2351        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2352        editor.end_selection(window, cx);
 2353        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2354
 2355        editor.scroll_manager.show_scrollbars(window, cx);
 2356        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2357
 2358        if full_mode {
 2359            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2360            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2361
 2362            if editor.git_blame_inline_enabled {
 2363                editor.start_git_blame_inline(false, window, cx);
 2364            }
 2365
 2366            editor.go_to_active_debug_line(window, cx);
 2367
 2368            if let Some(buffer) = buffer.read(cx).as_singleton()
 2369                && let Some(project) = editor.project()
 2370            {
 2371                let handle = project.update(cx, |project, cx| {
 2372                    project.register_buffer_with_language_servers(&buffer, cx)
 2373                });
 2374                editor
 2375                    .registered_buffers
 2376                    .insert(buffer.read(cx).remote_id(), handle);
 2377            }
 2378
 2379            editor.minimap =
 2380                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2381            editor.colors = Some(LspColorData::new(cx));
 2382            editor.update_lsp_data(false, None, window, cx);
 2383        }
 2384
 2385        if editor.mode.is_full() {
 2386            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2387        }
 2388
 2389        editor
 2390    }
 2391
 2392    pub fn deploy_mouse_context_menu(
 2393        &mut self,
 2394        position: gpui::Point<Pixels>,
 2395        context_menu: Entity<ContextMenu>,
 2396        window: &mut Window,
 2397        cx: &mut Context<Self>,
 2398    ) {
 2399        self.mouse_context_menu = Some(MouseContextMenu::new(
 2400            self,
 2401            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2402            context_menu,
 2403            window,
 2404            cx,
 2405        ));
 2406    }
 2407
 2408    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2409        self.mouse_context_menu
 2410            .as_ref()
 2411            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2412    }
 2413
 2414    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2415        if self
 2416            .selections
 2417            .pending
 2418            .as_ref()
 2419            .is_some_and(|pending_selection| {
 2420                let snapshot = self.buffer().read(cx).snapshot(cx);
 2421                pending_selection
 2422                    .selection
 2423                    .range()
 2424                    .includes(range, &snapshot)
 2425            })
 2426        {
 2427            return true;
 2428        }
 2429
 2430        self.selections
 2431            .disjoint_in_range::<usize>(range.clone(), cx)
 2432            .into_iter()
 2433            .any(|selection| {
 2434                // This is needed to cover a corner case, if we just check for an existing
 2435                // selection in the fold range, having a cursor at the start of the fold
 2436                // marks it as selected. Non-empty selections don't cause this.
 2437                let length = selection.end - selection.start;
 2438                length > 0
 2439            })
 2440    }
 2441
 2442    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2443        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2444    }
 2445
 2446    fn key_context_internal(
 2447        &self,
 2448        has_active_edit_prediction: bool,
 2449        window: &Window,
 2450        cx: &App,
 2451    ) -> KeyContext {
 2452        let mut key_context = KeyContext::new_with_defaults();
 2453        key_context.add("Editor");
 2454        let mode = match self.mode {
 2455            EditorMode::SingleLine => "single_line",
 2456            EditorMode::AutoHeight { .. } => "auto_height",
 2457            EditorMode::Minimap { .. } => "minimap",
 2458            EditorMode::Full { .. } => "full",
 2459        };
 2460
 2461        if EditorSettings::jupyter_enabled(cx) {
 2462            key_context.add("jupyter");
 2463        }
 2464
 2465        key_context.set("mode", mode);
 2466        if self.pending_rename.is_some() {
 2467            key_context.add("renaming");
 2468        }
 2469
 2470        match self.context_menu.borrow().as_ref() {
 2471            Some(CodeContextMenu::Completions(menu)) => {
 2472                if menu.visible() {
 2473                    key_context.add("menu");
 2474                    key_context.add("showing_completions");
 2475                }
 2476            }
 2477            Some(CodeContextMenu::CodeActions(menu)) => {
 2478                if menu.visible() {
 2479                    key_context.add("menu");
 2480                    key_context.add("showing_code_actions")
 2481                }
 2482            }
 2483            None => {}
 2484        }
 2485
 2486        if self.signature_help_state.has_multiple_signatures() {
 2487            key_context.add("showing_signature_help");
 2488        }
 2489
 2490        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2491        if !self.focus_handle(cx).contains_focused(window, cx)
 2492            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2493        {
 2494            for addon in self.addons.values() {
 2495                addon.extend_key_context(&mut key_context, cx)
 2496            }
 2497        }
 2498
 2499        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2500            if let Some(extension) = singleton_buffer
 2501                .read(cx)
 2502                .file()
 2503                .and_then(|file| file.path().extension()?.to_str())
 2504            {
 2505                key_context.set("extension", extension.to_string());
 2506            }
 2507        } else {
 2508            key_context.add("multibuffer");
 2509        }
 2510
 2511        if has_active_edit_prediction {
 2512            if self.edit_prediction_in_conflict() {
 2513                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2514            } else {
 2515                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2516                key_context.add("copilot_suggestion");
 2517            }
 2518        }
 2519
 2520        if self.selection_mark_mode {
 2521            key_context.add("selection_mode");
 2522        }
 2523
 2524        key_context
 2525    }
 2526
 2527    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2528        if self.mouse_cursor_hidden {
 2529            self.mouse_cursor_hidden = false;
 2530            cx.notify();
 2531        }
 2532    }
 2533
 2534    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2535        let hide_mouse_cursor = match origin {
 2536            HideMouseCursorOrigin::TypingAction => {
 2537                matches!(
 2538                    self.hide_mouse_mode,
 2539                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2540                )
 2541            }
 2542            HideMouseCursorOrigin::MovementAction => {
 2543                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2544            }
 2545        };
 2546        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2547            self.mouse_cursor_hidden = hide_mouse_cursor;
 2548            cx.notify();
 2549        }
 2550    }
 2551
 2552    pub fn edit_prediction_in_conflict(&self) -> bool {
 2553        if !self.show_edit_predictions_in_menu() {
 2554            return false;
 2555        }
 2556
 2557        let showing_completions = self
 2558            .context_menu
 2559            .borrow()
 2560            .as_ref()
 2561            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2562
 2563        showing_completions
 2564            || self.edit_prediction_requires_modifier()
 2565            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2566            // bindings to insert tab characters.
 2567            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2568    }
 2569
 2570    pub fn accept_edit_prediction_keybind(
 2571        &self,
 2572        accept_partial: bool,
 2573        window: &Window,
 2574        cx: &App,
 2575    ) -> AcceptEditPredictionBinding {
 2576        let key_context = self.key_context_internal(true, window, cx);
 2577        let in_conflict = self.edit_prediction_in_conflict();
 2578
 2579        let bindings = if accept_partial {
 2580            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2581        } else {
 2582            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2583        };
 2584
 2585        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2586        // just the first one.
 2587        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2588            !in_conflict
 2589                || binding
 2590                    .keystrokes()
 2591                    .first()
 2592                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2593        }))
 2594    }
 2595
 2596    pub fn new_file(
 2597        workspace: &mut Workspace,
 2598        _: &workspace::NewFile,
 2599        window: &mut Window,
 2600        cx: &mut Context<Workspace>,
 2601    ) {
 2602        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2603            "Failed to create buffer",
 2604            window,
 2605            cx,
 2606            |e, _, _| match e.error_code() {
 2607                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2608                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2609                e.error_tag("required").unwrap_or("the latest version")
 2610            )),
 2611                _ => None,
 2612            },
 2613        );
 2614    }
 2615
 2616    pub fn new_in_workspace(
 2617        workspace: &mut Workspace,
 2618        window: &mut Window,
 2619        cx: &mut Context<Workspace>,
 2620    ) -> Task<Result<Entity<Editor>>> {
 2621        let project = workspace.project().clone();
 2622        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2623
 2624        cx.spawn_in(window, async move |workspace, cx| {
 2625            let buffer = create.await?;
 2626            workspace.update_in(cx, |workspace, window, cx| {
 2627                let editor =
 2628                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2629                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2630                editor
 2631            })
 2632        })
 2633    }
 2634
 2635    fn new_file_vertical(
 2636        workspace: &mut Workspace,
 2637        _: &workspace::NewFileSplitVertical,
 2638        window: &mut Window,
 2639        cx: &mut Context<Workspace>,
 2640    ) {
 2641        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2642    }
 2643
 2644    fn new_file_horizontal(
 2645        workspace: &mut Workspace,
 2646        _: &workspace::NewFileSplitHorizontal,
 2647        window: &mut Window,
 2648        cx: &mut Context<Workspace>,
 2649    ) {
 2650        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2651    }
 2652
 2653    fn new_file_in_direction(
 2654        workspace: &mut Workspace,
 2655        direction: SplitDirection,
 2656        window: &mut Window,
 2657        cx: &mut Context<Workspace>,
 2658    ) {
 2659        let project = workspace.project().clone();
 2660        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2661
 2662        cx.spawn_in(window, async move |workspace, cx| {
 2663            let buffer = create.await?;
 2664            workspace.update_in(cx, move |workspace, window, cx| {
 2665                workspace.split_item(
 2666                    direction,
 2667                    Box::new(
 2668                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2669                    ),
 2670                    window,
 2671                    cx,
 2672                )
 2673            })?;
 2674            anyhow::Ok(())
 2675        })
 2676        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2677            match e.error_code() {
 2678                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2679                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2680                e.error_tag("required").unwrap_or("the latest version")
 2681            )),
 2682                _ => None,
 2683            }
 2684        });
 2685    }
 2686
 2687    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2688        self.leader_id
 2689    }
 2690
 2691    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2692        &self.buffer
 2693    }
 2694
 2695    pub fn project(&self) -> Option<&Entity<Project>> {
 2696        self.project.as_ref()
 2697    }
 2698
 2699    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2700        self.workspace.as_ref()?.0.upgrade()
 2701    }
 2702
 2703    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2704        self.buffer().read(cx).title(cx)
 2705    }
 2706
 2707    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2708        let git_blame_gutter_max_author_length = self
 2709            .render_git_blame_gutter(cx)
 2710            .then(|| {
 2711                if let Some(blame) = self.blame.as_ref() {
 2712                    let max_author_length =
 2713                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2714                    Some(max_author_length)
 2715                } else {
 2716                    None
 2717                }
 2718            })
 2719            .flatten();
 2720
 2721        EditorSnapshot {
 2722            mode: self.mode.clone(),
 2723            show_gutter: self.show_gutter,
 2724            show_line_numbers: self.show_line_numbers,
 2725            show_git_diff_gutter: self.show_git_diff_gutter,
 2726            show_code_actions: self.show_code_actions,
 2727            show_runnables: self.show_runnables,
 2728            show_breakpoints: self.show_breakpoints,
 2729            git_blame_gutter_max_author_length,
 2730            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2731            scroll_anchor: self.scroll_manager.anchor(),
 2732            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2733            placeholder_text: self.placeholder_text.clone(),
 2734            is_focused: self.focus_handle.is_focused(window),
 2735            current_line_highlight: self
 2736                .current_line_highlight
 2737                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2738            gutter_hovered: self.gutter_hovered,
 2739        }
 2740    }
 2741
 2742    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2743        self.buffer.read(cx).language_at(point, cx)
 2744    }
 2745
 2746    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2747        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2748    }
 2749
 2750    pub fn active_excerpt(
 2751        &self,
 2752        cx: &App,
 2753    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2754        self.buffer
 2755            .read(cx)
 2756            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2757    }
 2758
 2759    pub fn mode(&self) -> &EditorMode {
 2760        &self.mode
 2761    }
 2762
 2763    pub fn set_mode(&mut self, mode: EditorMode) {
 2764        self.mode = mode;
 2765    }
 2766
 2767    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2768        self.collaboration_hub.as_deref()
 2769    }
 2770
 2771    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2772        self.collaboration_hub = Some(hub);
 2773    }
 2774
 2775    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2776        self.in_project_search = in_project_search;
 2777    }
 2778
 2779    pub fn set_custom_context_menu(
 2780        &mut self,
 2781        f: impl 'static
 2782        + Fn(
 2783            &mut Self,
 2784            DisplayPoint,
 2785            &mut Window,
 2786            &mut Context<Self>,
 2787        ) -> Option<Entity<ui::ContextMenu>>,
 2788    ) {
 2789        self.custom_context_menu = Some(Box::new(f))
 2790    }
 2791
 2792    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2793        self.completion_provider = provider;
 2794    }
 2795
 2796    #[cfg(any(test, feature = "test-support"))]
 2797    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2798        self.completion_provider.clone()
 2799    }
 2800
 2801    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2802        self.semantics_provider.clone()
 2803    }
 2804
 2805    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2806        self.semantics_provider = provider;
 2807    }
 2808
 2809    pub fn set_edit_prediction_provider<T>(
 2810        &mut self,
 2811        provider: Option<Entity<T>>,
 2812        window: &mut Window,
 2813        cx: &mut Context<Self>,
 2814    ) where
 2815        T: EditPredictionProvider,
 2816    {
 2817        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2818            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2819                if this.focus_handle.is_focused(window) {
 2820                    this.update_visible_edit_prediction(window, cx);
 2821                }
 2822            }),
 2823            provider: Arc::new(provider),
 2824        });
 2825        self.update_edit_prediction_settings(cx);
 2826        self.refresh_edit_prediction(false, false, window, cx);
 2827    }
 2828
 2829    pub fn placeholder_text(&self) -> Option<&str> {
 2830        self.placeholder_text.as_deref()
 2831    }
 2832
 2833    pub fn set_placeholder_text(
 2834        &mut self,
 2835        placeholder_text: impl Into<Arc<str>>,
 2836        cx: &mut Context<Self>,
 2837    ) {
 2838        let placeholder_text = Some(placeholder_text.into());
 2839        if self.placeholder_text != placeholder_text {
 2840            self.placeholder_text = placeholder_text;
 2841            cx.notify();
 2842        }
 2843    }
 2844
 2845    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2846        self.cursor_shape = cursor_shape;
 2847
 2848        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2849        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2850
 2851        cx.notify();
 2852    }
 2853
 2854    pub fn set_current_line_highlight(
 2855        &mut self,
 2856        current_line_highlight: Option<CurrentLineHighlight>,
 2857    ) {
 2858        self.current_line_highlight = current_line_highlight;
 2859    }
 2860
 2861    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2862        self.collapse_matches = collapse_matches;
 2863    }
 2864
 2865    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2866        let buffers = self.buffer.read(cx).all_buffers();
 2867        let Some(project) = self.project.as_ref() else {
 2868            return;
 2869        };
 2870        project.update(cx, |project, cx| {
 2871            for buffer in buffers {
 2872                self.registered_buffers
 2873                    .entry(buffer.read(cx).remote_id())
 2874                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2875            }
 2876        })
 2877    }
 2878
 2879    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2880        if self.collapse_matches {
 2881            return range.start..range.start;
 2882        }
 2883        range.clone()
 2884    }
 2885
 2886    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2887        if self.display_map.read(cx).clip_at_line_ends != clip {
 2888            self.display_map
 2889                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2890        }
 2891    }
 2892
 2893    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2894        self.input_enabled = input_enabled;
 2895    }
 2896
 2897    pub fn set_edit_predictions_hidden_for_vim_mode(
 2898        &mut self,
 2899        hidden: bool,
 2900        window: &mut Window,
 2901        cx: &mut Context<Self>,
 2902    ) {
 2903        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2904            self.edit_predictions_hidden_for_vim_mode = hidden;
 2905            if hidden {
 2906                self.update_visible_edit_prediction(window, cx);
 2907            } else {
 2908                self.refresh_edit_prediction(true, false, window, cx);
 2909            }
 2910        }
 2911    }
 2912
 2913    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2914        self.menu_edit_predictions_policy = value;
 2915    }
 2916
 2917    pub fn set_autoindent(&mut self, autoindent: bool) {
 2918        if autoindent {
 2919            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2920        } else {
 2921            self.autoindent_mode = None;
 2922        }
 2923    }
 2924
 2925    pub fn read_only(&self, cx: &App) -> bool {
 2926        self.read_only || self.buffer.read(cx).read_only()
 2927    }
 2928
 2929    pub fn set_read_only(&mut self, read_only: bool) {
 2930        self.read_only = read_only;
 2931    }
 2932
 2933    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2934        self.use_autoclose = autoclose;
 2935    }
 2936
 2937    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2938        self.use_auto_surround = auto_surround;
 2939    }
 2940
 2941    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2942        self.auto_replace_emoji_shortcode = auto_replace;
 2943    }
 2944
 2945    pub fn toggle_edit_predictions(
 2946        &mut self,
 2947        _: &ToggleEditPrediction,
 2948        window: &mut Window,
 2949        cx: &mut Context<Self>,
 2950    ) {
 2951        if self.show_edit_predictions_override.is_some() {
 2952            self.set_show_edit_predictions(None, window, cx);
 2953        } else {
 2954            let show_edit_predictions = !self.edit_predictions_enabled();
 2955            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2956        }
 2957    }
 2958
 2959    pub fn set_show_edit_predictions(
 2960        &mut self,
 2961        show_edit_predictions: Option<bool>,
 2962        window: &mut Window,
 2963        cx: &mut Context<Self>,
 2964    ) {
 2965        self.show_edit_predictions_override = show_edit_predictions;
 2966        self.update_edit_prediction_settings(cx);
 2967
 2968        if let Some(false) = show_edit_predictions {
 2969            self.discard_edit_prediction(false, cx);
 2970        } else {
 2971            self.refresh_edit_prediction(false, true, window, cx);
 2972        }
 2973    }
 2974
 2975    fn edit_predictions_disabled_in_scope(
 2976        &self,
 2977        buffer: &Entity<Buffer>,
 2978        buffer_position: language::Anchor,
 2979        cx: &App,
 2980    ) -> bool {
 2981        let snapshot = buffer.read(cx).snapshot();
 2982        let settings = snapshot.settings_at(buffer_position, cx);
 2983
 2984        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2985            return false;
 2986        };
 2987
 2988        scope.override_name().is_some_and(|scope_name| {
 2989            settings
 2990                .edit_predictions_disabled_in
 2991                .iter()
 2992                .any(|s| s == scope_name)
 2993        })
 2994    }
 2995
 2996    pub fn set_use_modal_editing(&mut self, to: bool) {
 2997        self.use_modal_editing = to;
 2998    }
 2999
 3000    pub fn use_modal_editing(&self) -> bool {
 3001        self.use_modal_editing
 3002    }
 3003
 3004    fn selections_did_change(
 3005        &mut self,
 3006        local: bool,
 3007        old_cursor_position: &Anchor,
 3008        effects: SelectionEffects,
 3009        window: &mut Window,
 3010        cx: &mut Context<Self>,
 3011    ) {
 3012        window.invalidate_character_coordinates();
 3013
 3014        // Copy selections to primary selection buffer
 3015        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3016        if local {
 3017            let selections = self.selections.all::<usize>(cx);
 3018            let buffer_handle = self.buffer.read(cx).read(cx);
 3019
 3020            let mut text = String::new();
 3021            for (index, selection) in selections.iter().enumerate() {
 3022                let text_for_selection = buffer_handle
 3023                    .text_for_range(selection.start..selection.end)
 3024                    .collect::<String>();
 3025
 3026                text.push_str(&text_for_selection);
 3027                if index != selections.len() - 1 {
 3028                    text.push('\n');
 3029                }
 3030            }
 3031
 3032            if !text.is_empty() {
 3033                cx.write_to_primary(ClipboardItem::new_string(text));
 3034            }
 3035        }
 3036
 3037        let selection_anchors = self.selections.disjoint_anchors();
 3038
 3039        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3040            self.buffer.update(cx, |buffer, cx| {
 3041                buffer.set_active_selections(
 3042                    &selection_anchors,
 3043                    self.selections.line_mode,
 3044                    self.cursor_shape,
 3045                    cx,
 3046                )
 3047            });
 3048        }
 3049        let display_map = self
 3050            .display_map
 3051            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3052        let buffer = &display_map.buffer_snapshot;
 3053        if self.selections.count() == 1 {
 3054            self.add_selections_state = None;
 3055        }
 3056        self.select_next_state = None;
 3057        self.select_prev_state = None;
 3058        self.select_syntax_node_history.try_clear();
 3059        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3060        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3061        self.take_rename(false, window, cx);
 3062
 3063        let newest_selection = self.selections.newest_anchor();
 3064        let new_cursor_position = newest_selection.head();
 3065        let selection_start = newest_selection.start;
 3066
 3067        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3068            self.push_to_nav_history(
 3069                *old_cursor_position,
 3070                Some(new_cursor_position.to_point(buffer)),
 3071                false,
 3072                effects.nav_history == Some(true),
 3073                cx,
 3074            );
 3075        }
 3076
 3077        if local {
 3078            if let Some(buffer_id) = new_cursor_position.buffer_id
 3079                && !self.registered_buffers.contains_key(&buffer_id)
 3080                && let Some(project) = self.project.as_ref()
 3081            {
 3082                project.update(cx, |project, cx| {
 3083                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3084                        return;
 3085                    };
 3086                    self.registered_buffers.insert(
 3087                        buffer_id,
 3088                        project.register_buffer_with_language_servers(&buffer, cx),
 3089                    );
 3090                })
 3091            }
 3092
 3093            let mut context_menu = self.context_menu.borrow_mut();
 3094            let completion_menu = match context_menu.as_ref() {
 3095                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3096                Some(CodeContextMenu::CodeActions(_)) => {
 3097                    *context_menu = None;
 3098                    None
 3099                }
 3100                None => None,
 3101            };
 3102            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3103            drop(context_menu);
 3104
 3105            if effects.completions
 3106                && let Some(completion_position) = completion_position
 3107            {
 3108                let start_offset = selection_start.to_offset(buffer);
 3109                let position_matches = start_offset == completion_position.to_offset(buffer);
 3110                let continue_showing = if position_matches {
 3111                    if self.snippet_stack.is_empty() {
 3112                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3113                    } else {
 3114                        // Snippet choices can be shown even when the cursor is in whitespace.
 3115                        // Dismissing the menu with actions like backspace is handled by
 3116                        // invalidation regions.
 3117                        true
 3118                    }
 3119                } else {
 3120                    false
 3121                };
 3122
 3123                if continue_showing {
 3124                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3125                } else {
 3126                    self.hide_context_menu(window, cx);
 3127                }
 3128            }
 3129
 3130            hide_hover(self, cx);
 3131
 3132            if old_cursor_position.to_display_point(&display_map).row()
 3133                != new_cursor_position.to_display_point(&display_map).row()
 3134            {
 3135                self.available_code_actions.take();
 3136            }
 3137            self.refresh_code_actions(window, cx);
 3138            self.refresh_document_highlights(cx);
 3139            self.refresh_selected_text_highlights(false, window, cx);
 3140            refresh_matching_bracket_highlights(self, window, cx);
 3141            self.update_visible_edit_prediction(window, cx);
 3142            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3143            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3144            self.inline_blame_popover.take();
 3145            if self.git_blame_inline_enabled {
 3146                self.start_inline_blame_timer(window, cx);
 3147            }
 3148        }
 3149
 3150        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3151        cx.emit(EditorEvent::SelectionsChanged { local });
 3152
 3153        let selections = &self.selections.disjoint;
 3154        if selections.len() == 1 {
 3155            cx.emit(SearchEvent::ActiveMatchChanged)
 3156        }
 3157        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3158            let inmemory_selections = selections
 3159                .iter()
 3160                .map(|s| {
 3161                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3162                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3163                })
 3164                .collect();
 3165            self.update_restoration_data(cx, |data| {
 3166                data.selections = inmemory_selections;
 3167            });
 3168
 3169            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3170                && let Some(workspace_id) =
 3171                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3172            {
 3173                let snapshot = self.buffer().read(cx).snapshot(cx);
 3174                let selections = selections.clone();
 3175                let background_executor = cx.background_executor().clone();
 3176                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3177                self.serialize_selections = cx.background_spawn(async move {
 3178                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3179                            let db_selections = selections
 3180                                .iter()
 3181                                .map(|selection| {
 3182                                    (
 3183                                        selection.start.to_offset(&snapshot),
 3184                                        selection.end.to_offset(&snapshot),
 3185                                    )
 3186                                })
 3187                                .collect();
 3188
 3189                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3190                                .await
 3191                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3192                                .log_err();
 3193                        });
 3194            }
 3195        }
 3196
 3197        cx.notify();
 3198    }
 3199
 3200    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3201        use text::ToOffset as _;
 3202        use text::ToPoint as _;
 3203
 3204        if self.mode.is_minimap()
 3205            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3206        {
 3207            return;
 3208        }
 3209
 3210        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3211            return;
 3212        };
 3213
 3214        let snapshot = singleton.read(cx).snapshot();
 3215        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3216            let display_snapshot = display_map.snapshot(cx);
 3217
 3218            display_snapshot
 3219                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3220                .map(|fold| {
 3221                    fold.range.start.text_anchor.to_point(&snapshot)
 3222                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3223                })
 3224                .collect()
 3225        });
 3226        self.update_restoration_data(cx, |data| {
 3227            data.folds = inmemory_folds;
 3228        });
 3229
 3230        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3231            return;
 3232        };
 3233        let background_executor = cx.background_executor().clone();
 3234        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3235        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3236            display_map
 3237                .snapshot(cx)
 3238                .folds_in_range(0..snapshot.len())
 3239                .map(|fold| {
 3240                    (
 3241                        fold.range.start.text_anchor.to_offset(&snapshot),
 3242                        fold.range.end.text_anchor.to_offset(&snapshot),
 3243                    )
 3244                })
 3245                .collect()
 3246        });
 3247        self.serialize_folds = cx.background_spawn(async move {
 3248            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3249            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3250                .await
 3251                .with_context(|| {
 3252                    format!(
 3253                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3254                    )
 3255                })
 3256                .log_err();
 3257        });
 3258    }
 3259
 3260    pub fn sync_selections(
 3261        &mut self,
 3262        other: Entity<Editor>,
 3263        cx: &mut Context<Self>,
 3264    ) -> gpui::Subscription {
 3265        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3266        self.selections.change_with(cx, |selections| {
 3267            selections.select_anchors(other_selections);
 3268        });
 3269
 3270        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3271            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3272                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3273                if other_selections.is_empty() {
 3274                    return;
 3275                }
 3276                this.selections.change_with(cx, |selections| {
 3277                    selections.select_anchors(other_selections);
 3278                });
 3279            }
 3280        });
 3281
 3282        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3283            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3284                let these_selections = this.selections.disjoint.to_vec();
 3285                if these_selections.is_empty() {
 3286                    return;
 3287                }
 3288                other.update(cx, |other_editor, cx| {
 3289                    other_editor.selections.change_with(cx, |selections| {
 3290                        selections.select_anchors(these_selections);
 3291                    })
 3292                });
 3293            }
 3294        });
 3295
 3296        Subscription::join(other_subscription, this_subscription)
 3297    }
 3298
 3299    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3300    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3301    /// effects of selection change occur at the end of the transaction.
 3302    pub fn change_selections<R>(
 3303        &mut self,
 3304        effects: SelectionEffects,
 3305        window: &mut Window,
 3306        cx: &mut Context<Self>,
 3307        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3308    ) -> R {
 3309        if let Some(state) = &mut self.deferred_selection_effects_state {
 3310            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3311            state.effects.completions = effects.completions;
 3312            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3313            let (changed, result) = self.selections.change_with(cx, change);
 3314            state.changed |= changed;
 3315            return result;
 3316        }
 3317        let mut state = DeferredSelectionEffectsState {
 3318            changed: false,
 3319            effects,
 3320            old_cursor_position: self.selections.newest_anchor().head(),
 3321            history_entry: SelectionHistoryEntry {
 3322                selections: self.selections.disjoint_anchors(),
 3323                select_next_state: self.select_next_state.clone(),
 3324                select_prev_state: self.select_prev_state.clone(),
 3325                add_selections_state: self.add_selections_state.clone(),
 3326            },
 3327        };
 3328        let (changed, result) = self.selections.change_with(cx, change);
 3329        state.changed = state.changed || changed;
 3330        if self.defer_selection_effects {
 3331            self.deferred_selection_effects_state = Some(state);
 3332        } else {
 3333            self.apply_selection_effects(state, window, cx);
 3334        }
 3335        result
 3336    }
 3337
 3338    /// Defers the effects of selection change, so that the effects of multiple calls to
 3339    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3340    /// to selection history and the state of popovers based on selection position aren't
 3341    /// erroneously updated.
 3342    pub fn with_selection_effects_deferred<R>(
 3343        &mut self,
 3344        window: &mut Window,
 3345        cx: &mut Context<Self>,
 3346        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3347    ) -> R {
 3348        let already_deferred = self.defer_selection_effects;
 3349        self.defer_selection_effects = true;
 3350        let result = update(self, window, cx);
 3351        if !already_deferred {
 3352            self.defer_selection_effects = false;
 3353            if let Some(state) = self.deferred_selection_effects_state.take() {
 3354                self.apply_selection_effects(state, window, cx);
 3355            }
 3356        }
 3357        result
 3358    }
 3359
 3360    fn apply_selection_effects(
 3361        &mut self,
 3362        state: DeferredSelectionEffectsState,
 3363        window: &mut Window,
 3364        cx: &mut Context<Self>,
 3365    ) {
 3366        if state.changed {
 3367            self.selection_history.push(state.history_entry);
 3368
 3369            if let Some(autoscroll) = state.effects.scroll {
 3370                self.request_autoscroll(autoscroll, cx);
 3371            }
 3372
 3373            let old_cursor_position = &state.old_cursor_position;
 3374
 3375            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3376
 3377            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3378                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3379            }
 3380        }
 3381    }
 3382
 3383    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3384    where
 3385        I: IntoIterator<Item = (Range<S>, T)>,
 3386        S: ToOffset,
 3387        T: Into<Arc<str>>,
 3388    {
 3389        if self.read_only(cx) {
 3390            return;
 3391        }
 3392
 3393        self.buffer
 3394            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3395    }
 3396
 3397    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3398    where
 3399        I: IntoIterator<Item = (Range<S>, T)>,
 3400        S: ToOffset,
 3401        T: Into<Arc<str>>,
 3402    {
 3403        if self.read_only(cx) {
 3404            return;
 3405        }
 3406
 3407        self.buffer.update(cx, |buffer, cx| {
 3408            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3409        });
 3410    }
 3411
 3412    pub fn edit_with_block_indent<I, S, T>(
 3413        &mut self,
 3414        edits: I,
 3415        original_indent_columns: Vec<Option<u32>>,
 3416        cx: &mut Context<Self>,
 3417    ) where
 3418        I: IntoIterator<Item = (Range<S>, T)>,
 3419        S: ToOffset,
 3420        T: Into<Arc<str>>,
 3421    {
 3422        if self.read_only(cx) {
 3423            return;
 3424        }
 3425
 3426        self.buffer.update(cx, |buffer, cx| {
 3427            buffer.edit(
 3428                edits,
 3429                Some(AutoindentMode::Block {
 3430                    original_indent_columns,
 3431                }),
 3432                cx,
 3433            )
 3434        });
 3435    }
 3436
 3437    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3438        self.hide_context_menu(window, cx);
 3439
 3440        match phase {
 3441            SelectPhase::Begin {
 3442                position,
 3443                add,
 3444                click_count,
 3445            } => self.begin_selection(position, add, click_count, window, cx),
 3446            SelectPhase::BeginColumnar {
 3447                position,
 3448                goal_column,
 3449                reset,
 3450                mode,
 3451            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3452            SelectPhase::Extend {
 3453                position,
 3454                click_count,
 3455            } => self.extend_selection(position, click_count, window, cx),
 3456            SelectPhase::Update {
 3457                position,
 3458                goal_column,
 3459                scroll_delta,
 3460            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3461            SelectPhase::End => self.end_selection(window, cx),
 3462        }
 3463    }
 3464
 3465    fn extend_selection(
 3466        &mut self,
 3467        position: DisplayPoint,
 3468        click_count: usize,
 3469        window: &mut Window,
 3470        cx: &mut Context<Self>,
 3471    ) {
 3472        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3473        let tail = self.selections.newest::<usize>(cx).tail();
 3474        self.begin_selection(position, false, click_count, window, cx);
 3475
 3476        let position = position.to_offset(&display_map, Bias::Left);
 3477        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3478
 3479        let mut pending_selection = self
 3480            .selections
 3481            .pending_anchor()
 3482            .expect("extend_selection not called with pending selection");
 3483        if position >= tail {
 3484            pending_selection.start = tail_anchor;
 3485        } else {
 3486            pending_selection.end = tail_anchor;
 3487            pending_selection.reversed = true;
 3488        }
 3489
 3490        let mut pending_mode = self.selections.pending_mode().unwrap();
 3491        match &mut pending_mode {
 3492            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3493            _ => {}
 3494        }
 3495
 3496        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3497            SelectionEffects::scroll(Autoscroll::fit())
 3498        } else {
 3499            SelectionEffects::no_scroll()
 3500        };
 3501
 3502        self.change_selections(effects, window, cx, |s| {
 3503            s.set_pending(pending_selection, pending_mode)
 3504        });
 3505    }
 3506
 3507    fn begin_selection(
 3508        &mut self,
 3509        position: DisplayPoint,
 3510        add: bool,
 3511        click_count: usize,
 3512        window: &mut Window,
 3513        cx: &mut Context<Self>,
 3514    ) {
 3515        if !self.focus_handle.is_focused(window) {
 3516            self.last_focused_descendant = None;
 3517            window.focus(&self.focus_handle);
 3518        }
 3519
 3520        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3521        let buffer = &display_map.buffer_snapshot;
 3522        let position = display_map.clip_point(position, Bias::Left);
 3523
 3524        let start;
 3525        let end;
 3526        let mode;
 3527        let mut auto_scroll;
 3528        match click_count {
 3529            1 => {
 3530                start = buffer.anchor_before(position.to_point(&display_map));
 3531                end = start;
 3532                mode = SelectMode::Character;
 3533                auto_scroll = true;
 3534            }
 3535            2 => {
 3536                let position = display_map
 3537                    .clip_point(position, Bias::Left)
 3538                    .to_offset(&display_map, Bias::Left);
 3539                let (range, _) = buffer.surrounding_word(position, false);
 3540                start = buffer.anchor_before(range.start);
 3541                end = buffer.anchor_before(range.end);
 3542                mode = SelectMode::Word(start..end);
 3543                auto_scroll = true;
 3544            }
 3545            3 => {
 3546                let position = display_map
 3547                    .clip_point(position, Bias::Left)
 3548                    .to_point(&display_map);
 3549                let line_start = display_map.prev_line_boundary(position).0;
 3550                let next_line_start = buffer.clip_point(
 3551                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3552                    Bias::Left,
 3553                );
 3554                start = buffer.anchor_before(line_start);
 3555                end = buffer.anchor_before(next_line_start);
 3556                mode = SelectMode::Line(start..end);
 3557                auto_scroll = true;
 3558            }
 3559            _ => {
 3560                start = buffer.anchor_before(0);
 3561                end = buffer.anchor_before(buffer.len());
 3562                mode = SelectMode::All;
 3563                auto_scroll = false;
 3564            }
 3565        }
 3566        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3567
 3568        let point_to_delete: Option<usize> = {
 3569            let selected_points: Vec<Selection<Point>> =
 3570                self.selections.disjoint_in_range(start..end, cx);
 3571
 3572            if !add || click_count > 1 {
 3573                None
 3574            } else if !selected_points.is_empty() {
 3575                Some(selected_points[0].id)
 3576            } else {
 3577                let clicked_point_already_selected =
 3578                    self.selections.disjoint.iter().find(|selection| {
 3579                        selection.start.to_point(buffer) == start.to_point(buffer)
 3580                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3581                    });
 3582
 3583                clicked_point_already_selected.map(|selection| selection.id)
 3584            }
 3585        };
 3586
 3587        let selections_count = self.selections.count();
 3588        let effects = if auto_scroll {
 3589            SelectionEffects::default()
 3590        } else {
 3591            SelectionEffects::no_scroll()
 3592        };
 3593
 3594        self.change_selections(effects, window, cx, |s| {
 3595            if let Some(point_to_delete) = point_to_delete {
 3596                s.delete(point_to_delete);
 3597
 3598                if selections_count == 1 {
 3599                    s.set_pending_anchor_range(start..end, mode);
 3600                }
 3601            } else {
 3602                if !add {
 3603                    s.clear_disjoint();
 3604                }
 3605
 3606                s.set_pending_anchor_range(start..end, mode);
 3607            }
 3608        });
 3609    }
 3610
 3611    fn begin_columnar_selection(
 3612        &mut self,
 3613        position: DisplayPoint,
 3614        goal_column: u32,
 3615        reset: bool,
 3616        mode: ColumnarMode,
 3617        window: &mut Window,
 3618        cx: &mut Context<Self>,
 3619    ) {
 3620        if !self.focus_handle.is_focused(window) {
 3621            self.last_focused_descendant = None;
 3622            window.focus(&self.focus_handle);
 3623        }
 3624
 3625        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3626
 3627        if reset {
 3628            let pointer_position = display_map
 3629                .buffer_snapshot
 3630                .anchor_before(position.to_point(&display_map));
 3631
 3632            self.change_selections(
 3633                SelectionEffects::scroll(Autoscroll::newest()),
 3634                window,
 3635                cx,
 3636                |s| {
 3637                    s.clear_disjoint();
 3638                    s.set_pending_anchor_range(
 3639                        pointer_position..pointer_position,
 3640                        SelectMode::Character,
 3641                    );
 3642                },
 3643            );
 3644        };
 3645
 3646        let tail = self.selections.newest::<Point>(cx).tail();
 3647        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3648        self.columnar_selection_state = match mode {
 3649            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3650                selection_tail: selection_anchor,
 3651                display_point: if reset {
 3652                    if position.column() != goal_column {
 3653                        Some(DisplayPoint::new(position.row(), goal_column))
 3654                    } else {
 3655                        None
 3656                    }
 3657                } else {
 3658                    None
 3659                },
 3660            }),
 3661            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3662                selection_tail: selection_anchor,
 3663            }),
 3664        };
 3665
 3666        if !reset {
 3667            self.select_columns(position, goal_column, &display_map, window, cx);
 3668        }
 3669    }
 3670
 3671    fn update_selection(
 3672        &mut self,
 3673        position: DisplayPoint,
 3674        goal_column: u32,
 3675        scroll_delta: gpui::Point<f32>,
 3676        window: &mut Window,
 3677        cx: &mut Context<Self>,
 3678    ) {
 3679        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3680
 3681        if self.columnar_selection_state.is_some() {
 3682            self.select_columns(position, goal_column, &display_map, window, cx);
 3683        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3684            let buffer = &display_map.buffer_snapshot;
 3685            let head;
 3686            let tail;
 3687            let mode = self.selections.pending_mode().unwrap();
 3688            match &mode {
 3689                SelectMode::Character => {
 3690                    head = position.to_point(&display_map);
 3691                    tail = pending.tail().to_point(buffer);
 3692                }
 3693                SelectMode::Word(original_range) => {
 3694                    let offset = display_map
 3695                        .clip_point(position, Bias::Left)
 3696                        .to_offset(&display_map, Bias::Left);
 3697                    let original_range = original_range.to_offset(buffer);
 3698
 3699                    let head_offset = if buffer.is_inside_word(offset, false)
 3700                        || original_range.contains(&offset)
 3701                    {
 3702                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3703                        if word_range.start < original_range.start {
 3704                            word_range.start
 3705                        } else {
 3706                            word_range.end
 3707                        }
 3708                    } else {
 3709                        offset
 3710                    };
 3711
 3712                    head = head_offset.to_point(buffer);
 3713                    if head_offset <= original_range.start {
 3714                        tail = original_range.end.to_point(buffer);
 3715                    } else {
 3716                        tail = original_range.start.to_point(buffer);
 3717                    }
 3718                }
 3719                SelectMode::Line(original_range) => {
 3720                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3721
 3722                    let position = display_map
 3723                        .clip_point(position, Bias::Left)
 3724                        .to_point(&display_map);
 3725                    let line_start = display_map.prev_line_boundary(position).0;
 3726                    let next_line_start = buffer.clip_point(
 3727                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3728                        Bias::Left,
 3729                    );
 3730
 3731                    if line_start < original_range.start {
 3732                        head = line_start
 3733                    } else {
 3734                        head = next_line_start
 3735                    }
 3736
 3737                    if head <= original_range.start {
 3738                        tail = original_range.end;
 3739                    } else {
 3740                        tail = original_range.start;
 3741                    }
 3742                }
 3743                SelectMode::All => {
 3744                    return;
 3745                }
 3746            };
 3747
 3748            if head < tail {
 3749                pending.start = buffer.anchor_before(head);
 3750                pending.end = buffer.anchor_before(tail);
 3751                pending.reversed = true;
 3752            } else {
 3753                pending.start = buffer.anchor_before(tail);
 3754                pending.end = buffer.anchor_before(head);
 3755                pending.reversed = false;
 3756            }
 3757
 3758            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3759                s.set_pending(pending, mode);
 3760            });
 3761        } else {
 3762            log::error!("update_selection dispatched with no pending selection");
 3763            return;
 3764        }
 3765
 3766        self.apply_scroll_delta(scroll_delta, window, cx);
 3767        cx.notify();
 3768    }
 3769
 3770    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3771        self.columnar_selection_state.take();
 3772        if self.selections.pending_anchor().is_some() {
 3773            let selections = self.selections.all::<usize>(cx);
 3774            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3775                s.select(selections);
 3776                s.clear_pending();
 3777            });
 3778        }
 3779    }
 3780
 3781    fn select_columns(
 3782        &mut self,
 3783        head: DisplayPoint,
 3784        goal_column: u32,
 3785        display_map: &DisplaySnapshot,
 3786        window: &mut Window,
 3787        cx: &mut Context<Self>,
 3788    ) {
 3789        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3790            return;
 3791        };
 3792
 3793        let tail = match columnar_state {
 3794            ColumnarSelectionState::FromMouse {
 3795                selection_tail,
 3796                display_point,
 3797            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3798            ColumnarSelectionState::FromSelection { selection_tail } => {
 3799                selection_tail.to_display_point(display_map)
 3800            }
 3801        };
 3802
 3803        let start_row = cmp::min(tail.row(), head.row());
 3804        let end_row = cmp::max(tail.row(), head.row());
 3805        let start_column = cmp::min(tail.column(), goal_column);
 3806        let end_column = cmp::max(tail.column(), goal_column);
 3807        let reversed = start_column < tail.column();
 3808
 3809        let selection_ranges = (start_row.0..=end_row.0)
 3810            .map(DisplayRow)
 3811            .filter_map(|row| {
 3812                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3813                    || start_column <= display_map.line_len(row))
 3814                    && !display_map.is_block_line(row)
 3815                {
 3816                    let start = display_map
 3817                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3818                        .to_point(display_map);
 3819                    let end = display_map
 3820                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3821                        .to_point(display_map);
 3822                    if reversed {
 3823                        Some(end..start)
 3824                    } else {
 3825                        Some(start..end)
 3826                    }
 3827                } else {
 3828                    None
 3829                }
 3830            })
 3831            .collect::<Vec<_>>();
 3832
 3833        let ranges = match columnar_state {
 3834            ColumnarSelectionState::FromMouse { .. } => {
 3835                let mut non_empty_ranges = selection_ranges
 3836                    .iter()
 3837                    .filter(|selection_range| selection_range.start != selection_range.end)
 3838                    .peekable();
 3839                if non_empty_ranges.peek().is_some() {
 3840                    non_empty_ranges.cloned().collect()
 3841                } else {
 3842                    selection_ranges
 3843                }
 3844            }
 3845            _ => selection_ranges,
 3846        };
 3847
 3848        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3849            s.select_ranges(ranges);
 3850        });
 3851        cx.notify();
 3852    }
 3853
 3854    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3855        self.selections
 3856            .all_adjusted(cx)
 3857            .iter()
 3858            .any(|selection| !selection.is_empty())
 3859    }
 3860
 3861    pub fn has_pending_nonempty_selection(&self) -> bool {
 3862        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3863            Some(Selection { start, end, .. }) => start != end,
 3864            None => false,
 3865        };
 3866
 3867        pending_nonempty_selection
 3868            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3869    }
 3870
 3871    pub fn has_pending_selection(&self) -> bool {
 3872        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3873    }
 3874
 3875    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3876        self.selection_mark_mode = false;
 3877        self.selection_drag_state = SelectionDragState::None;
 3878
 3879        if self.clear_expanded_diff_hunks(cx) {
 3880            cx.notify();
 3881            return;
 3882        }
 3883        if self.dismiss_menus_and_popups(true, window, cx) {
 3884            return;
 3885        }
 3886
 3887        if self.mode.is_full()
 3888            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3889        {
 3890            return;
 3891        }
 3892
 3893        cx.propagate();
 3894    }
 3895
 3896    pub fn dismiss_menus_and_popups(
 3897        &mut self,
 3898        is_user_requested: bool,
 3899        window: &mut Window,
 3900        cx: &mut Context<Self>,
 3901    ) -> bool {
 3902        if self.take_rename(false, window, cx).is_some() {
 3903            return true;
 3904        }
 3905
 3906        if hide_hover(self, cx) {
 3907            return true;
 3908        }
 3909
 3910        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3911            return true;
 3912        }
 3913
 3914        if self.hide_context_menu(window, cx).is_some() {
 3915            return true;
 3916        }
 3917
 3918        if self.mouse_context_menu.take().is_some() {
 3919            return true;
 3920        }
 3921
 3922        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3923            return true;
 3924        }
 3925
 3926        if self.snippet_stack.pop().is_some() {
 3927            return true;
 3928        }
 3929
 3930        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3931            self.dismiss_diagnostics(cx);
 3932            return true;
 3933        }
 3934
 3935        false
 3936    }
 3937
 3938    fn linked_editing_ranges_for(
 3939        &self,
 3940        selection: Range<text::Anchor>,
 3941        cx: &App,
 3942    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3943        if self.linked_edit_ranges.is_empty() {
 3944            return None;
 3945        }
 3946        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3947            selection.end.buffer_id.and_then(|end_buffer_id| {
 3948                if selection.start.buffer_id != Some(end_buffer_id) {
 3949                    return None;
 3950                }
 3951                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3952                let snapshot = buffer.read(cx).snapshot();
 3953                self.linked_edit_ranges
 3954                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3955                    .map(|ranges| (ranges, snapshot, buffer))
 3956            })?;
 3957        use text::ToOffset as TO;
 3958        // find offset from the start of current range to current cursor position
 3959        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3960
 3961        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3962        let start_difference = start_offset - start_byte_offset;
 3963        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3964        let end_difference = end_offset - start_byte_offset;
 3965        // Current range has associated linked ranges.
 3966        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3967        for range in linked_ranges.iter() {
 3968            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3969            let end_offset = start_offset + end_difference;
 3970            let start_offset = start_offset + start_difference;
 3971            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3972                continue;
 3973            }
 3974            if self.selections.disjoint_anchor_ranges().any(|s| {
 3975                if s.start.buffer_id != selection.start.buffer_id
 3976                    || s.end.buffer_id != selection.end.buffer_id
 3977                {
 3978                    return false;
 3979                }
 3980                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3981                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3982            }) {
 3983                continue;
 3984            }
 3985            let start = buffer_snapshot.anchor_after(start_offset);
 3986            let end = buffer_snapshot.anchor_after(end_offset);
 3987            linked_edits
 3988                .entry(buffer.clone())
 3989                .or_default()
 3990                .push(start..end);
 3991        }
 3992        Some(linked_edits)
 3993    }
 3994
 3995    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3996        let text: Arc<str> = text.into();
 3997
 3998        if self.read_only(cx) {
 3999            return;
 4000        }
 4001
 4002        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4003
 4004        let selections = self.selections.all_adjusted(cx);
 4005        let mut bracket_inserted = false;
 4006        let mut edits = Vec::new();
 4007        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4008        let mut new_selections = Vec::with_capacity(selections.len());
 4009        let mut new_autoclose_regions = Vec::new();
 4010        let snapshot = self.buffer.read(cx).read(cx);
 4011        let mut clear_linked_edit_ranges = false;
 4012
 4013        for (selection, autoclose_region) in
 4014            self.selections_with_autoclose_regions(selections, &snapshot)
 4015        {
 4016            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4017                // Determine if the inserted text matches the opening or closing
 4018                // bracket of any of this language's bracket pairs.
 4019                let mut bracket_pair = None;
 4020                let mut is_bracket_pair_start = false;
 4021                let mut is_bracket_pair_end = false;
 4022                if !text.is_empty() {
 4023                    let mut bracket_pair_matching_end = None;
 4024                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4025                    //  and they are removing the character that triggered IME popup.
 4026                    for (pair, enabled) in scope.brackets() {
 4027                        if !pair.close && !pair.surround {
 4028                            continue;
 4029                        }
 4030
 4031                        if enabled && pair.start.ends_with(text.as_ref()) {
 4032                            let prefix_len = pair.start.len() - text.len();
 4033                            let preceding_text_matches_prefix = prefix_len == 0
 4034                                || (selection.start.column >= (prefix_len as u32)
 4035                                    && snapshot.contains_str_at(
 4036                                        Point::new(
 4037                                            selection.start.row,
 4038                                            selection.start.column - (prefix_len as u32),
 4039                                        ),
 4040                                        &pair.start[..prefix_len],
 4041                                    ));
 4042                            if preceding_text_matches_prefix {
 4043                                bracket_pair = Some(pair.clone());
 4044                                is_bracket_pair_start = true;
 4045                                break;
 4046                            }
 4047                        }
 4048                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4049                        {
 4050                            // take first bracket pair matching end, but don't break in case a later bracket
 4051                            // pair matches start
 4052                            bracket_pair_matching_end = Some(pair.clone());
 4053                        }
 4054                    }
 4055                    if let Some(end) = bracket_pair_matching_end
 4056                        && bracket_pair.is_none()
 4057                    {
 4058                        bracket_pair = Some(end);
 4059                        is_bracket_pair_end = true;
 4060                    }
 4061                }
 4062
 4063                if let Some(bracket_pair) = bracket_pair {
 4064                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4065                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4066                    let auto_surround =
 4067                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4068                    if selection.is_empty() {
 4069                        if is_bracket_pair_start {
 4070                            // If the inserted text is a suffix of an opening bracket and the
 4071                            // selection is preceded by the rest of the opening bracket, then
 4072                            // insert the closing bracket.
 4073                            let following_text_allows_autoclose = snapshot
 4074                                .chars_at(selection.start)
 4075                                .next()
 4076                                .is_none_or(|c| scope.should_autoclose_before(c));
 4077
 4078                            let preceding_text_allows_autoclose = selection.start.column == 0
 4079                                || snapshot
 4080                                    .reversed_chars_at(selection.start)
 4081                                    .next()
 4082                                    .is_none_or(|c| {
 4083                                        bracket_pair.start != bracket_pair.end
 4084                                            || !snapshot
 4085                                                .char_classifier_at(selection.start)
 4086                                                .is_word(c)
 4087                                    });
 4088
 4089                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4090                                && bracket_pair.start.len() == 1
 4091                            {
 4092                                let target = bracket_pair.start.chars().next().unwrap();
 4093                                let current_line_count = snapshot
 4094                                    .reversed_chars_at(selection.start)
 4095                                    .take_while(|&c| c != '\n')
 4096                                    .filter(|&c| c == target)
 4097                                    .count();
 4098                                current_line_count % 2 == 1
 4099                            } else {
 4100                                false
 4101                            };
 4102
 4103                            if autoclose
 4104                                && bracket_pair.close
 4105                                && following_text_allows_autoclose
 4106                                && preceding_text_allows_autoclose
 4107                                && !is_closing_quote
 4108                            {
 4109                                let anchor = snapshot.anchor_before(selection.end);
 4110                                new_selections.push((selection.map(|_| anchor), text.len()));
 4111                                new_autoclose_regions.push((
 4112                                    anchor,
 4113                                    text.len(),
 4114                                    selection.id,
 4115                                    bracket_pair.clone(),
 4116                                ));
 4117                                edits.push((
 4118                                    selection.range(),
 4119                                    format!("{}{}", text, bracket_pair.end).into(),
 4120                                ));
 4121                                bracket_inserted = true;
 4122                                continue;
 4123                            }
 4124                        }
 4125
 4126                        if let Some(region) = autoclose_region {
 4127                            // If the selection is followed by an auto-inserted closing bracket,
 4128                            // then don't insert that closing bracket again; just move the selection
 4129                            // past the closing bracket.
 4130                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4131                                && text.as_ref() == region.pair.end.as_str()
 4132                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4133                            if should_skip {
 4134                                let anchor = snapshot.anchor_after(selection.end);
 4135                                new_selections
 4136                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4137                                continue;
 4138                            }
 4139                        }
 4140
 4141                        let always_treat_brackets_as_autoclosed = snapshot
 4142                            .language_settings_at(selection.start, cx)
 4143                            .always_treat_brackets_as_autoclosed;
 4144                        if always_treat_brackets_as_autoclosed
 4145                            && is_bracket_pair_end
 4146                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4147                        {
 4148                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4149                            // and the inserted text is a closing bracket and the selection is followed
 4150                            // by the closing bracket then move the selection past the closing bracket.
 4151                            let anchor = snapshot.anchor_after(selection.end);
 4152                            new_selections.push((selection.map(|_| anchor), text.len()));
 4153                            continue;
 4154                        }
 4155                    }
 4156                    // If an opening bracket is 1 character long and is typed while
 4157                    // text is selected, then surround that text with the bracket pair.
 4158                    else if auto_surround
 4159                        && bracket_pair.surround
 4160                        && is_bracket_pair_start
 4161                        && bracket_pair.start.chars().count() == 1
 4162                    {
 4163                        edits.push((selection.start..selection.start, text.clone()));
 4164                        edits.push((
 4165                            selection.end..selection.end,
 4166                            bracket_pair.end.as_str().into(),
 4167                        ));
 4168                        bracket_inserted = true;
 4169                        new_selections.push((
 4170                            Selection {
 4171                                id: selection.id,
 4172                                start: snapshot.anchor_after(selection.start),
 4173                                end: snapshot.anchor_before(selection.end),
 4174                                reversed: selection.reversed,
 4175                                goal: selection.goal,
 4176                            },
 4177                            0,
 4178                        ));
 4179                        continue;
 4180                    }
 4181                }
 4182            }
 4183
 4184            if self.auto_replace_emoji_shortcode
 4185                && selection.is_empty()
 4186                && text.as_ref().ends_with(':')
 4187                && let Some(possible_emoji_short_code) =
 4188                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4189                && !possible_emoji_short_code.is_empty()
 4190                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4191            {
 4192                let emoji_shortcode_start = Point::new(
 4193                    selection.start.row,
 4194                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4195                );
 4196
 4197                // Remove shortcode from buffer
 4198                edits.push((
 4199                    emoji_shortcode_start..selection.start,
 4200                    "".to_string().into(),
 4201                ));
 4202                new_selections.push((
 4203                    Selection {
 4204                        id: selection.id,
 4205                        start: snapshot.anchor_after(emoji_shortcode_start),
 4206                        end: snapshot.anchor_before(selection.start),
 4207                        reversed: selection.reversed,
 4208                        goal: selection.goal,
 4209                    },
 4210                    0,
 4211                ));
 4212
 4213                // Insert emoji
 4214                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4215                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4216                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4217
 4218                continue;
 4219            }
 4220
 4221            // If not handling any auto-close operation, then just replace the selected
 4222            // text with the given input and move the selection to the end of the
 4223            // newly inserted text.
 4224            let anchor = snapshot.anchor_after(selection.end);
 4225            if !self.linked_edit_ranges.is_empty() {
 4226                let start_anchor = snapshot.anchor_before(selection.start);
 4227
 4228                let is_word_char = text.chars().next().is_none_or(|char| {
 4229                    let classifier = snapshot
 4230                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4231                        .ignore_punctuation(true);
 4232                    classifier.is_word(char)
 4233                });
 4234
 4235                if is_word_char {
 4236                    if let Some(ranges) = self
 4237                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4238                    {
 4239                        for (buffer, edits) in ranges {
 4240                            linked_edits
 4241                                .entry(buffer.clone())
 4242                                .or_default()
 4243                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4244                        }
 4245                    }
 4246                } else {
 4247                    clear_linked_edit_ranges = true;
 4248                }
 4249            }
 4250
 4251            new_selections.push((selection.map(|_| anchor), 0));
 4252            edits.push((selection.start..selection.end, text.clone()));
 4253        }
 4254
 4255        drop(snapshot);
 4256
 4257        self.transact(window, cx, |this, window, cx| {
 4258            if clear_linked_edit_ranges {
 4259                this.linked_edit_ranges.clear();
 4260            }
 4261            let initial_buffer_versions =
 4262                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4263
 4264            this.buffer.update(cx, |buffer, cx| {
 4265                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4266            });
 4267            for (buffer, edits) in linked_edits {
 4268                buffer.update(cx, |buffer, cx| {
 4269                    let snapshot = buffer.snapshot();
 4270                    let edits = edits
 4271                        .into_iter()
 4272                        .map(|(range, text)| {
 4273                            use text::ToPoint as TP;
 4274                            let end_point = TP::to_point(&range.end, &snapshot);
 4275                            let start_point = TP::to_point(&range.start, &snapshot);
 4276                            (start_point..end_point, text)
 4277                        })
 4278                        .sorted_by_key(|(range, _)| range.start);
 4279                    buffer.edit(edits, None, cx);
 4280                })
 4281            }
 4282            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4283            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4284            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4285            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4286                .zip(new_selection_deltas)
 4287                .map(|(selection, delta)| Selection {
 4288                    id: selection.id,
 4289                    start: selection.start + delta,
 4290                    end: selection.end + delta,
 4291                    reversed: selection.reversed,
 4292                    goal: SelectionGoal::None,
 4293                })
 4294                .collect::<Vec<_>>();
 4295
 4296            let mut i = 0;
 4297            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4298                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4299                let start = map.buffer_snapshot.anchor_before(position);
 4300                let end = map.buffer_snapshot.anchor_after(position);
 4301                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4302                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4303                        Ordering::Less => i += 1,
 4304                        Ordering::Greater => break,
 4305                        Ordering::Equal => {
 4306                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4307                                Ordering::Less => i += 1,
 4308                                Ordering::Equal => break,
 4309                                Ordering::Greater => break,
 4310                            }
 4311                        }
 4312                    }
 4313                }
 4314                this.autoclose_regions.insert(
 4315                    i,
 4316                    AutocloseRegion {
 4317                        selection_id,
 4318                        range: start..end,
 4319                        pair,
 4320                    },
 4321                );
 4322            }
 4323
 4324            let had_active_edit_prediction = this.has_active_edit_prediction();
 4325            this.change_selections(
 4326                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4327                window,
 4328                cx,
 4329                |s| s.select(new_selections),
 4330            );
 4331
 4332            if !bracket_inserted
 4333                && let Some(on_type_format_task) =
 4334                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4335            {
 4336                on_type_format_task.detach_and_log_err(cx);
 4337            }
 4338
 4339            let editor_settings = EditorSettings::get_global(cx);
 4340            if bracket_inserted
 4341                && (editor_settings.auto_signature_help
 4342                    || editor_settings.show_signature_help_after_edits)
 4343            {
 4344                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4345            }
 4346
 4347            let trigger_in_words =
 4348                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4349            if this.hard_wrap.is_some() {
 4350                let latest: Range<Point> = this.selections.newest(cx).range();
 4351                if latest.is_empty()
 4352                    && this
 4353                        .buffer()
 4354                        .read(cx)
 4355                        .snapshot(cx)
 4356                        .line_len(MultiBufferRow(latest.start.row))
 4357                        == latest.start.column
 4358                {
 4359                    this.rewrap_impl(
 4360                        RewrapOptions {
 4361                            override_language_settings: true,
 4362                            preserve_existing_whitespace: true,
 4363                        },
 4364                        cx,
 4365                    )
 4366                }
 4367            }
 4368            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4369            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4370            this.refresh_edit_prediction(true, false, window, cx);
 4371            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4372        });
 4373    }
 4374
 4375    fn find_possible_emoji_shortcode_at_position(
 4376        snapshot: &MultiBufferSnapshot,
 4377        position: Point,
 4378    ) -> Option<String> {
 4379        let mut chars = Vec::new();
 4380        let mut found_colon = false;
 4381        for char in snapshot.reversed_chars_at(position).take(100) {
 4382            // Found a possible emoji shortcode in the middle of the buffer
 4383            if found_colon {
 4384                if char.is_whitespace() {
 4385                    chars.reverse();
 4386                    return Some(chars.iter().collect());
 4387                }
 4388                // If the previous character is not a whitespace, we are in the middle of a word
 4389                // and we only want to complete the shortcode if the word is made up of other emojis
 4390                let mut containing_word = String::new();
 4391                for ch in snapshot
 4392                    .reversed_chars_at(position)
 4393                    .skip(chars.len() + 1)
 4394                    .take(100)
 4395                {
 4396                    if ch.is_whitespace() {
 4397                        break;
 4398                    }
 4399                    containing_word.push(ch);
 4400                }
 4401                let containing_word = containing_word.chars().rev().collect::<String>();
 4402                if util::word_consists_of_emojis(containing_word.as_str()) {
 4403                    chars.reverse();
 4404                    return Some(chars.iter().collect());
 4405                }
 4406            }
 4407
 4408            if char.is_whitespace() || !char.is_ascii() {
 4409                return None;
 4410            }
 4411            if char == ':' {
 4412                found_colon = true;
 4413            } else {
 4414                chars.push(char);
 4415            }
 4416        }
 4417        // Found a possible emoji shortcode at the beginning of the buffer
 4418        chars.reverse();
 4419        Some(chars.iter().collect())
 4420    }
 4421
 4422    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4423        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4424        self.transact(window, cx, |this, window, cx| {
 4425            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4426                let selections = this.selections.all::<usize>(cx);
 4427                let multi_buffer = this.buffer.read(cx);
 4428                let buffer = multi_buffer.snapshot(cx);
 4429                selections
 4430                    .iter()
 4431                    .map(|selection| {
 4432                        let start_point = selection.start.to_point(&buffer);
 4433                        let mut existing_indent =
 4434                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4435                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4436                        let start = selection.start;
 4437                        let end = selection.end;
 4438                        let selection_is_empty = start == end;
 4439                        let language_scope = buffer.language_scope_at(start);
 4440                        let (
 4441                            comment_delimiter,
 4442                            doc_delimiter,
 4443                            insert_extra_newline,
 4444                            indent_on_newline,
 4445                            indent_on_extra_newline,
 4446                        ) = if let Some(language) = &language_scope {
 4447                            let mut insert_extra_newline =
 4448                                insert_extra_newline_brackets(&buffer, start..end, language)
 4449                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4450
 4451                            // Comment extension on newline is allowed only for cursor selections
 4452                            let comment_delimiter = maybe!({
 4453                                if !selection_is_empty {
 4454                                    return None;
 4455                                }
 4456
 4457                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4458                                    return None;
 4459                                }
 4460
 4461                                let delimiters = language.line_comment_prefixes();
 4462                                let max_len_of_delimiter =
 4463                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4464                                let (snapshot, range) =
 4465                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4466
 4467                                let num_of_whitespaces = snapshot
 4468                                    .chars_for_range(range.clone())
 4469                                    .take_while(|c| c.is_whitespace())
 4470                                    .count();
 4471                                let comment_candidate = snapshot
 4472                                    .chars_for_range(range.clone())
 4473                                    .skip(num_of_whitespaces)
 4474                                    .take(max_len_of_delimiter)
 4475                                    .collect::<String>();
 4476                                let (delimiter, trimmed_len) = delimiters
 4477                                    .iter()
 4478                                    .filter_map(|delimiter| {
 4479                                        let prefix = delimiter.trim_end();
 4480                                        if comment_candidate.starts_with(prefix) {
 4481                                            Some((delimiter, prefix.len()))
 4482                                        } else {
 4483                                            None
 4484                                        }
 4485                                    })
 4486                                    .max_by_key(|(_, len)| *len)?;
 4487
 4488                                if let Some(BlockCommentConfig {
 4489                                    start: block_start, ..
 4490                                }) = language.block_comment()
 4491                                {
 4492                                    let block_start_trimmed = block_start.trim_end();
 4493                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4494                                        let line_content = snapshot
 4495                                            .chars_for_range(range)
 4496                                            .skip(num_of_whitespaces)
 4497                                            .take(block_start_trimmed.len())
 4498                                            .collect::<String>();
 4499
 4500                                        if line_content.starts_with(block_start_trimmed) {
 4501                                            return None;
 4502                                        }
 4503                                    }
 4504                                }
 4505
 4506                                let cursor_is_placed_after_comment_marker =
 4507                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4508                                if cursor_is_placed_after_comment_marker {
 4509                                    Some(delimiter.clone())
 4510                                } else {
 4511                                    None
 4512                                }
 4513                            });
 4514
 4515                            let mut indent_on_newline = IndentSize::spaces(0);
 4516                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4517
 4518                            let doc_delimiter = maybe!({
 4519                                if !selection_is_empty {
 4520                                    return None;
 4521                                }
 4522
 4523                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4524                                    return None;
 4525                                }
 4526
 4527                                let BlockCommentConfig {
 4528                                    start: start_tag,
 4529                                    end: end_tag,
 4530                                    prefix: delimiter,
 4531                                    tab_size: len,
 4532                                } = language.documentation_comment()?;
 4533                                let is_within_block_comment = buffer
 4534                                    .language_scope_at(start_point)
 4535                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4536                                if !is_within_block_comment {
 4537                                    return None;
 4538                                }
 4539
 4540                                let (snapshot, range) =
 4541                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4542
 4543                                let num_of_whitespaces = snapshot
 4544                                    .chars_for_range(range.clone())
 4545                                    .take_while(|c| c.is_whitespace())
 4546                                    .count();
 4547
 4548                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4549                                let column = start_point.column;
 4550                                let cursor_is_after_start_tag = {
 4551                                    let start_tag_len = start_tag.len();
 4552                                    let start_tag_line = snapshot
 4553                                        .chars_for_range(range.clone())
 4554                                        .skip(num_of_whitespaces)
 4555                                        .take(start_tag_len)
 4556                                        .collect::<String>();
 4557                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4558                                        num_of_whitespaces + start_tag_len <= column as usize
 4559                                    } else {
 4560                                        false
 4561                                    }
 4562                                };
 4563
 4564                                let cursor_is_after_delimiter = {
 4565                                    let delimiter_trim = delimiter.trim_end();
 4566                                    let delimiter_line = snapshot
 4567                                        .chars_for_range(range.clone())
 4568                                        .skip(num_of_whitespaces)
 4569                                        .take(delimiter_trim.len())
 4570                                        .collect::<String>();
 4571                                    if delimiter_line.starts_with(delimiter_trim) {
 4572                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4573                                    } else {
 4574                                        false
 4575                                    }
 4576                                };
 4577
 4578                                let cursor_is_before_end_tag_if_exists = {
 4579                                    let mut char_position = 0u32;
 4580                                    let mut end_tag_offset = None;
 4581
 4582                                    'outer: for chunk in snapshot.text_for_range(range) {
 4583                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4584                                            let chars_before_match =
 4585                                                chunk[..byte_pos].chars().count() as u32;
 4586                                            end_tag_offset =
 4587                                                Some(char_position + chars_before_match);
 4588                                            break 'outer;
 4589                                        }
 4590                                        char_position += chunk.chars().count() as u32;
 4591                                    }
 4592
 4593                                    if let Some(end_tag_offset) = end_tag_offset {
 4594                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4595                                        if cursor_is_after_start_tag {
 4596                                            if cursor_is_before_end_tag {
 4597                                                insert_extra_newline = true;
 4598                                            }
 4599                                            let cursor_is_at_start_of_end_tag =
 4600                                                column == end_tag_offset;
 4601                                            if cursor_is_at_start_of_end_tag {
 4602                                                indent_on_extra_newline.len = *len;
 4603                                            }
 4604                                        }
 4605                                        cursor_is_before_end_tag
 4606                                    } else {
 4607                                        true
 4608                                    }
 4609                                };
 4610
 4611                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4612                                    && cursor_is_before_end_tag_if_exists
 4613                                {
 4614                                    if cursor_is_after_start_tag {
 4615                                        indent_on_newline.len = *len;
 4616                                    }
 4617                                    Some(delimiter.clone())
 4618                                } else {
 4619                                    None
 4620                                }
 4621                            });
 4622
 4623                            (
 4624                                comment_delimiter,
 4625                                doc_delimiter,
 4626                                insert_extra_newline,
 4627                                indent_on_newline,
 4628                                indent_on_extra_newline,
 4629                            )
 4630                        } else {
 4631                            (
 4632                                None,
 4633                                None,
 4634                                false,
 4635                                IndentSize::default(),
 4636                                IndentSize::default(),
 4637                            )
 4638                        };
 4639
 4640                        let prevent_auto_indent = doc_delimiter.is_some();
 4641                        let delimiter = comment_delimiter.or(doc_delimiter);
 4642
 4643                        let capacity_for_delimiter =
 4644                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4645                        let mut new_text = String::with_capacity(
 4646                            1 + capacity_for_delimiter
 4647                                + existing_indent.len as usize
 4648                                + indent_on_newline.len as usize
 4649                                + indent_on_extra_newline.len as usize,
 4650                        );
 4651                        new_text.push('\n');
 4652                        new_text.extend(existing_indent.chars());
 4653                        new_text.extend(indent_on_newline.chars());
 4654
 4655                        if let Some(delimiter) = &delimiter {
 4656                            new_text.push_str(delimiter);
 4657                        }
 4658
 4659                        if insert_extra_newline {
 4660                            new_text.push('\n');
 4661                            new_text.extend(existing_indent.chars());
 4662                            new_text.extend(indent_on_extra_newline.chars());
 4663                        }
 4664
 4665                        let anchor = buffer.anchor_after(end);
 4666                        let new_selection = selection.map(|_| anchor);
 4667                        (
 4668                            ((start..end, new_text), prevent_auto_indent),
 4669                            (insert_extra_newline, new_selection),
 4670                        )
 4671                    })
 4672                    .unzip()
 4673            };
 4674
 4675            let mut auto_indent_edits = Vec::new();
 4676            let mut edits = Vec::new();
 4677            for (edit, prevent_auto_indent) in edits_with_flags {
 4678                if prevent_auto_indent {
 4679                    edits.push(edit);
 4680                } else {
 4681                    auto_indent_edits.push(edit);
 4682                }
 4683            }
 4684            if !edits.is_empty() {
 4685                this.edit(edits, cx);
 4686            }
 4687            if !auto_indent_edits.is_empty() {
 4688                this.edit_with_autoindent(auto_indent_edits, cx);
 4689            }
 4690
 4691            let buffer = this.buffer.read(cx).snapshot(cx);
 4692            let new_selections = selection_info
 4693                .into_iter()
 4694                .map(|(extra_newline_inserted, new_selection)| {
 4695                    let mut cursor = new_selection.end.to_point(&buffer);
 4696                    if extra_newline_inserted {
 4697                        cursor.row -= 1;
 4698                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4699                    }
 4700                    new_selection.map(|_| cursor)
 4701                })
 4702                .collect();
 4703
 4704            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4705            this.refresh_edit_prediction(true, false, window, cx);
 4706        });
 4707    }
 4708
 4709    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4710        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4711
 4712        let buffer = self.buffer.read(cx);
 4713        let snapshot = buffer.snapshot(cx);
 4714
 4715        let mut edits = Vec::new();
 4716        let mut rows = Vec::new();
 4717
 4718        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4719            let cursor = selection.head();
 4720            let row = cursor.row;
 4721
 4722            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4723
 4724            let newline = "\n".to_string();
 4725            edits.push((start_of_line..start_of_line, newline));
 4726
 4727            rows.push(row + rows_inserted as u32);
 4728        }
 4729
 4730        self.transact(window, cx, |editor, window, cx| {
 4731            editor.edit(edits, cx);
 4732
 4733            editor.change_selections(Default::default(), window, cx, |s| {
 4734                let mut index = 0;
 4735                s.move_cursors_with(|map, _, _| {
 4736                    let row = rows[index];
 4737                    index += 1;
 4738
 4739                    let point = Point::new(row, 0);
 4740                    let boundary = map.next_line_boundary(point).1;
 4741                    let clipped = map.clip_point(boundary, Bias::Left);
 4742
 4743                    (clipped, SelectionGoal::None)
 4744                });
 4745            });
 4746
 4747            let mut indent_edits = Vec::new();
 4748            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4749            for row in rows {
 4750                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4751                for (row, indent) in indents {
 4752                    if indent.len == 0 {
 4753                        continue;
 4754                    }
 4755
 4756                    let text = match indent.kind {
 4757                        IndentKind::Space => " ".repeat(indent.len as usize),
 4758                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4759                    };
 4760                    let point = Point::new(row.0, 0);
 4761                    indent_edits.push((point..point, text));
 4762                }
 4763            }
 4764            editor.edit(indent_edits, cx);
 4765        });
 4766    }
 4767
 4768    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4769        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4770
 4771        let buffer = self.buffer.read(cx);
 4772        let snapshot = buffer.snapshot(cx);
 4773
 4774        let mut edits = Vec::new();
 4775        let mut rows = Vec::new();
 4776        let mut rows_inserted = 0;
 4777
 4778        for selection in self.selections.all_adjusted(cx) {
 4779            let cursor = selection.head();
 4780            let row = cursor.row;
 4781
 4782            let point = Point::new(row + 1, 0);
 4783            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4784
 4785            let newline = "\n".to_string();
 4786            edits.push((start_of_line..start_of_line, newline));
 4787
 4788            rows_inserted += 1;
 4789            rows.push(row + rows_inserted);
 4790        }
 4791
 4792        self.transact(window, cx, |editor, window, cx| {
 4793            editor.edit(edits, cx);
 4794
 4795            editor.change_selections(Default::default(), window, cx, |s| {
 4796                let mut index = 0;
 4797                s.move_cursors_with(|map, _, _| {
 4798                    let row = rows[index];
 4799                    index += 1;
 4800
 4801                    let point = Point::new(row, 0);
 4802                    let boundary = map.next_line_boundary(point).1;
 4803                    let clipped = map.clip_point(boundary, Bias::Left);
 4804
 4805                    (clipped, SelectionGoal::None)
 4806                });
 4807            });
 4808
 4809            let mut indent_edits = Vec::new();
 4810            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4811            for row in rows {
 4812                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4813                for (row, indent) in indents {
 4814                    if indent.len == 0 {
 4815                        continue;
 4816                    }
 4817
 4818                    let text = match indent.kind {
 4819                        IndentKind::Space => " ".repeat(indent.len as usize),
 4820                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4821                    };
 4822                    let point = Point::new(row.0, 0);
 4823                    indent_edits.push((point..point, text));
 4824                }
 4825            }
 4826            editor.edit(indent_edits, cx);
 4827        });
 4828    }
 4829
 4830    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4831        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4832            original_indent_columns: Vec::new(),
 4833        });
 4834        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4835    }
 4836
 4837    fn insert_with_autoindent_mode(
 4838        &mut self,
 4839        text: &str,
 4840        autoindent_mode: Option<AutoindentMode>,
 4841        window: &mut Window,
 4842        cx: &mut Context<Self>,
 4843    ) {
 4844        if self.read_only(cx) {
 4845            return;
 4846        }
 4847
 4848        let text: Arc<str> = text.into();
 4849        self.transact(window, cx, |this, window, cx| {
 4850            let old_selections = this.selections.all_adjusted(cx);
 4851            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4852                let anchors = {
 4853                    let snapshot = buffer.read(cx);
 4854                    old_selections
 4855                        .iter()
 4856                        .map(|s| {
 4857                            let anchor = snapshot.anchor_after(s.head());
 4858                            s.map(|_| anchor)
 4859                        })
 4860                        .collect::<Vec<_>>()
 4861                };
 4862                buffer.edit(
 4863                    old_selections
 4864                        .iter()
 4865                        .map(|s| (s.start..s.end, text.clone())),
 4866                    autoindent_mode,
 4867                    cx,
 4868                );
 4869                anchors
 4870            });
 4871
 4872            this.change_selections(Default::default(), window, cx, |s| {
 4873                s.select_anchors(selection_anchors);
 4874            });
 4875
 4876            cx.notify();
 4877        });
 4878    }
 4879
 4880    fn trigger_completion_on_input(
 4881        &mut self,
 4882        text: &str,
 4883        trigger_in_words: bool,
 4884        window: &mut Window,
 4885        cx: &mut Context<Self>,
 4886    ) {
 4887        let completions_source = self
 4888            .context_menu
 4889            .borrow()
 4890            .as_ref()
 4891            .and_then(|menu| match menu {
 4892                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4893                CodeContextMenu::CodeActions(_) => None,
 4894            });
 4895
 4896        match completions_source {
 4897            Some(CompletionsMenuSource::Words { .. }) => {
 4898                self.open_or_update_completions_menu(
 4899                    Some(CompletionsMenuSource::Words {
 4900                        ignore_threshold: false,
 4901                    }),
 4902                    None,
 4903                    window,
 4904                    cx,
 4905                );
 4906            }
 4907            Some(CompletionsMenuSource::Normal)
 4908            | Some(CompletionsMenuSource::SnippetChoices)
 4909            | None
 4910                if self.is_completion_trigger(
 4911                    text,
 4912                    trigger_in_words,
 4913                    completions_source.is_some(),
 4914                    cx,
 4915                ) =>
 4916            {
 4917                self.show_completions(
 4918                    &ShowCompletions {
 4919                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4920                    },
 4921                    window,
 4922                    cx,
 4923                )
 4924            }
 4925            _ => {
 4926                self.hide_context_menu(window, cx);
 4927            }
 4928        }
 4929    }
 4930
 4931    fn is_completion_trigger(
 4932        &self,
 4933        text: &str,
 4934        trigger_in_words: bool,
 4935        menu_is_open: bool,
 4936        cx: &mut Context<Self>,
 4937    ) -> bool {
 4938        let position = self.selections.newest_anchor().head();
 4939        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4940            return false;
 4941        };
 4942
 4943        if let Some(completion_provider) = &self.completion_provider {
 4944            completion_provider.is_completion_trigger(
 4945                &buffer,
 4946                position.text_anchor,
 4947                text,
 4948                trigger_in_words,
 4949                menu_is_open,
 4950                cx,
 4951            )
 4952        } else {
 4953            false
 4954        }
 4955    }
 4956
 4957    /// If any empty selections is touching the start of its innermost containing autoclose
 4958    /// region, expand it to select the brackets.
 4959    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4960        let selections = self.selections.all::<usize>(cx);
 4961        let buffer = self.buffer.read(cx).read(cx);
 4962        let new_selections = self
 4963            .selections_with_autoclose_regions(selections, &buffer)
 4964            .map(|(mut selection, region)| {
 4965                if !selection.is_empty() {
 4966                    return selection;
 4967                }
 4968
 4969                if let Some(region) = region {
 4970                    let mut range = region.range.to_offset(&buffer);
 4971                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4972                        range.start -= region.pair.start.len();
 4973                        if buffer.contains_str_at(range.start, &region.pair.start)
 4974                            && buffer.contains_str_at(range.end, &region.pair.end)
 4975                        {
 4976                            range.end += region.pair.end.len();
 4977                            selection.start = range.start;
 4978                            selection.end = range.end;
 4979
 4980                            return selection;
 4981                        }
 4982                    }
 4983                }
 4984
 4985                let always_treat_brackets_as_autoclosed = buffer
 4986                    .language_settings_at(selection.start, cx)
 4987                    .always_treat_brackets_as_autoclosed;
 4988
 4989                if !always_treat_brackets_as_autoclosed {
 4990                    return selection;
 4991                }
 4992
 4993                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4994                    for (pair, enabled) in scope.brackets() {
 4995                        if !enabled || !pair.close {
 4996                            continue;
 4997                        }
 4998
 4999                        if buffer.contains_str_at(selection.start, &pair.end) {
 5000                            let pair_start_len = pair.start.len();
 5001                            if buffer.contains_str_at(
 5002                                selection.start.saturating_sub(pair_start_len),
 5003                                &pair.start,
 5004                            ) {
 5005                                selection.start -= pair_start_len;
 5006                                selection.end += pair.end.len();
 5007
 5008                                return selection;
 5009                            }
 5010                        }
 5011                    }
 5012                }
 5013
 5014                selection
 5015            })
 5016            .collect();
 5017
 5018        drop(buffer);
 5019        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5020            selections.select(new_selections)
 5021        });
 5022    }
 5023
 5024    /// Iterate the given selections, and for each one, find the smallest surrounding
 5025    /// autoclose region. This uses the ordering of the selections and the autoclose
 5026    /// regions to avoid repeated comparisons.
 5027    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5028        &'a self,
 5029        selections: impl IntoIterator<Item = Selection<D>>,
 5030        buffer: &'a MultiBufferSnapshot,
 5031    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5032        let mut i = 0;
 5033        let mut regions = self.autoclose_regions.as_slice();
 5034        selections.into_iter().map(move |selection| {
 5035            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5036
 5037            let mut enclosing = None;
 5038            while let Some(pair_state) = regions.get(i) {
 5039                if pair_state.range.end.to_offset(buffer) < range.start {
 5040                    regions = &regions[i + 1..];
 5041                    i = 0;
 5042                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5043                    break;
 5044                } else {
 5045                    if pair_state.selection_id == selection.id {
 5046                        enclosing = Some(pair_state);
 5047                    }
 5048                    i += 1;
 5049                }
 5050            }
 5051
 5052            (selection, enclosing)
 5053        })
 5054    }
 5055
 5056    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5057    fn invalidate_autoclose_regions(
 5058        &mut self,
 5059        mut selections: &[Selection<Anchor>],
 5060        buffer: &MultiBufferSnapshot,
 5061    ) {
 5062        self.autoclose_regions.retain(|state| {
 5063            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5064                return false;
 5065            }
 5066
 5067            let mut i = 0;
 5068            while let Some(selection) = selections.get(i) {
 5069                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5070                    selections = &selections[1..];
 5071                    continue;
 5072                }
 5073                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5074                    break;
 5075                }
 5076                if selection.id == state.selection_id {
 5077                    return true;
 5078                } else {
 5079                    i += 1;
 5080                }
 5081            }
 5082            false
 5083        });
 5084    }
 5085
 5086    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5087        let offset = position.to_offset(buffer);
 5088        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5089        if offset > word_range.start && kind == Some(CharKind::Word) {
 5090            Some(
 5091                buffer
 5092                    .text_for_range(word_range.start..offset)
 5093                    .collect::<String>(),
 5094            )
 5095        } else {
 5096            None
 5097        }
 5098    }
 5099
 5100    pub fn toggle_inline_values(
 5101        &mut self,
 5102        _: &ToggleInlineValues,
 5103        _: &mut Window,
 5104        cx: &mut Context<Self>,
 5105    ) {
 5106        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5107
 5108        self.refresh_inline_values(cx);
 5109    }
 5110
 5111    pub fn toggle_inlay_hints(
 5112        &mut self,
 5113        _: &ToggleInlayHints,
 5114        _: &mut Window,
 5115        cx: &mut Context<Self>,
 5116    ) {
 5117        self.refresh_inlay_hints(
 5118            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5119            cx,
 5120        );
 5121    }
 5122
 5123    pub fn inlay_hints_enabled(&self) -> bool {
 5124        self.inlay_hint_cache.enabled
 5125    }
 5126
 5127    pub fn inline_values_enabled(&self) -> bool {
 5128        self.inline_value_cache.enabled
 5129    }
 5130
 5131    #[cfg(any(test, feature = "test-support"))]
 5132    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5133        self.display_map
 5134            .read(cx)
 5135            .current_inlays()
 5136            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5137            .cloned()
 5138            .collect()
 5139    }
 5140
 5141    #[cfg(any(test, feature = "test-support"))]
 5142    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5143        self.display_map
 5144            .read(cx)
 5145            .current_inlays()
 5146            .cloned()
 5147            .collect()
 5148    }
 5149
 5150    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5151        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5152            return;
 5153        }
 5154
 5155        let reason_description = reason.description();
 5156        let ignore_debounce = matches!(
 5157            reason,
 5158            InlayHintRefreshReason::SettingsChange(_)
 5159                | InlayHintRefreshReason::Toggle(_)
 5160                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5161                | InlayHintRefreshReason::ModifiersChanged(_)
 5162        );
 5163        let (invalidate_cache, required_languages) = match reason {
 5164            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5165                match self.inlay_hint_cache.modifiers_override(enabled) {
 5166                    Some(enabled) => {
 5167                        if enabled {
 5168                            (InvalidationStrategy::RefreshRequested, None)
 5169                        } else {
 5170                            self.splice_inlays(
 5171                                &self
 5172                                    .visible_inlay_hints(cx)
 5173                                    .iter()
 5174                                    .map(|inlay| inlay.id)
 5175                                    .collect::<Vec<InlayId>>(),
 5176                                Vec::new(),
 5177                                cx,
 5178                            );
 5179                            return;
 5180                        }
 5181                    }
 5182                    None => return,
 5183                }
 5184            }
 5185            InlayHintRefreshReason::Toggle(enabled) => {
 5186                if self.inlay_hint_cache.toggle(enabled) {
 5187                    if enabled {
 5188                        (InvalidationStrategy::RefreshRequested, None)
 5189                    } else {
 5190                        self.splice_inlays(
 5191                            &self
 5192                                .visible_inlay_hints(cx)
 5193                                .iter()
 5194                                .map(|inlay| inlay.id)
 5195                                .collect::<Vec<InlayId>>(),
 5196                            Vec::new(),
 5197                            cx,
 5198                        );
 5199                        return;
 5200                    }
 5201                } else {
 5202                    return;
 5203                }
 5204            }
 5205            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5206                match self.inlay_hint_cache.update_settings(
 5207                    &self.buffer,
 5208                    new_settings,
 5209                    self.visible_inlay_hints(cx),
 5210                    cx,
 5211                ) {
 5212                    ControlFlow::Break(Some(InlaySplice {
 5213                        to_remove,
 5214                        to_insert,
 5215                    })) => {
 5216                        self.splice_inlays(&to_remove, to_insert, cx);
 5217                        return;
 5218                    }
 5219                    ControlFlow::Break(None) => return,
 5220                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5221                }
 5222            }
 5223            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5224                if let Some(InlaySplice {
 5225                    to_remove,
 5226                    to_insert,
 5227                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5228                {
 5229                    self.splice_inlays(&to_remove, to_insert, cx);
 5230                }
 5231                self.display_map.update(cx, |display_map, _| {
 5232                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5233                });
 5234                return;
 5235            }
 5236            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5237            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5238                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5239            }
 5240            InlayHintRefreshReason::RefreshRequested => {
 5241                (InvalidationStrategy::RefreshRequested, None)
 5242            }
 5243        };
 5244
 5245        if let Some(InlaySplice {
 5246            to_remove,
 5247            to_insert,
 5248        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5249            reason_description,
 5250            self.visible_excerpts(required_languages.as_ref(), cx),
 5251            invalidate_cache,
 5252            ignore_debounce,
 5253            cx,
 5254        ) {
 5255            self.splice_inlays(&to_remove, to_insert, cx);
 5256        }
 5257    }
 5258
 5259    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5260        self.display_map
 5261            .read(cx)
 5262            .current_inlays()
 5263            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5264            .cloned()
 5265            .collect()
 5266    }
 5267
 5268    pub fn visible_excerpts(
 5269        &self,
 5270        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5271        cx: &mut Context<Editor>,
 5272    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5273        let Some(project) = self.project() else {
 5274            return HashMap::default();
 5275        };
 5276        let project = project.read(cx);
 5277        let multi_buffer = self.buffer().read(cx);
 5278        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5279        let multi_buffer_visible_start = self
 5280            .scroll_manager
 5281            .anchor()
 5282            .anchor
 5283            .to_point(&multi_buffer_snapshot);
 5284        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5285            multi_buffer_visible_start
 5286                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5287            Bias::Left,
 5288        );
 5289        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5290        multi_buffer_snapshot
 5291            .range_to_buffer_ranges(multi_buffer_visible_range)
 5292            .into_iter()
 5293            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5294            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5295                let buffer_file = project::File::from_dyn(buffer.file())?;
 5296                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5297                let worktree_entry = buffer_worktree
 5298                    .read(cx)
 5299                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5300                if worktree_entry.is_ignored {
 5301                    return None;
 5302                }
 5303
 5304                let language = buffer.language()?;
 5305                if let Some(restrict_to_languages) = restrict_to_languages
 5306                    && !restrict_to_languages.contains(language)
 5307                {
 5308                    return None;
 5309                }
 5310                Some((
 5311                    excerpt_id,
 5312                    (
 5313                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5314                        buffer.version().clone(),
 5315                        excerpt_visible_range,
 5316                    ),
 5317                ))
 5318            })
 5319            .collect()
 5320    }
 5321
 5322    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5323        TextLayoutDetails {
 5324            text_system: window.text_system().clone(),
 5325            editor_style: self.style.clone().unwrap(),
 5326            rem_size: window.rem_size(),
 5327            scroll_anchor: self.scroll_manager.anchor(),
 5328            visible_rows: self.visible_line_count(),
 5329            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5330        }
 5331    }
 5332
 5333    pub fn splice_inlays(
 5334        &self,
 5335        to_remove: &[InlayId],
 5336        to_insert: Vec<Inlay>,
 5337        cx: &mut Context<Self>,
 5338    ) {
 5339        self.display_map.update(cx, |display_map, cx| {
 5340            display_map.splice_inlays(to_remove, to_insert, cx)
 5341        });
 5342        cx.notify();
 5343    }
 5344
 5345    fn trigger_on_type_formatting(
 5346        &self,
 5347        input: String,
 5348        window: &mut Window,
 5349        cx: &mut Context<Self>,
 5350    ) -> Option<Task<Result<()>>> {
 5351        if input.len() != 1 {
 5352            return None;
 5353        }
 5354
 5355        let project = self.project()?;
 5356        let position = self.selections.newest_anchor().head();
 5357        let (buffer, buffer_position) = self
 5358            .buffer
 5359            .read(cx)
 5360            .text_anchor_for_position(position, cx)?;
 5361
 5362        let settings = language_settings::language_settings(
 5363            buffer
 5364                .read(cx)
 5365                .language_at(buffer_position)
 5366                .map(|l| l.name()),
 5367            buffer.read(cx).file(),
 5368            cx,
 5369        );
 5370        if !settings.use_on_type_format {
 5371            return None;
 5372        }
 5373
 5374        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5375        // hence we do LSP request & edit on host side only — add formats to host's history.
 5376        let push_to_lsp_host_history = true;
 5377        // If this is not the host, append its history with new edits.
 5378        let push_to_client_history = project.read(cx).is_via_collab();
 5379
 5380        let on_type_formatting = project.update(cx, |project, cx| {
 5381            project.on_type_format(
 5382                buffer.clone(),
 5383                buffer_position,
 5384                input,
 5385                push_to_lsp_host_history,
 5386                cx,
 5387            )
 5388        });
 5389        Some(cx.spawn_in(window, async move |editor, cx| {
 5390            if let Some(transaction) = on_type_formatting.await? {
 5391                if push_to_client_history {
 5392                    buffer
 5393                        .update(cx, |buffer, _| {
 5394                            buffer.push_transaction(transaction, Instant::now());
 5395                            buffer.finalize_last_transaction();
 5396                        })
 5397                        .ok();
 5398                }
 5399                editor.update(cx, |editor, cx| {
 5400                    editor.refresh_document_highlights(cx);
 5401                })?;
 5402            }
 5403            Ok(())
 5404        }))
 5405    }
 5406
 5407    pub fn show_word_completions(
 5408        &mut self,
 5409        _: &ShowWordCompletions,
 5410        window: &mut Window,
 5411        cx: &mut Context<Self>,
 5412    ) {
 5413        self.open_or_update_completions_menu(
 5414            Some(CompletionsMenuSource::Words {
 5415                ignore_threshold: true,
 5416            }),
 5417            None,
 5418            window,
 5419            cx,
 5420        );
 5421    }
 5422
 5423    pub fn show_completions(
 5424        &mut self,
 5425        options: &ShowCompletions,
 5426        window: &mut Window,
 5427        cx: &mut Context<Self>,
 5428    ) {
 5429        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5430    }
 5431
 5432    fn open_or_update_completions_menu(
 5433        &mut self,
 5434        requested_source: Option<CompletionsMenuSource>,
 5435        trigger: Option<&str>,
 5436        window: &mut Window,
 5437        cx: &mut Context<Self>,
 5438    ) {
 5439        if self.pending_rename.is_some() {
 5440            return;
 5441        }
 5442
 5443        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5444
 5445        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5446        // inserted and selected. To handle that case, the start of the selection is used so that
 5447        // the menu starts with all choices.
 5448        let position = self
 5449            .selections
 5450            .newest_anchor()
 5451            .start
 5452            .bias_right(&multibuffer_snapshot);
 5453        if position.diff_base_anchor.is_some() {
 5454            return;
 5455        }
 5456        let (buffer, buffer_position) =
 5457            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5458                output
 5459            } else {
 5460                return;
 5461            };
 5462        let buffer_snapshot = buffer.read(cx).snapshot();
 5463
 5464        let query: Option<Arc<String>> =
 5465            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5466
 5467        drop(multibuffer_snapshot);
 5468
 5469        let mut ignore_word_threshold = false;
 5470        let provider = match requested_source {
 5471            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5472            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5473                ignore_word_threshold = ignore_threshold;
 5474                None
 5475            }
 5476            Some(CompletionsMenuSource::SnippetChoices) => {
 5477                log::error!("bug: SnippetChoices requested_source is not handled");
 5478                None
 5479            }
 5480        };
 5481
 5482        let sort_completions = provider
 5483            .as_ref()
 5484            .is_some_and(|provider| provider.sort_completions());
 5485
 5486        let filter_completions = provider
 5487            .as_ref()
 5488            .is_none_or(|provider| provider.filter_completions());
 5489
 5490        let trigger_kind = match trigger {
 5491            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5492                CompletionTriggerKind::TRIGGER_CHARACTER
 5493            }
 5494            _ => CompletionTriggerKind::INVOKED,
 5495        };
 5496        let completion_context = CompletionContext {
 5497            trigger_character: trigger.and_then(|trigger| {
 5498                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5499                    Some(String::from(trigger))
 5500                } else {
 5501                    None
 5502                }
 5503            }),
 5504            trigger_kind,
 5505        };
 5506
 5507        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5508        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5509        // involve trigger chars, so this is skipped in that case.
 5510        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5511        {
 5512            let menu_is_open = matches!(
 5513                self.context_menu.borrow().as_ref(),
 5514                Some(CodeContextMenu::Completions(_))
 5515            );
 5516            if menu_is_open {
 5517                self.hide_context_menu(window, cx);
 5518            }
 5519        }
 5520
 5521        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5522            if filter_completions {
 5523                menu.filter(query.clone(), provider.clone(), window, cx);
 5524            }
 5525            // When `is_incomplete` is false, no need to re-query completions when the current query
 5526            // is a suffix of the initial query.
 5527            if !menu.is_incomplete {
 5528                // If the new query is a suffix of the old query (typing more characters) and
 5529                // the previous result was complete, the existing completions can be filtered.
 5530                //
 5531                // Note that this is always true for snippet completions.
 5532                let query_matches = match (&menu.initial_query, &query) {
 5533                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5534                    (None, _) => true,
 5535                    _ => false,
 5536                };
 5537                if query_matches {
 5538                    let position_matches = if menu.initial_position == position {
 5539                        true
 5540                    } else {
 5541                        let snapshot = self.buffer.read(cx).read(cx);
 5542                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5543                    };
 5544                    if position_matches {
 5545                        return;
 5546                    }
 5547                }
 5548            }
 5549        };
 5550
 5551        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5552            buffer_snapshot.surrounding_word(buffer_position, false)
 5553        {
 5554            let word_to_exclude = buffer_snapshot
 5555                .text_for_range(word_range.clone())
 5556                .collect::<String>();
 5557            (
 5558                buffer_snapshot.anchor_before(word_range.start)
 5559                    ..buffer_snapshot.anchor_after(buffer_position),
 5560                Some(word_to_exclude),
 5561            )
 5562        } else {
 5563            (buffer_position..buffer_position, None)
 5564        };
 5565
 5566        let language = buffer_snapshot
 5567            .language_at(buffer_position)
 5568            .map(|language| language.name());
 5569
 5570        let completion_settings =
 5571            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5572
 5573        let show_completion_documentation = buffer_snapshot
 5574            .settings_at(buffer_position, cx)
 5575            .show_completion_documentation;
 5576
 5577        // The document can be large, so stay in reasonable bounds when searching for words,
 5578        // otherwise completion pop-up might be slow to appear.
 5579        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5580        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5581        let min_word_search = buffer_snapshot.clip_point(
 5582            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5583            Bias::Left,
 5584        );
 5585        let max_word_search = buffer_snapshot.clip_point(
 5586            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5587            Bias::Right,
 5588        );
 5589        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5590            ..buffer_snapshot.point_to_offset(max_word_search);
 5591
 5592        let skip_digits = query
 5593            .as_ref()
 5594            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5595
 5596        let omit_word_completions = !self.word_completions_enabled
 5597            || (!ignore_word_threshold
 5598                && match &query {
 5599                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5600                    None => completion_settings.words_min_length != 0,
 5601                });
 5602
 5603        let (mut words, provider_responses) = match &provider {
 5604            Some(provider) => {
 5605                let provider_responses = provider.completions(
 5606                    position.excerpt_id,
 5607                    &buffer,
 5608                    buffer_position,
 5609                    completion_context,
 5610                    window,
 5611                    cx,
 5612                );
 5613
 5614                let words = match (omit_word_completions, completion_settings.words) {
 5615                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5616                        Task::ready(BTreeMap::default())
 5617                    }
 5618                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5619                        .background_spawn(async move {
 5620                            buffer_snapshot.words_in_range(WordsQuery {
 5621                                fuzzy_contents: None,
 5622                                range: word_search_range,
 5623                                skip_digits,
 5624                            })
 5625                        }),
 5626                };
 5627
 5628                (words, provider_responses)
 5629            }
 5630            None => {
 5631                let words = if omit_word_completions {
 5632                    Task::ready(BTreeMap::default())
 5633                } else {
 5634                    cx.background_spawn(async move {
 5635                        buffer_snapshot.words_in_range(WordsQuery {
 5636                            fuzzy_contents: None,
 5637                            range: word_search_range,
 5638                            skip_digits,
 5639                        })
 5640                    })
 5641                };
 5642                (words, Task::ready(Ok(Vec::new())))
 5643            }
 5644        };
 5645
 5646        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5647
 5648        let id = post_inc(&mut self.next_completion_id);
 5649        let task = cx.spawn_in(window, async move |editor, cx| {
 5650            let Ok(()) = editor.update(cx, |this, _| {
 5651                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5652            }) else {
 5653                return;
 5654            };
 5655
 5656            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5657            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5658            let mut completions = Vec::new();
 5659            let mut is_incomplete = false;
 5660            let mut display_options: Option<CompletionDisplayOptions> = None;
 5661            if let Some(provider_responses) = provider_responses.await.log_err()
 5662                && !provider_responses.is_empty()
 5663            {
 5664                for response in provider_responses {
 5665                    completions.extend(response.completions);
 5666                    is_incomplete = is_incomplete || response.is_incomplete;
 5667                    match display_options.as_mut() {
 5668                        None => {
 5669                            display_options = Some(response.display_options);
 5670                        }
 5671                        Some(options) => options.merge(&response.display_options),
 5672                    }
 5673                }
 5674                if completion_settings.words == WordsCompletionMode::Fallback {
 5675                    words = Task::ready(BTreeMap::default());
 5676                }
 5677            }
 5678            let display_options = display_options.unwrap_or_default();
 5679
 5680            let mut words = words.await;
 5681            if let Some(word_to_exclude) = &word_to_exclude {
 5682                words.remove(word_to_exclude);
 5683            }
 5684            for lsp_completion in &completions {
 5685                words.remove(&lsp_completion.new_text);
 5686            }
 5687            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5688                replace_range: word_replace_range.clone(),
 5689                new_text: word.clone(),
 5690                label: CodeLabel::plain(word, None),
 5691                icon_path: None,
 5692                documentation: None,
 5693                source: CompletionSource::BufferWord {
 5694                    word_range,
 5695                    resolved: false,
 5696                },
 5697                insert_text_mode: Some(InsertTextMode::AS_IS),
 5698                confirm: None,
 5699            }));
 5700
 5701            let menu = if completions.is_empty() {
 5702                None
 5703            } else {
 5704                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5705                    let languages = editor
 5706                        .workspace
 5707                        .as_ref()
 5708                        .and_then(|(workspace, _)| workspace.upgrade())
 5709                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5710                    let menu = CompletionsMenu::new(
 5711                        id,
 5712                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5713                        sort_completions,
 5714                        show_completion_documentation,
 5715                        position,
 5716                        query.clone(),
 5717                        is_incomplete,
 5718                        buffer.clone(),
 5719                        completions.into(),
 5720                        display_options,
 5721                        snippet_sort_order,
 5722                        languages,
 5723                        language,
 5724                        cx,
 5725                    );
 5726
 5727                    let query = if filter_completions { query } else { None };
 5728                    let matches_task = if let Some(query) = query {
 5729                        menu.do_async_filtering(query, cx)
 5730                    } else {
 5731                        Task::ready(menu.unfiltered_matches())
 5732                    };
 5733                    (menu, matches_task)
 5734                }) else {
 5735                    return;
 5736                };
 5737
 5738                let matches = matches_task.await;
 5739
 5740                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5741                    // Newer menu already set, so exit.
 5742                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5743                        editor.context_menu.borrow().as_ref()
 5744                        && prev_menu.id > id
 5745                    {
 5746                        return;
 5747                    };
 5748
 5749                    // Only valid to take prev_menu because it the new menu is immediately set
 5750                    // below, or the menu is hidden.
 5751                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5752                        editor.context_menu.borrow_mut().take()
 5753                    {
 5754                        let position_matches =
 5755                            if prev_menu.initial_position == menu.initial_position {
 5756                                true
 5757                            } else {
 5758                                let snapshot = editor.buffer.read(cx).read(cx);
 5759                                prev_menu.initial_position.to_offset(&snapshot)
 5760                                    == menu.initial_position.to_offset(&snapshot)
 5761                            };
 5762                        if position_matches {
 5763                            // Preserve markdown cache before `set_filter_results` because it will
 5764                            // try to populate the documentation cache.
 5765                            menu.preserve_markdown_cache(prev_menu);
 5766                        }
 5767                    };
 5768
 5769                    menu.set_filter_results(matches, provider, window, cx);
 5770                }) else {
 5771                    return;
 5772                };
 5773
 5774                menu.visible().then_some(menu)
 5775            };
 5776
 5777            editor
 5778                .update_in(cx, |editor, window, cx| {
 5779                    if editor.focus_handle.is_focused(window)
 5780                        && let Some(menu) = menu
 5781                    {
 5782                        *editor.context_menu.borrow_mut() =
 5783                            Some(CodeContextMenu::Completions(menu));
 5784
 5785                        crate::hover_popover::hide_hover(editor, cx);
 5786                        if editor.show_edit_predictions_in_menu() {
 5787                            editor.update_visible_edit_prediction(window, cx);
 5788                        } else {
 5789                            editor.discard_edit_prediction(false, cx);
 5790                        }
 5791
 5792                        cx.notify();
 5793                        return;
 5794                    }
 5795
 5796                    if editor.completion_tasks.len() <= 1 {
 5797                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5798                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5799                        // If it was already hidden and we don't show edit predictions in the menu,
 5800                        // we should also show the edit prediction when available.
 5801                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5802                            editor.update_visible_edit_prediction(window, cx);
 5803                        }
 5804                    }
 5805                })
 5806                .ok();
 5807        });
 5808
 5809        self.completion_tasks.push((id, task));
 5810    }
 5811
 5812    #[cfg(feature = "test-support")]
 5813    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5814        let menu = self.context_menu.borrow();
 5815        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5816            let completions = menu.completions.borrow();
 5817            Some(completions.to_vec())
 5818        } else {
 5819            None
 5820        }
 5821    }
 5822
 5823    pub fn with_completions_menu_matching_id<R>(
 5824        &self,
 5825        id: CompletionId,
 5826        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5827    ) -> R {
 5828        let mut context_menu = self.context_menu.borrow_mut();
 5829        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5830            return f(None);
 5831        };
 5832        if completions_menu.id != id {
 5833            return f(None);
 5834        }
 5835        f(Some(completions_menu))
 5836    }
 5837
 5838    pub fn confirm_completion(
 5839        &mut self,
 5840        action: &ConfirmCompletion,
 5841        window: &mut Window,
 5842        cx: &mut Context<Self>,
 5843    ) -> Option<Task<Result<()>>> {
 5844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5845        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5846    }
 5847
 5848    pub fn confirm_completion_insert(
 5849        &mut self,
 5850        _: &ConfirmCompletionInsert,
 5851        window: &mut Window,
 5852        cx: &mut Context<Self>,
 5853    ) -> Option<Task<Result<()>>> {
 5854        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5855        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5856    }
 5857
 5858    pub fn confirm_completion_replace(
 5859        &mut self,
 5860        _: &ConfirmCompletionReplace,
 5861        window: &mut Window,
 5862        cx: &mut Context<Self>,
 5863    ) -> Option<Task<Result<()>>> {
 5864        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5865        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5866    }
 5867
 5868    pub fn compose_completion(
 5869        &mut self,
 5870        action: &ComposeCompletion,
 5871        window: &mut Window,
 5872        cx: &mut Context<Self>,
 5873    ) -> Option<Task<Result<()>>> {
 5874        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5875        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5876    }
 5877
 5878    fn do_completion(
 5879        &mut self,
 5880        item_ix: Option<usize>,
 5881        intent: CompletionIntent,
 5882        window: &mut Window,
 5883        cx: &mut Context<Editor>,
 5884    ) -> Option<Task<Result<()>>> {
 5885        use language::ToOffset as _;
 5886
 5887        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5888        else {
 5889            return None;
 5890        };
 5891
 5892        let candidate_id = {
 5893            let entries = completions_menu.entries.borrow();
 5894            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5895            if self.show_edit_predictions_in_menu() {
 5896                self.discard_edit_prediction(true, cx);
 5897            }
 5898            mat.candidate_id
 5899        };
 5900
 5901        let completion = completions_menu
 5902            .completions
 5903            .borrow()
 5904            .get(candidate_id)?
 5905            .clone();
 5906        cx.stop_propagation();
 5907
 5908        let buffer_handle = completions_menu.buffer.clone();
 5909
 5910        let CompletionEdit {
 5911            new_text,
 5912            snippet,
 5913            replace_range,
 5914        } = process_completion_for_edit(
 5915            &completion,
 5916            intent,
 5917            &buffer_handle,
 5918            &completions_menu.initial_position.text_anchor,
 5919            cx,
 5920        );
 5921
 5922        let buffer = buffer_handle.read(cx);
 5923        let snapshot = self.buffer.read(cx).snapshot(cx);
 5924        let newest_anchor = self.selections.newest_anchor();
 5925        let replace_range_multibuffer = {
 5926            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5927            let multibuffer_anchor = snapshot
 5928                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5929                .unwrap()
 5930                ..snapshot
 5931                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5932                    .unwrap();
 5933            multibuffer_anchor.start.to_offset(&snapshot)
 5934                ..multibuffer_anchor.end.to_offset(&snapshot)
 5935        };
 5936        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5937            return None;
 5938        }
 5939
 5940        let old_text = buffer
 5941            .text_for_range(replace_range.clone())
 5942            .collect::<String>();
 5943        let lookbehind = newest_anchor
 5944            .start
 5945            .text_anchor
 5946            .to_offset(buffer)
 5947            .saturating_sub(replace_range.start);
 5948        let lookahead = replace_range
 5949            .end
 5950            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5951        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5952        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5953
 5954        let selections = self.selections.all::<usize>(cx);
 5955        let mut ranges = Vec::new();
 5956        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5957
 5958        for selection in &selections {
 5959            let range = if selection.id == newest_anchor.id {
 5960                replace_range_multibuffer.clone()
 5961            } else {
 5962                let mut range = selection.range();
 5963
 5964                // if prefix is present, don't duplicate it
 5965                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5966                    range.start = range.start.saturating_sub(lookbehind);
 5967
 5968                    // if suffix is also present, mimic the newest cursor and replace it
 5969                    if selection.id != newest_anchor.id
 5970                        && snapshot.contains_str_at(range.end, suffix)
 5971                    {
 5972                        range.end += lookahead;
 5973                    }
 5974                }
 5975                range
 5976            };
 5977
 5978            ranges.push(range.clone());
 5979
 5980            if !self.linked_edit_ranges.is_empty() {
 5981                let start_anchor = snapshot.anchor_before(range.start);
 5982                let end_anchor = snapshot.anchor_after(range.end);
 5983                if let Some(ranges) = self
 5984                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5985                {
 5986                    for (buffer, edits) in ranges {
 5987                        linked_edits
 5988                            .entry(buffer.clone())
 5989                            .or_default()
 5990                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5991                    }
 5992                }
 5993            }
 5994        }
 5995
 5996        let common_prefix_len = old_text
 5997            .chars()
 5998            .zip(new_text.chars())
 5999            .take_while(|(a, b)| a == b)
 6000            .map(|(a, _)| a.len_utf8())
 6001            .sum::<usize>();
 6002
 6003        cx.emit(EditorEvent::InputHandled {
 6004            utf16_range_to_replace: None,
 6005            text: new_text[common_prefix_len..].into(),
 6006        });
 6007
 6008        self.transact(window, cx, |editor, window, cx| {
 6009            if let Some(mut snippet) = snippet {
 6010                snippet.text = new_text.to_string();
 6011                editor
 6012                    .insert_snippet(&ranges, snippet, window, cx)
 6013                    .log_err();
 6014            } else {
 6015                editor.buffer.update(cx, |multi_buffer, cx| {
 6016                    let auto_indent = match completion.insert_text_mode {
 6017                        Some(InsertTextMode::AS_IS) => None,
 6018                        _ => editor.autoindent_mode.clone(),
 6019                    };
 6020                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6021                    multi_buffer.edit(edits, auto_indent, cx);
 6022                });
 6023            }
 6024            for (buffer, edits) in linked_edits {
 6025                buffer.update(cx, |buffer, cx| {
 6026                    let snapshot = buffer.snapshot();
 6027                    let edits = edits
 6028                        .into_iter()
 6029                        .map(|(range, text)| {
 6030                            use text::ToPoint as TP;
 6031                            let end_point = TP::to_point(&range.end, &snapshot);
 6032                            let start_point = TP::to_point(&range.start, &snapshot);
 6033                            (start_point..end_point, text)
 6034                        })
 6035                        .sorted_by_key(|(range, _)| range.start);
 6036                    buffer.edit(edits, None, cx);
 6037                })
 6038            }
 6039
 6040            editor.refresh_edit_prediction(true, false, window, cx);
 6041        });
 6042        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 6043
 6044        let show_new_completions_on_confirm = completion
 6045            .confirm
 6046            .as_ref()
 6047            .is_some_and(|confirm| confirm(intent, window, cx));
 6048        if show_new_completions_on_confirm {
 6049            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6050        }
 6051
 6052        let provider = self.completion_provider.as_ref()?;
 6053        drop(completion);
 6054        let apply_edits = provider.apply_additional_edits_for_completion(
 6055            buffer_handle,
 6056            completions_menu.completions.clone(),
 6057            candidate_id,
 6058            true,
 6059            cx,
 6060        );
 6061
 6062        let editor_settings = EditorSettings::get_global(cx);
 6063        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6064            // After the code completion is finished, users often want to know what signatures are needed.
 6065            // so we should automatically call signature_help
 6066            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6067        }
 6068
 6069        Some(cx.foreground_executor().spawn(async move {
 6070            apply_edits.await?;
 6071            Ok(())
 6072        }))
 6073    }
 6074
 6075    pub fn toggle_code_actions(
 6076        &mut self,
 6077        action: &ToggleCodeActions,
 6078        window: &mut Window,
 6079        cx: &mut Context<Self>,
 6080    ) {
 6081        let quick_launch = action.quick_launch;
 6082        let mut context_menu = self.context_menu.borrow_mut();
 6083        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6084            if code_actions.deployed_from == action.deployed_from {
 6085                // Toggle if we're selecting the same one
 6086                *context_menu = None;
 6087                cx.notify();
 6088                return;
 6089            } else {
 6090                // Otherwise, clear it and start a new one
 6091                *context_menu = None;
 6092                cx.notify();
 6093            }
 6094        }
 6095        drop(context_menu);
 6096        let snapshot = self.snapshot(window, cx);
 6097        let deployed_from = action.deployed_from.clone();
 6098        let action = action.clone();
 6099        self.completion_tasks.clear();
 6100        self.discard_edit_prediction(false, cx);
 6101
 6102        let multibuffer_point = match &action.deployed_from {
 6103            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6104                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6105            }
 6106            _ => self.selections.newest::<Point>(cx).head(),
 6107        };
 6108        let Some((buffer, buffer_row)) = snapshot
 6109            .buffer_snapshot
 6110            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6111            .and_then(|(buffer_snapshot, range)| {
 6112                self.buffer()
 6113                    .read(cx)
 6114                    .buffer(buffer_snapshot.remote_id())
 6115                    .map(|buffer| (buffer, range.start.row))
 6116            })
 6117        else {
 6118            return;
 6119        };
 6120        let buffer_id = buffer.read(cx).remote_id();
 6121        let tasks = self
 6122            .tasks
 6123            .get(&(buffer_id, buffer_row))
 6124            .map(|t| Arc::new(t.to_owned()));
 6125
 6126        if !self.focus_handle.is_focused(window) {
 6127            return;
 6128        }
 6129        let project = self.project.clone();
 6130
 6131        let code_actions_task = match deployed_from {
 6132            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6133            _ => self.code_actions(buffer_row, window, cx),
 6134        };
 6135
 6136        let runnable_task = match deployed_from {
 6137            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6138            _ => {
 6139                let mut task_context_task = Task::ready(None);
 6140                if let Some(tasks) = &tasks
 6141                    && let Some(project) = project
 6142                {
 6143                    task_context_task =
 6144                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6145                }
 6146
 6147                cx.spawn_in(window, {
 6148                    let buffer = buffer.clone();
 6149                    async move |editor, cx| {
 6150                        let task_context = task_context_task.await;
 6151
 6152                        let resolved_tasks =
 6153                            tasks
 6154                                .zip(task_context.clone())
 6155                                .map(|(tasks, task_context)| ResolvedTasks {
 6156                                    templates: tasks.resolve(&task_context).collect(),
 6157                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6158                                        multibuffer_point.row,
 6159                                        tasks.column,
 6160                                    )),
 6161                                });
 6162                        let debug_scenarios = editor
 6163                            .update(cx, |editor, cx| {
 6164                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6165                            })?
 6166                            .await;
 6167                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6168                    }
 6169                })
 6170            }
 6171        };
 6172
 6173        cx.spawn_in(window, async move |editor, cx| {
 6174            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6175            let code_actions = code_actions_task.await;
 6176            let spawn_straight_away = quick_launch
 6177                && resolved_tasks
 6178                    .as_ref()
 6179                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6180                && code_actions
 6181                    .as_ref()
 6182                    .is_none_or(|actions| actions.is_empty())
 6183                && debug_scenarios.is_empty();
 6184
 6185            editor.update_in(cx, |editor, window, cx| {
 6186                crate::hover_popover::hide_hover(editor, cx);
 6187                let actions = CodeActionContents::new(
 6188                    resolved_tasks,
 6189                    code_actions,
 6190                    debug_scenarios,
 6191                    task_context.unwrap_or_default(),
 6192                );
 6193
 6194                // Don't show the menu if there are no actions available
 6195                if actions.is_empty() {
 6196                    cx.notify();
 6197                    return Task::ready(Ok(()));
 6198                }
 6199
 6200                *editor.context_menu.borrow_mut() =
 6201                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6202                        buffer,
 6203                        actions,
 6204                        selected_item: Default::default(),
 6205                        scroll_handle: UniformListScrollHandle::default(),
 6206                        deployed_from,
 6207                    }));
 6208                cx.notify();
 6209                if spawn_straight_away
 6210                    && let Some(task) = editor.confirm_code_action(
 6211                        &ConfirmCodeAction { item_ix: Some(0) },
 6212                        window,
 6213                        cx,
 6214                    )
 6215                {
 6216                    return task;
 6217                }
 6218
 6219                Task::ready(Ok(()))
 6220            })
 6221        })
 6222        .detach_and_log_err(cx);
 6223    }
 6224
 6225    fn debug_scenarios(
 6226        &mut self,
 6227        resolved_tasks: &Option<ResolvedTasks>,
 6228        buffer: &Entity<Buffer>,
 6229        cx: &mut App,
 6230    ) -> Task<Vec<task::DebugScenario>> {
 6231        maybe!({
 6232            let project = self.project()?;
 6233            let dap_store = project.read(cx).dap_store();
 6234            let mut scenarios = vec![];
 6235            let resolved_tasks = resolved_tasks.as_ref()?;
 6236            let buffer = buffer.read(cx);
 6237            let language = buffer.language()?;
 6238            let file = buffer.file();
 6239            let debug_adapter = language_settings(language.name().into(), file, cx)
 6240                .debuggers
 6241                .first()
 6242                .map(SharedString::from)
 6243                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6244
 6245            dap_store.update(cx, |dap_store, cx| {
 6246                for (_, task) in &resolved_tasks.templates {
 6247                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6248                        task.original_task().clone(),
 6249                        debug_adapter.clone().into(),
 6250                        task.display_label().to_owned().into(),
 6251                        cx,
 6252                    );
 6253                    scenarios.push(maybe_scenario);
 6254                }
 6255            });
 6256            Some(cx.background_spawn(async move {
 6257                futures::future::join_all(scenarios)
 6258                    .await
 6259                    .into_iter()
 6260                    .flatten()
 6261                    .collect::<Vec<_>>()
 6262            }))
 6263        })
 6264        .unwrap_or_else(|| Task::ready(vec![]))
 6265    }
 6266
 6267    fn code_actions(
 6268        &mut self,
 6269        buffer_row: u32,
 6270        window: &mut Window,
 6271        cx: &mut Context<Self>,
 6272    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6273        let mut task = self.code_actions_task.take();
 6274        cx.spawn_in(window, async move |editor, cx| {
 6275            while let Some(prev_task) = task {
 6276                prev_task.await.log_err();
 6277                task = editor
 6278                    .update(cx, |this, _| this.code_actions_task.take())
 6279                    .ok()?;
 6280            }
 6281
 6282            editor
 6283                .update(cx, |editor, cx| {
 6284                    editor
 6285                        .available_code_actions
 6286                        .clone()
 6287                        .and_then(|(location, code_actions)| {
 6288                            let snapshot = location.buffer.read(cx).snapshot();
 6289                            let point_range = location.range.to_point(&snapshot);
 6290                            let point_range = point_range.start.row..=point_range.end.row;
 6291                            if point_range.contains(&buffer_row) {
 6292                                Some(code_actions)
 6293                            } else {
 6294                                None
 6295                            }
 6296                        })
 6297                })
 6298                .ok()
 6299                .flatten()
 6300        })
 6301    }
 6302
 6303    pub fn confirm_code_action(
 6304        &mut self,
 6305        action: &ConfirmCodeAction,
 6306        window: &mut Window,
 6307        cx: &mut Context<Self>,
 6308    ) -> Option<Task<Result<()>>> {
 6309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6310
 6311        let actions_menu =
 6312            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6313                menu
 6314            } else {
 6315                return None;
 6316            };
 6317
 6318        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6319        let action = actions_menu.actions.get(action_ix)?;
 6320        let title = action.label();
 6321        let buffer = actions_menu.buffer;
 6322        let workspace = self.workspace()?;
 6323
 6324        match action {
 6325            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6326                workspace.update(cx, |workspace, cx| {
 6327                    workspace.schedule_resolved_task(
 6328                        task_source_kind,
 6329                        resolved_task,
 6330                        false,
 6331                        window,
 6332                        cx,
 6333                    );
 6334
 6335                    Some(Task::ready(Ok(())))
 6336                })
 6337            }
 6338            CodeActionsItem::CodeAction {
 6339                excerpt_id,
 6340                action,
 6341                provider,
 6342            } => {
 6343                let apply_code_action =
 6344                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6345                let workspace = workspace.downgrade();
 6346                Some(cx.spawn_in(window, async move |editor, cx| {
 6347                    let project_transaction = apply_code_action.await?;
 6348                    Self::open_project_transaction(
 6349                        &editor,
 6350                        workspace,
 6351                        project_transaction,
 6352                        title,
 6353                        cx,
 6354                    )
 6355                    .await
 6356                }))
 6357            }
 6358            CodeActionsItem::DebugScenario(scenario) => {
 6359                let context = actions_menu.actions.context;
 6360
 6361                workspace.update(cx, |workspace, cx| {
 6362                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6363                    workspace.start_debug_session(
 6364                        scenario,
 6365                        context,
 6366                        Some(buffer),
 6367                        None,
 6368                        window,
 6369                        cx,
 6370                    );
 6371                });
 6372                Some(Task::ready(Ok(())))
 6373            }
 6374        }
 6375    }
 6376
 6377    pub async fn open_project_transaction(
 6378        editor: &WeakEntity<Editor>,
 6379        workspace: WeakEntity<Workspace>,
 6380        transaction: ProjectTransaction,
 6381        title: String,
 6382        cx: &mut AsyncWindowContext,
 6383    ) -> Result<()> {
 6384        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6385        cx.update(|_, cx| {
 6386            entries.sort_unstable_by_key(|(buffer, _)| {
 6387                buffer.read(cx).file().map(|f| f.path().clone())
 6388            });
 6389        })?;
 6390
 6391        // If the project transaction's edits are all contained within this editor, then
 6392        // avoid opening a new editor to display them.
 6393
 6394        if let Some((buffer, transaction)) = entries.first() {
 6395            if entries.len() == 1 {
 6396                let excerpt = editor.update(cx, |editor, cx| {
 6397                    editor
 6398                        .buffer()
 6399                        .read(cx)
 6400                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6401                })?;
 6402                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6403                    && excerpted_buffer == *buffer
 6404                {
 6405                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6406                        let excerpt_range = excerpt_range.to_offset(buffer);
 6407                        buffer
 6408                            .edited_ranges_for_transaction::<usize>(transaction)
 6409                            .all(|range| {
 6410                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6411                            })
 6412                    })?;
 6413
 6414                    if all_edits_within_excerpt {
 6415                        return Ok(());
 6416                    }
 6417                }
 6418            }
 6419        } else {
 6420            return Ok(());
 6421        }
 6422
 6423        let mut ranges_to_highlight = Vec::new();
 6424        let excerpt_buffer = cx.new(|cx| {
 6425            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6426            for (buffer_handle, transaction) in &entries {
 6427                let edited_ranges = buffer_handle
 6428                    .read(cx)
 6429                    .edited_ranges_for_transaction::<Point>(transaction)
 6430                    .collect::<Vec<_>>();
 6431                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6432                    PathKey::for_buffer(buffer_handle, cx),
 6433                    buffer_handle.clone(),
 6434                    edited_ranges,
 6435                    multibuffer_context_lines(cx),
 6436                    cx,
 6437                );
 6438
 6439                ranges_to_highlight.extend(ranges);
 6440            }
 6441            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6442            multibuffer
 6443        })?;
 6444
 6445        workspace.update_in(cx, |workspace, window, cx| {
 6446            let project = workspace.project().clone();
 6447            let editor =
 6448                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6449            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6450            editor.update(cx, |editor, cx| {
 6451                editor.highlight_background::<Self>(
 6452                    &ranges_to_highlight,
 6453                    |theme| theme.colors().editor_highlighted_line_background,
 6454                    cx,
 6455                );
 6456            });
 6457        })?;
 6458
 6459        Ok(())
 6460    }
 6461
 6462    pub fn clear_code_action_providers(&mut self) {
 6463        self.code_action_providers.clear();
 6464        self.available_code_actions.take();
 6465    }
 6466
 6467    pub fn add_code_action_provider(
 6468        &mut self,
 6469        provider: Rc<dyn CodeActionProvider>,
 6470        window: &mut Window,
 6471        cx: &mut Context<Self>,
 6472    ) {
 6473        if self
 6474            .code_action_providers
 6475            .iter()
 6476            .any(|existing_provider| existing_provider.id() == provider.id())
 6477        {
 6478            return;
 6479        }
 6480
 6481        self.code_action_providers.push(provider);
 6482        self.refresh_code_actions(window, cx);
 6483    }
 6484
 6485    pub fn remove_code_action_provider(
 6486        &mut self,
 6487        id: Arc<str>,
 6488        window: &mut Window,
 6489        cx: &mut Context<Self>,
 6490    ) {
 6491        self.code_action_providers
 6492            .retain(|provider| provider.id() != id);
 6493        self.refresh_code_actions(window, cx);
 6494    }
 6495
 6496    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6497        !self.code_action_providers.is_empty()
 6498            && EditorSettings::get_global(cx).toolbar.code_actions
 6499    }
 6500
 6501    pub fn has_available_code_actions(&self) -> bool {
 6502        self.available_code_actions
 6503            .as_ref()
 6504            .is_some_and(|(_, actions)| !actions.is_empty())
 6505    }
 6506
 6507    fn render_inline_code_actions(
 6508        &self,
 6509        icon_size: ui::IconSize,
 6510        display_row: DisplayRow,
 6511        is_active: bool,
 6512        cx: &mut Context<Self>,
 6513    ) -> AnyElement {
 6514        let show_tooltip = !self.context_menu_visible();
 6515        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6516            .icon_size(icon_size)
 6517            .shape(ui::IconButtonShape::Square)
 6518            .icon_color(ui::Color::Hidden)
 6519            .toggle_state(is_active)
 6520            .when(show_tooltip, |this| {
 6521                this.tooltip({
 6522                    let focus_handle = self.focus_handle.clone();
 6523                    move |window, cx| {
 6524                        Tooltip::for_action_in(
 6525                            "Toggle Code Actions",
 6526                            &ToggleCodeActions {
 6527                                deployed_from: None,
 6528                                quick_launch: false,
 6529                            },
 6530                            &focus_handle,
 6531                            window,
 6532                            cx,
 6533                        )
 6534                    }
 6535                })
 6536            })
 6537            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6538                window.focus(&editor.focus_handle(cx));
 6539                editor.toggle_code_actions(
 6540                    &crate::actions::ToggleCodeActions {
 6541                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6542                            display_row,
 6543                        )),
 6544                        quick_launch: false,
 6545                    },
 6546                    window,
 6547                    cx,
 6548                );
 6549            }))
 6550            .into_any_element()
 6551    }
 6552
 6553    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6554        &self.context_menu
 6555    }
 6556
 6557    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6558        let newest_selection = self.selections.newest_anchor().clone();
 6559        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6560        let buffer = self.buffer.read(cx);
 6561        if newest_selection.head().diff_base_anchor.is_some() {
 6562            return None;
 6563        }
 6564        let (start_buffer, start) =
 6565            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6566        let (end_buffer, end) =
 6567            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6568        if start_buffer != end_buffer {
 6569            return None;
 6570        }
 6571
 6572        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6573            cx.background_executor()
 6574                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6575                .await;
 6576
 6577            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6578                let providers = this.code_action_providers.clone();
 6579                let tasks = this
 6580                    .code_action_providers
 6581                    .iter()
 6582                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6583                    .collect::<Vec<_>>();
 6584                (providers, tasks)
 6585            })?;
 6586
 6587            let mut actions = Vec::new();
 6588            for (provider, provider_actions) in
 6589                providers.into_iter().zip(future::join_all(tasks).await)
 6590            {
 6591                if let Some(provider_actions) = provider_actions.log_err() {
 6592                    actions.extend(provider_actions.into_iter().map(|action| {
 6593                        AvailableCodeAction {
 6594                            excerpt_id: newest_selection.start.excerpt_id,
 6595                            action,
 6596                            provider: provider.clone(),
 6597                        }
 6598                    }));
 6599                }
 6600            }
 6601
 6602            this.update(cx, |this, cx| {
 6603                this.available_code_actions = if actions.is_empty() {
 6604                    None
 6605                } else {
 6606                    Some((
 6607                        Location {
 6608                            buffer: start_buffer,
 6609                            range: start..end,
 6610                        },
 6611                        actions.into(),
 6612                    ))
 6613                };
 6614                cx.notify();
 6615            })
 6616        }));
 6617        None
 6618    }
 6619
 6620    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6621        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6622            self.show_git_blame_inline = false;
 6623
 6624            self.show_git_blame_inline_delay_task =
 6625                Some(cx.spawn_in(window, async move |this, cx| {
 6626                    cx.background_executor().timer(delay).await;
 6627
 6628                    this.update(cx, |this, cx| {
 6629                        this.show_git_blame_inline = true;
 6630                        cx.notify();
 6631                    })
 6632                    .log_err();
 6633                }));
 6634        }
 6635    }
 6636
 6637    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6638        let snapshot = self.snapshot(window, cx);
 6639        let cursor = self.selections.newest::<Point>(cx).head();
 6640        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6641        else {
 6642            return;
 6643        };
 6644
 6645        let Some(blame) = self.blame.as_ref() else {
 6646            return;
 6647        };
 6648
 6649        let row_info = RowInfo {
 6650            buffer_id: Some(buffer.remote_id()),
 6651            buffer_row: Some(point.row),
 6652            ..Default::default()
 6653        };
 6654        let Some((buffer, blame_entry)) = blame
 6655            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6656            .flatten()
 6657        else {
 6658            return;
 6659        };
 6660
 6661        let anchor = self.selections.newest_anchor().head();
 6662        let position = self.to_pixel_point(anchor, &snapshot, window);
 6663        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6664            self.show_blame_popover(
 6665                buffer,
 6666                &blame_entry,
 6667                position + last_bounds.origin,
 6668                true,
 6669                cx,
 6670            );
 6671        };
 6672    }
 6673
 6674    fn show_blame_popover(
 6675        &mut self,
 6676        buffer: BufferId,
 6677        blame_entry: &BlameEntry,
 6678        position: gpui::Point<Pixels>,
 6679        ignore_timeout: bool,
 6680        cx: &mut Context<Self>,
 6681    ) {
 6682        if let Some(state) = &mut self.inline_blame_popover {
 6683            state.hide_task.take();
 6684        } else {
 6685            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6686            let blame_entry = blame_entry.clone();
 6687            let show_task = cx.spawn(async move |editor, cx| {
 6688                if !ignore_timeout {
 6689                    cx.background_executor()
 6690                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6691                        .await;
 6692                }
 6693                editor
 6694                    .update(cx, |editor, cx| {
 6695                        editor.inline_blame_popover_show_task.take();
 6696                        let Some(blame) = editor.blame.as_ref() else {
 6697                            return;
 6698                        };
 6699                        let blame = blame.read(cx);
 6700                        let details = blame.details_for_entry(buffer, &blame_entry);
 6701                        let markdown = cx.new(|cx| {
 6702                            Markdown::new(
 6703                                details
 6704                                    .as_ref()
 6705                                    .map(|message| message.message.clone())
 6706                                    .unwrap_or_default(),
 6707                                None,
 6708                                None,
 6709                                cx,
 6710                            )
 6711                        });
 6712                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6713                            position,
 6714                            hide_task: None,
 6715                            popover_bounds: None,
 6716                            popover_state: InlineBlamePopoverState {
 6717                                scroll_handle: ScrollHandle::new(),
 6718                                commit_message: details,
 6719                                markdown,
 6720                            },
 6721                            keyboard_grace: ignore_timeout,
 6722                        });
 6723                        cx.notify();
 6724                    })
 6725                    .ok();
 6726            });
 6727            self.inline_blame_popover_show_task = Some(show_task);
 6728        }
 6729    }
 6730
 6731    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6732        self.inline_blame_popover_show_task.take();
 6733        if let Some(state) = &mut self.inline_blame_popover {
 6734            let hide_task = cx.spawn(async move |editor, cx| {
 6735                cx.background_executor()
 6736                    .timer(std::time::Duration::from_millis(100))
 6737                    .await;
 6738                editor
 6739                    .update(cx, |editor, cx| {
 6740                        editor.inline_blame_popover.take();
 6741                        cx.notify();
 6742                    })
 6743                    .ok();
 6744            });
 6745            state.hide_task = Some(hide_task);
 6746        }
 6747    }
 6748
 6749    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6750        if self.pending_rename.is_some() {
 6751            return None;
 6752        }
 6753
 6754        let provider = self.semantics_provider.clone()?;
 6755        let buffer = self.buffer.read(cx);
 6756        let newest_selection = self.selections.newest_anchor().clone();
 6757        let cursor_position = newest_selection.head();
 6758        let (cursor_buffer, cursor_buffer_position) =
 6759            buffer.text_anchor_for_position(cursor_position, cx)?;
 6760        let (tail_buffer, tail_buffer_position) =
 6761            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6762        if cursor_buffer != tail_buffer {
 6763            return None;
 6764        }
 6765
 6766        let snapshot = cursor_buffer.read(cx).snapshot();
 6767        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6768        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6769        if start_word_range != end_word_range {
 6770            self.document_highlights_task.take();
 6771            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6772            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6773            return None;
 6774        }
 6775
 6776        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6777        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6778            cx.background_executor()
 6779                .timer(Duration::from_millis(debounce))
 6780                .await;
 6781
 6782            let highlights = if let Some(highlights) = cx
 6783                .update(|cx| {
 6784                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6785                })
 6786                .ok()
 6787                .flatten()
 6788            {
 6789                highlights.await.log_err()
 6790            } else {
 6791                None
 6792            };
 6793
 6794            if let Some(highlights) = highlights {
 6795                this.update(cx, |this, cx| {
 6796                    if this.pending_rename.is_some() {
 6797                        return;
 6798                    }
 6799
 6800                    let buffer = this.buffer.read(cx);
 6801                    if buffer
 6802                        .text_anchor_for_position(cursor_position, cx)
 6803                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6804                    {
 6805                        return;
 6806                    }
 6807
 6808                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6809                    let mut write_ranges = Vec::new();
 6810                    let mut read_ranges = Vec::new();
 6811                    for highlight in highlights {
 6812                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6813                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6814                        {
 6815                            let start = highlight
 6816                                .range
 6817                                .start
 6818                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6819                            let end = highlight
 6820                                .range
 6821                                .end
 6822                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6823                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6824                                continue;
 6825                            }
 6826
 6827                            let range = Anchor {
 6828                                buffer_id: Some(buffer_id),
 6829                                excerpt_id,
 6830                                text_anchor: start,
 6831                                diff_base_anchor: None,
 6832                            }..Anchor {
 6833                                buffer_id: Some(buffer_id),
 6834                                excerpt_id,
 6835                                text_anchor: end,
 6836                                diff_base_anchor: None,
 6837                            };
 6838                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6839                                write_ranges.push(range);
 6840                            } else {
 6841                                read_ranges.push(range);
 6842                            }
 6843                        }
 6844                    }
 6845
 6846                    this.highlight_background::<DocumentHighlightRead>(
 6847                        &read_ranges,
 6848                        |theme| theme.colors().editor_document_highlight_read_background,
 6849                        cx,
 6850                    );
 6851                    this.highlight_background::<DocumentHighlightWrite>(
 6852                        &write_ranges,
 6853                        |theme| theme.colors().editor_document_highlight_write_background,
 6854                        cx,
 6855                    );
 6856                    cx.notify();
 6857                })
 6858                .log_err();
 6859            }
 6860        }));
 6861        None
 6862    }
 6863
 6864    fn prepare_highlight_query_from_selection(
 6865        &mut self,
 6866        cx: &mut Context<Editor>,
 6867    ) -> Option<(String, Range<Anchor>)> {
 6868        if matches!(self.mode, EditorMode::SingleLine) {
 6869            return None;
 6870        }
 6871        if !EditorSettings::get_global(cx).selection_highlight {
 6872            return None;
 6873        }
 6874        if self.selections.count() != 1 || self.selections.line_mode {
 6875            return None;
 6876        }
 6877        let selection = self.selections.newest::<Point>(cx);
 6878        if selection.is_empty() || selection.start.row != selection.end.row {
 6879            return None;
 6880        }
 6881        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6882        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6883        let query = multi_buffer_snapshot
 6884            .text_for_range(selection_anchor_range.clone())
 6885            .collect::<String>();
 6886        if query.trim().is_empty() {
 6887            return None;
 6888        }
 6889        Some((query, selection_anchor_range))
 6890    }
 6891
 6892    fn update_selection_occurrence_highlights(
 6893        &mut self,
 6894        query_text: String,
 6895        query_range: Range<Anchor>,
 6896        multi_buffer_range_to_query: Range<Point>,
 6897        use_debounce: bool,
 6898        window: &mut Window,
 6899        cx: &mut Context<Editor>,
 6900    ) -> Task<()> {
 6901        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6902        cx.spawn_in(window, async move |editor, cx| {
 6903            if use_debounce {
 6904                cx.background_executor()
 6905                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6906                    .await;
 6907            }
 6908            let match_task = cx.background_spawn(async move {
 6909                let buffer_ranges = multi_buffer_snapshot
 6910                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6911                    .into_iter()
 6912                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6913                let mut match_ranges = Vec::new();
 6914                let Ok(regex) = project::search::SearchQuery::text(
 6915                    query_text.clone(),
 6916                    false,
 6917                    false,
 6918                    false,
 6919                    Default::default(),
 6920                    Default::default(),
 6921                    false,
 6922                    None,
 6923                ) else {
 6924                    return Vec::default();
 6925                };
 6926                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6927                    match_ranges.extend(
 6928                        regex
 6929                            .search(buffer_snapshot, Some(search_range.clone()))
 6930                            .await
 6931                            .into_iter()
 6932                            .filter_map(|match_range| {
 6933                                let match_start = buffer_snapshot
 6934                                    .anchor_after(search_range.start + match_range.start);
 6935                                let match_end = buffer_snapshot
 6936                                    .anchor_before(search_range.start + match_range.end);
 6937                                let match_anchor_range = Anchor::range_in_buffer(
 6938                                    excerpt_id,
 6939                                    buffer_snapshot.remote_id(),
 6940                                    match_start..match_end,
 6941                                );
 6942                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6943                            }),
 6944                    );
 6945                }
 6946                match_ranges
 6947            });
 6948            let match_ranges = match_task.await;
 6949            editor
 6950                .update_in(cx, |editor, _, cx| {
 6951                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6952                    if !match_ranges.is_empty() {
 6953                        editor.highlight_background::<SelectedTextHighlight>(
 6954                            &match_ranges,
 6955                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6956                            cx,
 6957                        )
 6958                    }
 6959                })
 6960                .log_err();
 6961        })
 6962    }
 6963
 6964    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6965        struct NewlineFold;
 6966        let type_id = std::any::TypeId::of::<NewlineFold>();
 6967        if !self.mode.is_single_line() {
 6968            return;
 6969        }
 6970        let snapshot = self.snapshot(window, cx);
 6971        if snapshot.buffer_snapshot.max_point().row == 0 {
 6972            return;
 6973        }
 6974        let task = cx.background_spawn(async move {
 6975            let new_newlines = snapshot
 6976                .buffer_chars_at(0)
 6977                .filter_map(|(c, i)| {
 6978                    if c == '\n' {
 6979                        Some(
 6980                            snapshot.buffer_snapshot.anchor_after(i)
 6981                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6982                        )
 6983                    } else {
 6984                        None
 6985                    }
 6986                })
 6987                .collect::<Vec<_>>();
 6988            let existing_newlines = snapshot
 6989                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6990                .filter_map(|fold| {
 6991                    if fold.placeholder.type_tag == Some(type_id) {
 6992                        Some(fold.range.start..fold.range.end)
 6993                    } else {
 6994                        None
 6995                    }
 6996                })
 6997                .collect::<Vec<_>>();
 6998
 6999            (new_newlines, existing_newlines)
 7000        });
 7001        self.folding_newlines = cx.spawn(async move |this, cx| {
 7002            let (new_newlines, existing_newlines) = task.await;
 7003            if new_newlines == existing_newlines {
 7004                return;
 7005            }
 7006            let placeholder = FoldPlaceholder {
 7007                render: Arc::new(move |_, _, cx| {
 7008                    div()
 7009                        .bg(cx.theme().status().hint_background)
 7010                        .border_b_1()
 7011                        .size_full()
 7012                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7013                        .border_color(cx.theme().status().hint)
 7014                        .child("\\n")
 7015                        .into_any()
 7016                }),
 7017                constrain_width: false,
 7018                merge_adjacent: false,
 7019                type_tag: Some(type_id),
 7020            };
 7021            let creases = new_newlines
 7022                .into_iter()
 7023                .map(|range| Crease::simple(range, placeholder.clone()))
 7024                .collect();
 7025            this.update(cx, |this, cx| {
 7026                this.display_map.update(cx, |display_map, cx| {
 7027                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7028                    display_map.fold(creases, cx);
 7029                });
 7030            })
 7031            .ok();
 7032        });
 7033    }
 7034
 7035    fn refresh_selected_text_highlights(
 7036        &mut self,
 7037        on_buffer_edit: bool,
 7038        window: &mut Window,
 7039        cx: &mut Context<Editor>,
 7040    ) {
 7041        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7042        else {
 7043            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7044            self.quick_selection_highlight_task.take();
 7045            self.debounced_selection_highlight_task.take();
 7046            return;
 7047        };
 7048        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7049        if on_buffer_edit
 7050            || self
 7051                .quick_selection_highlight_task
 7052                .as_ref()
 7053                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7054        {
 7055            let multi_buffer_visible_start = self
 7056                .scroll_manager
 7057                .anchor()
 7058                .anchor
 7059                .to_point(&multi_buffer_snapshot);
 7060            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7061                multi_buffer_visible_start
 7062                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7063                Bias::Left,
 7064            );
 7065            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7066            self.quick_selection_highlight_task = Some((
 7067                query_range.clone(),
 7068                self.update_selection_occurrence_highlights(
 7069                    query_text.clone(),
 7070                    query_range.clone(),
 7071                    multi_buffer_visible_range,
 7072                    false,
 7073                    window,
 7074                    cx,
 7075                ),
 7076            ));
 7077        }
 7078        if on_buffer_edit
 7079            || self
 7080                .debounced_selection_highlight_task
 7081                .as_ref()
 7082                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7083        {
 7084            let multi_buffer_start = multi_buffer_snapshot
 7085                .anchor_before(0)
 7086                .to_point(&multi_buffer_snapshot);
 7087            let multi_buffer_end = multi_buffer_snapshot
 7088                .anchor_after(multi_buffer_snapshot.len())
 7089                .to_point(&multi_buffer_snapshot);
 7090            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7091            self.debounced_selection_highlight_task = Some((
 7092                query_range.clone(),
 7093                self.update_selection_occurrence_highlights(
 7094                    query_text,
 7095                    query_range,
 7096                    multi_buffer_full_range,
 7097                    true,
 7098                    window,
 7099                    cx,
 7100                ),
 7101            ));
 7102        }
 7103    }
 7104
 7105    pub fn refresh_edit_prediction(
 7106        &mut self,
 7107        debounce: bool,
 7108        user_requested: bool,
 7109        window: &mut Window,
 7110        cx: &mut Context<Self>,
 7111    ) -> Option<()> {
 7112        if DisableAiSettings::get_global(cx).disable_ai {
 7113            return None;
 7114        }
 7115
 7116        let provider = self.edit_prediction_provider()?;
 7117        let cursor = self.selections.newest_anchor().head();
 7118        let (buffer, cursor_buffer_position) =
 7119            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7120
 7121        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7122            self.discard_edit_prediction(false, cx);
 7123            return None;
 7124        }
 7125
 7126        if !user_requested
 7127            && (!self.should_show_edit_predictions()
 7128                || !self.is_focused(window)
 7129                || buffer.read(cx).is_empty())
 7130        {
 7131            self.discard_edit_prediction(false, cx);
 7132            return None;
 7133        }
 7134
 7135        self.update_visible_edit_prediction(window, cx);
 7136        provider.refresh(
 7137            self.project.clone(),
 7138            buffer,
 7139            cursor_buffer_position,
 7140            debounce,
 7141            cx,
 7142        );
 7143        Some(())
 7144    }
 7145
 7146    fn show_edit_predictions_in_menu(&self) -> bool {
 7147        match self.edit_prediction_settings {
 7148            EditPredictionSettings::Disabled => false,
 7149            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7150        }
 7151    }
 7152
 7153    pub fn edit_predictions_enabled(&self) -> bool {
 7154        match self.edit_prediction_settings {
 7155            EditPredictionSettings::Disabled => false,
 7156            EditPredictionSettings::Enabled { .. } => true,
 7157        }
 7158    }
 7159
 7160    fn edit_prediction_requires_modifier(&self) -> bool {
 7161        match self.edit_prediction_settings {
 7162            EditPredictionSettings::Disabled => false,
 7163            EditPredictionSettings::Enabled {
 7164                preview_requires_modifier,
 7165                ..
 7166            } => preview_requires_modifier,
 7167        }
 7168    }
 7169
 7170    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7171        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7172            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7173            self.discard_edit_prediction(false, cx);
 7174        } else {
 7175            let selection = self.selections.newest_anchor();
 7176            let cursor = selection.head();
 7177
 7178            if let Some((buffer, cursor_buffer_position)) =
 7179                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7180            {
 7181                self.edit_prediction_settings =
 7182                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7183            }
 7184        }
 7185    }
 7186
 7187    fn edit_prediction_settings_at_position(
 7188        &self,
 7189        buffer: &Entity<Buffer>,
 7190        buffer_position: language::Anchor,
 7191        cx: &App,
 7192    ) -> EditPredictionSettings {
 7193        if !self.mode.is_full()
 7194            || !self.show_edit_predictions_override.unwrap_or(true)
 7195            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7196        {
 7197            return EditPredictionSettings::Disabled;
 7198        }
 7199
 7200        let buffer = buffer.read(cx);
 7201
 7202        let file = buffer.file();
 7203
 7204        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7205            return EditPredictionSettings::Disabled;
 7206        };
 7207
 7208        let by_provider = matches!(
 7209            self.menu_edit_predictions_policy,
 7210            MenuEditPredictionsPolicy::ByProvider
 7211        );
 7212
 7213        let show_in_menu = by_provider
 7214            && self
 7215                .edit_prediction_provider
 7216                .as_ref()
 7217                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7218
 7219        let preview_requires_modifier =
 7220            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7221
 7222        EditPredictionSettings::Enabled {
 7223            show_in_menu,
 7224            preview_requires_modifier,
 7225        }
 7226    }
 7227
 7228    fn should_show_edit_predictions(&self) -> bool {
 7229        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7230    }
 7231
 7232    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7233        matches!(
 7234            self.edit_prediction_preview,
 7235            EditPredictionPreview::Active { .. }
 7236        )
 7237    }
 7238
 7239    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7240        let cursor = self.selections.newest_anchor().head();
 7241        if let Some((buffer, cursor_position)) =
 7242            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7243        {
 7244            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7245        } else {
 7246            false
 7247        }
 7248    }
 7249
 7250    pub fn supports_minimap(&self, cx: &App) -> bool {
 7251        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7252    }
 7253
 7254    fn edit_predictions_enabled_in_buffer(
 7255        &self,
 7256        buffer: &Entity<Buffer>,
 7257        buffer_position: language::Anchor,
 7258        cx: &App,
 7259    ) -> bool {
 7260        maybe!({
 7261            if self.read_only(cx) {
 7262                return Some(false);
 7263            }
 7264            let provider = self.edit_prediction_provider()?;
 7265            if !provider.is_enabled(buffer, buffer_position, cx) {
 7266                return Some(false);
 7267            }
 7268            let buffer = buffer.read(cx);
 7269            let Some(file) = buffer.file() else {
 7270                return Some(true);
 7271            };
 7272            let settings = all_language_settings(Some(file), cx);
 7273            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7274        })
 7275        .unwrap_or(false)
 7276    }
 7277
 7278    fn cycle_edit_prediction(
 7279        &mut self,
 7280        direction: Direction,
 7281        window: &mut Window,
 7282        cx: &mut Context<Self>,
 7283    ) -> Option<()> {
 7284        let provider = self.edit_prediction_provider()?;
 7285        let cursor = self.selections.newest_anchor().head();
 7286        let (buffer, cursor_buffer_position) =
 7287            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7288        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7289            return None;
 7290        }
 7291
 7292        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7293        self.update_visible_edit_prediction(window, cx);
 7294
 7295        Some(())
 7296    }
 7297
 7298    pub fn show_edit_prediction(
 7299        &mut self,
 7300        _: &ShowEditPrediction,
 7301        window: &mut Window,
 7302        cx: &mut Context<Self>,
 7303    ) {
 7304        if !self.has_active_edit_prediction() {
 7305            self.refresh_edit_prediction(false, true, window, cx);
 7306            return;
 7307        }
 7308
 7309        self.update_visible_edit_prediction(window, cx);
 7310    }
 7311
 7312    pub fn display_cursor_names(
 7313        &mut self,
 7314        _: &DisplayCursorNames,
 7315        window: &mut Window,
 7316        cx: &mut Context<Self>,
 7317    ) {
 7318        self.show_cursor_names(window, cx);
 7319    }
 7320
 7321    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7322        self.show_cursor_names = true;
 7323        cx.notify();
 7324        cx.spawn_in(window, async move |this, cx| {
 7325            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7326            this.update(cx, |this, cx| {
 7327                this.show_cursor_names = false;
 7328                cx.notify()
 7329            })
 7330            .ok()
 7331        })
 7332        .detach();
 7333    }
 7334
 7335    pub fn next_edit_prediction(
 7336        &mut self,
 7337        _: &NextEditPrediction,
 7338        window: &mut Window,
 7339        cx: &mut Context<Self>,
 7340    ) {
 7341        if self.has_active_edit_prediction() {
 7342            self.cycle_edit_prediction(Direction::Next, window, cx);
 7343        } else {
 7344            let is_copilot_disabled = self
 7345                .refresh_edit_prediction(false, true, window, cx)
 7346                .is_none();
 7347            if is_copilot_disabled {
 7348                cx.propagate();
 7349            }
 7350        }
 7351    }
 7352
 7353    pub fn previous_edit_prediction(
 7354        &mut self,
 7355        _: &PreviousEditPrediction,
 7356        window: &mut Window,
 7357        cx: &mut Context<Self>,
 7358    ) {
 7359        if self.has_active_edit_prediction() {
 7360            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7361        } else {
 7362            let is_copilot_disabled = self
 7363                .refresh_edit_prediction(false, true, window, cx)
 7364                .is_none();
 7365            if is_copilot_disabled {
 7366                cx.propagate();
 7367            }
 7368        }
 7369    }
 7370
 7371    pub fn accept_edit_prediction(
 7372        &mut self,
 7373        _: &AcceptEditPrediction,
 7374        window: &mut Window,
 7375        cx: &mut Context<Self>,
 7376    ) {
 7377        if self.show_edit_predictions_in_menu() {
 7378            self.hide_context_menu(window, cx);
 7379        }
 7380
 7381        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7382            return;
 7383        };
 7384
 7385        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7386
 7387        match &active_edit_prediction.completion {
 7388            EditPrediction::Move { target, .. } => {
 7389                let target = *target;
 7390
 7391                if let Some(position_map) = &self.last_position_map {
 7392                    if position_map
 7393                        .visible_row_range
 7394                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7395                        || !self.edit_prediction_requires_modifier()
 7396                    {
 7397                        self.unfold_ranges(&[target..target], true, false, cx);
 7398                        // Note that this is also done in vim's handler of the Tab action.
 7399                        self.change_selections(
 7400                            SelectionEffects::scroll(Autoscroll::newest()),
 7401                            window,
 7402                            cx,
 7403                            |selections| {
 7404                                selections.select_anchor_ranges([target..target]);
 7405                            },
 7406                        );
 7407                        self.clear_row_highlights::<EditPredictionPreview>();
 7408
 7409                        self.edit_prediction_preview
 7410                            .set_previous_scroll_position(None);
 7411                    } else {
 7412                        self.edit_prediction_preview
 7413                            .set_previous_scroll_position(Some(
 7414                                position_map.snapshot.scroll_anchor,
 7415                            ));
 7416
 7417                        self.highlight_rows::<EditPredictionPreview>(
 7418                            target..target,
 7419                            cx.theme().colors().editor_highlighted_line_background,
 7420                            RowHighlightOptions {
 7421                                autoscroll: true,
 7422                                ..Default::default()
 7423                            },
 7424                            cx,
 7425                        );
 7426                        self.request_autoscroll(Autoscroll::fit(), cx);
 7427                    }
 7428                }
 7429            }
 7430            EditPrediction::Edit { edits, .. } => {
 7431                if let Some(provider) = self.edit_prediction_provider() {
 7432                    provider.accept(cx);
 7433                }
 7434
 7435                // Store the transaction ID and selections before applying the edit
 7436                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7437
 7438                let snapshot = self.buffer.read(cx).snapshot(cx);
 7439                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7440
 7441                self.buffer.update(cx, |buffer, cx| {
 7442                    buffer.edit(edits.iter().cloned(), None, cx)
 7443                });
 7444
 7445                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7446                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7447                });
 7448
 7449                let selections = self.selections.disjoint_anchors();
 7450                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7451                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7452                    if has_new_transaction {
 7453                        self.selection_history
 7454                            .insert_transaction(transaction_id_now, selections);
 7455                    }
 7456                }
 7457
 7458                self.update_visible_edit_prediction(window, cx);
 7459                if self.active_edit_prediction.is_none() {
 7460                    self.refresh_edit_prediction(true, true, window, cx);
 7461                }
 7462
 7463                cx.notify();
 7464            }
 7465        }
 7466
 7467        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7468    }
 7469
 7470    pub fn accept_partial_edit_prediction(
 7471        &mut self,
 7472        _: &AcceptPartialEditPrediction,
 7473        window: &mut Window,
 7474        cx: &mut Context<Self>,
 7475    ) {
 7476        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7477            return;
 7478        };
 7479        if self.selections.count() != 1 {
 7480            return;
 7481        }
 7482
 7483        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7484
 7485        match &active_edit_prediction.completion {
 7486            EditPrediction::Move { target, .. } => {
 7487                let target = *target;
 7488                self.change_selections(
 7489                    SelectionEffects::scroll(Autoscroll::newest()),
 7490                    window,
 7491                    cx,
 7492                    |selections| {
 7493                        selections.select_anchor_ranges([target..target]);
 7494                    },
 7495                );
 7496            }
 7497            EditPrediction::Edit { edits, .. } => {
 7498                // Find an insertion that starts at the cursor position.
 7499                let snapshot = self.buffer.read(cx).snapshot(cx);
 7500                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7501                let insertion = edits.iter().find_map(|(range, text)| {
 7502                    let range = range.to_offset(&snapshot);
 7503                    if range.is_empty() && range.start == cursor_offset {
 7504                        Some(text)
 7505                    } else {
 7506                        None
 7507                    }
 7508                });
 7509
 7510                if let Some(text) = insertion {
 7511                    let mut partial_completion = text
 7512                        .chars()
 7513                        .by_ref()
 7514                        .take_while(|c| c.is_alphabetic())
 7515                        .collect::<String>();
 7516                    if partial_completion.is_empty() {
 7517                        partial_completion = text
 7518                            .chars()
 7519                            .by_ref()
 7520                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7521                            .collect::<String>();
 7522                    }
 7523
 7524                    cx.emit(EditorEvent::InputHandled {
 7525                        utf16_range_to_replace: None,
 7526                        text: partial_completion.clone().into(),
 7527                    });
 7528
 7529                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7530
 7531                    self.refresh_edit_prediction(true, true, window, cx);
 7532                    cx.notify();
 7533                } else {
 7534                    self.accept_edit_prediction(&Default::default(), window, cx);
 7535                }
 7536            }
 7537        }
 7538    }
 7539
 7540    fn discard_edit_prediction(
 7541        &mut self,
 7542        should_report_edit_prediction_event: bool,
 7543        cx: &mut Context<Self>,
 7544    ) -> bool {
 7545        if should_report_edit_prediction_event {
 7546            let completion_id = self
 7547                .active_edit_prediction
 7548                .as_ref()
 7549                .and_then(|active_completion| active_completion.completion_id.clone());
 7550
 7551            self.report_edit_prediction_event(completion_id, false, cx);
 7552        }
 7553
 7554        if let Some(provider) = self.edit_prediction_provider() {
 7555            provider.discard(cx);
 7556        }
 7557
 7558        self.take_active_edit_prediction(cx)
 7559    }
 7560
 7561    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7562        let Some(provider) = self.edit_prediction_provider() else {
 7563            return;
 7564        };
 7565
 7566        let Some((_, buffer, _)) = self
 7567            .buffer
 7568            .read(cx)
 7569            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7570        else {
 7571            return;
 7572        };
 7573
 7574        let extension = buffer
 7575            .read(cx)
 7576            .file()
 7577            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7578
 7579        let event_type = match accepted {
 7580            true => "Edit Prediction Accepted",
 7581            false => "Edit Prediction Discarded",
 7582        };
 7583        telemetry::event!(
 7584            event_type,
 7585            provider = provider.name(),
 7586            prediction_id = id,
 7587            suggestion_accepted = accepted,
 7588            file_extension = extension,
 7589        );
 7590    }
 7591
 7592    pub fn has_active_edit_prediction(&self) -> bool {
 7593        self.active_edit_prediction.is_some()
 7594    }
 7595
 7596    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7597        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7598            return false;
 7599        };
 7600
 7601        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7602        self.clear_highlights::<EditPredictionHighlight>(cx);
 7603        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7604        true
 7605    }
 7606
 7607    /// Returns true when we're displaying the edit prediction popover below the cursor
 7608    /// like we are not previewing and the LSP autocomplete menu is visible
 7609    /// or we are in `when_holding_modifier` mode.
 7610    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7611        if self.edit_prediction_preview_is_active()
 7612            || !self.show_edit_predictions_in_menu()
 7613            || !self.edit_predictions_enabled()
 7614        {
 7615            return false;
 7616        }
 7617
 7618        if self.has_visible_completions_menu() {
 7619            return true;
 7620        }
 7621
 7622        has_completion && self.edit_prediction_requires_modifier()
 7623    }
 7624
 7625    fn handle_modifiers_changed(
 7626        &mut self,
 7627        modifiers: Modifiers,
 7628        position_map: &PositionMap,
 7629        window: &mut Window,
 7630        cx: &mut Context<Self>,
 7631    ) {
 7632        if self.show_edit_predictions_in_menu() {
 7633            self.update_edit_prediction_preview(&modifiers, window, cx);
 7634        }
 7635
 7636        self.update_selection_mode(&modifiers, position_map, window, cx);
 7637
 7638        let mouse_position = window.mouse_position();
 7639        if !position_map.text_hitbox.is_hovered(window) {
 7640            return;
 7641        }
 7642
 7643        self.update_hovered_link(
 7644            position_map.point_for_position(mouse_position),
 7645            &position_map.snapshot,
 7646            modifiers,
 7647            window,
 7648            cx,
 7649        )
 7650    }
 7651
 7652    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7653        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7654        if invert {
 7655            match multi_cursor_setting {
 7656                MultiCursorModifier::Alt => modifiers.alt,
 7657                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7658            }
 7659        } else {
 7660            match multi_cursor_setting {
 7661                MultiCursorModifier::Alt => modifiers.secondary(),
 7662                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7663            }
 7664        }
 7665    }
 7666
 7667    fn columnar_selection_mode(
 7668        modifiers: &Modifiers,
 7669        cx: &mut Context<Self>,
 7670    ) -> Option<ColumnarMode> {
 7671        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7672            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7673                Some(ColumnarMode::FromMouse)
 7674            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7675                Some(ColumnarMode::FromSelection)
 7676            } else {
 7677                None
 7678            }
 7679        } else {
 7680            None
 7681        }
 7682    }
 7683
 7684    fn update_selection_mode(
 7685        &mut self,
 7686        modifiers: &Modifiers,
 7687        position_map: &PositionMap,
 7688        window: &mut Window,
 7689        cx: &mut Context<Self>,
 7690    ) {
 7691        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7692            return;
 7693        };
 7694        if self.selections.pending.is_none() {
 7695            return;
 7696        }
 7697
 7698        let mouse_position = window.mouse_position();
 7699        let point_for_position = position_map.point_for_position(mouse_position);
 7700        let position = point_for_position.previous_valid;
 7701
 7702        self.select(
 7703            SelectPhase::BeginColumnar {
 7704                position,
 7705                reset: false,
 7706                mode,
 7707                goal_column: point_for_position.exact_unclipped.column(),
 7708            },
 7709            window,
 7710            cx,
 7711        );
 7712    }
 7713
 7714    fn update_edit_prediction_preview(
 7715        &mut self,
 7716        modifiers: &Modifiers,
 7717        window: &mut Window,
 7718        cx: &mut Context<Self>,
 7719    ) {
 7720        let mut modifiers_held = false;
 7721        if let Some(accept_keystroke) = self
 7722            .accept_edit_prediction_keybind(false, window, cx)
 7723            .keystroke()
 7724        {
 7725            modifiers_held = modifiers_held
 7726                || (accept_keystroke.modifiers() == modifiers
 7727                    && accept_keystroke.modifiers().modified());
 7728        };
 7729        if let Some(accept_partial_keystroke) = self
 7730            .accept_edit_prediction_keybind(true, window, cx)
 7731            .keystroke()
 7732        {
 7733            modifiers_held = modifiers_held
 7734                || (accept_partial_keystroke.modifiers() == modifiers
 7735                    && accept_partial_keystroke.modifiers().modified());
 7736        }
 7737
 7738        if modifiers_held {
 7739            if matches!(
 7740                self.edit_prediction_preview,
 7741                EditPredictionPreview::Inactive { .. }
 7742            ) {
 7743                self.edit_prediction_preview = EditPredictionPreview::Active {
 7744                    previous_scroll_position: None,
 7745                    since: Instant::now(),
 7746                };
 7747
 7748                self.update_visible_edit_prediction(window, cx);
 7749                cx.notify();
 7750            }
 7751        } else if let EditPredictionPreview::Active {
 7752            previous_scroll_position,
 7753            since,
 7754        } = self.edit_prediction_preview
 7755        {
 7756            if let (Some(previous_scroll_position), Some(position_map)) =
 7757                (previous_scroll_position, self.last_position_map.as_ref())
 7758            {
 7759                self.set_scroll_position(
 7760                    previous_scroll_position
 7761                        .scroll_position(&position_map.snapshot.display_snapshot),
 7762                    window,
 7763                    cx,
 7764                );
 7765            }
 7766
 7767            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7768                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7769            };
 7770            self.clear_row_highlights::<EditPredictionPreview>();
 7771            self.update_visible_edit_prediction(window, cx);
 7772            cx.notify();
 7773        }
 7774    }
 7775
 7776    fn update_visible_edit_prediction(
 7777        &mut self,
 7778        _window: &mut Window,
 7779        cx: &mut Context<Self>,
 7780    ) -> Option<()> {
 7781        if DisableAiSettings::get_global(cx).disable_ai {
 7782            return None;
 7783        }
 7784
 7785        if self.ime_transaction.is_some() {
 7786            self.discard_edit_prediction(false, cx);
 7787            return None;
 7788        }
 7789
 7790        let selection = self.selections.newest_anchor();
 7791        let cursor = selection.head();
 7792        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7793        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7794        let excerpt_id = cursor.excerpt_id;
 7795
 7796        let show_in_menu = self.show_edit_predictions_in_menu();
 7797        let completions_menu_has_precedence = !show_in_menu
 7798            && (self.context_menu.borrow().is_some()
 7799                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7800
 7801        if completions_menu_has_precedence
 7802            || !offset_selection.is_empty()
 7803            || self
 7804                .active_edit_prediction
 7805                .as_ref()
 7806                .is_some_and(|completion| {
 7807                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7808                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7809                    !invalidation_range.contains(&offset_selection.head())
 7810                })
 7811        {
 7812            self.discard_edit_prediction(false, cx);
 7813            return None;
 7814        }
 7815
 7816        self.take_active_edit_prediction(cx);
 7817        let Some(provider) = self.edit_prediction_provider() else {
 7818            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7819            return None;
 7820        };
 7821
 7822        let (buffer, cursor_buffer_position) =
 7823            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7824
 7825        self.edit_prediction_settings =
 7826            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7827
 7828        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7829            self.discard_edit_prediction(false, cx);
 7830            return None;
 7831        };
 7832
 7833        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7834
 7835        if self.edit_prediction_indent_conflict {
 7836            let cursor_point = cursor.to_point(&multibuffer);
 7837
 7838            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7839
 7840            if let Some((_, indent)) = indents.iter().next()
 7841                && indent.len == cursor_point.column
 7842            {
 7843                self.edit_prediction_indent_conflict = false;
 7844            }
 7845        }
 7846
 7847        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7848        let edits = edit_prediction
 7849            .edits
 7850            .into_iter()
 7851            .flat_map(|(range, new_text)| {
 7852                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7853                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7854                Some((start..end, new_text))
 7855            })
 7856            .collect::<Vec<_>>();
 7857        if edits.is_empty() {
 7858            return None;
 7859        }
 7860
 7861        let first_edit_start = edits.first().unwrap().0.start;
 7862        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7863        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7864
 7865        let last_edit_end = edits.last().unwrap().0.end;
 7866        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7867        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7868
 7869        let cursor_row = cursor.to_point(&multibuffer).row;
 7870
 7871        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7872
 7873        let mut inlay_ids = Vec::new();
 7874        let invalidation_row_range;
 7875        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7876            Some(cursor_row..edit_end_row)
 7877        } else if cursor_row > edit_end_row {
 7878            Some(edit_start_row..cursor_row)
 7879        } else {
 7880            None
 7881        };
 7882        let supports_jump = self
 7883            .edit_prediction_provider
 7884            .as_ref()
 7885            .map(|provider| provider.provider.supports_jump_to_edit())
 7886            .unwrap_or(true);
 7887
 7888        let is_move = supports_jump
 7889            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7890        let completion = if is_move {
 7891            invalidation_row_range =
 7892                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7893            let target = first_edit_start;
 7894            EditPrediction::Move { target, snapshot }
 7895        } else {
 7896            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7897                && !self.edit_predictions_hidden_for_vim_mode;
 7898
 7899            if show_completions_in_buffer {
 7900                if edits
 7901                    .iter()
 7902                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7903                {
 7904                    let mut inlays = Vec::new();
 7905                    for (range, new_text) in &edits {
 7906                        let inlay = Inlay::edit_prediction(
 7907                            post_inc(&mut self.next_inlay_id),
 7908                            range.start,
 7909                            new_text.as_str(),
 7910                        );
 7911                        inlay_ids.push(inlay.id);
 7912                        inlays.push(inlay);
 7913                    }
 7914
 7915                    self.splice_inlays(&[], inlays, cx);
 7916                } else {
 7917                    let background_color = cx.theme().status().deleted_background;
 7918                    self.highlight_text::<EditPredictionHighlight>(
 7919                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7920                        HighlightStyle {
 7921                            background_color: Some(background_color),
 7922                            ..Default::default()
 7923                        },
 7924                        cx,
 7925                    );
 7926                }
 7927            }
 7928
 7929            invalidation_row_range = edit_start_row..edit_end_row;
 7930
 7931            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7932                if provider.show_tab_accept_marker() {
 7933                    EditDisplayMode::TabAccept
 7934                } else {
 7935                    EditDisplayMode::Inline
 7936                }
 7937            } else {
 7938                EditDisplayMode::DiffPopover
 7939            };
 7940
 7941            EditPrediction::Edit {
 7942                edits,
 7943                edit_preview: edit_prediction.edit_preview,
 7944                display_mode,
 7945                snapshot,
 7946            }
 7947        };
 7948
 7949        let invalidation_range = multibuffer
 7950            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7951            ..multibuffer.anchor_after(Point::new(
 7952                invalidation_row_range.end,
 7953                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7954            ));
 7955
 7956        self.stale_edit_prediction_in_menu = None;
 7957        self.active_edit_prediction = Some(EditPredictionState {
 7958            inlay_ids,
 7959            completion,
 7960            completion_id: edit_prediction.id,
 7961            invalidation_range,
 7962        });
 7963
 7964        cx.notify();
 7965
 7966        Some(())
 7967    }
 7968
 7969    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7970        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7971    }
 7972
 7973    fn clear_tasks(&mut self) {
 7974        self.tasks.clear()
 7975    }
 7976
 7977    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7978        if self.tasks.insert(key, value).is_some() {
 7979            // This case should hopefully be rare, but just in case...
 7980            log::error!(
 7981                "multiple different run targets found on a single line, only the last target will be rendered"
 7982            )
 7983        }
 7984    }
 7985
 7986    /// Get all display points of breakpoints that will be rendered within editor
 7987    ///
 7988    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7989    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7990    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7991    fn active_breakpoints(
 7992        &self,
 7993        range: Range<DisplayRow>,
 7994        window: &mut Window,
 7995        cx: &mut Context<Self>,
 7996    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7997        let mut breakpoint_display_points = HashMap::default();
 7998
 7999        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8000            return breakpoint_display_points;
 8001        };
 8002
 8003        let snapshot = self.snapshot(window, cx);
 8004
 8005        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8006        let Some(project) = self.project() else {
 8007            return breakpoint_display_points;
 8008        };
 8009
 8010        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8011            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8012
 8013        for (buffer_snapshot, range, excerpt_id) in
 8014            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8015        {
 8016            let Some(buffer) = project
 8017                .read(cx)
 8018                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8019            else {
 8020                continue;
 8021            };
 8022            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8023                &buffer,
 8024                Some(
 8025                    buffer_snapshot.anchor_before(range.start)
 8026                        ..buffer_snapshot.anchor_after(range.end),
 8027                ),
 8028                buffer_snapshot,
 8029                cx,
 8030            );
 8031            for (breakpoint, state) in breakpoints {
 8032                let multi_buffer_anchor =
 8033                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8034                let position = multi_buffer_anchor
 8035                    .to_point(multi_buffer_snapshot)
 8036                    .to_display_point(&snapshot);
 8037
 8038                breakpoint_display_points.insert(
 8039                    position.row(),
 8040                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8041                );
 8042            }
 8043        }
 8044
 8045        breakpoint_display_points
 8046    }
 8047
 8048    fn breakpoint_context_menu(
 8049        &self,
 8050        anchor: Anchor,
 8051        window: &mut Window,
 8052        cx: &mut Context<Self>,
 8053    ) -> Entity<ui::ContextMenu> {
 8054        let weak_editor = cx.weak_entity();
 8055        let focus_handle = self.focus_handle(cx);
 8056
 8057        let row = self
 8058            .buffer
 8059            .read(cx)
 8060            .snapshot(cx)
 8061            .summary_for_anchor::<Point>(&anchor)
 8062            .row;
 8063
 8064        let breakpoint = self
 8065            .breakpoint_at_row(row, window, cx)
 8066            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8067
 8068        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8069            "Edit Log Breakpoint"
 8070        } else {
 8071            "Set Log Breakpoint"
 8072        };
 8073
 8074        let condition_breakpoint_msg = if breakpoint
 8075            .as_ref()
 8076            .is_some_and(|bp| bp.1.condition.is_some())
 8077        {
 8078            "Edit Condition Breakpoint"
 8079        } else {
 8080            "Set Condition Breakpoint"
 8081        };
 8082
 8083        let hit_condition_breakpoint_msg = if breakpoint
 8084            .as_ref()
 8085            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8086        {
 8087            "Edit Hit Condition Breakpoint"
 8088        } else {
 8089            "Set Hit Condition Breakpoint"
 8090        };
 8091
 8092        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8093            "Unset Breakpoint"
 8094        } else {
 8095            "Set Breakpoint"
 8096        };
 8097
 8098        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8099
 8100        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8101            BreakpointState::Enabled => Some("Disable"),
 8102            BreakpointState::Disabled => Some("Enable"),
 8103        });
 8104
 8105        let (anchor, breakpoint) =
 8106            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8107
 8108        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8109            menu.on_blur_subscription(Subscription::new(|| {}))
 8110                .context(focus_handle)
 8111                .when(run_to_cursor, |this| {
 8112                    let weak_editor = weak_editor.clone();
 8113                    this.entry("Run to cursor", None, move |window, cx| {
 8114                        weak_editor
 8115                            .update(cx, |editor, cx| {
 8116                                editor.change_selections(
 8117                                    SelectionEffects::no_scroll(),
 8118                                    window,
 8119                                    cx,
 8120                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8121                                );
 8122                            })
 8123                            .ok();
 8124
 8125                        window.dispatch_action(Box::new(RunToCursor), cx);
 8126                    })
 8127                    .separator()
 8128                })
 8129                .when_some(toggle_state_msg, |this, msg| {
 8130                    this.entry(msg, None, {
 8131                        let weak_editor = weak_editor.clone();
 8132                        let breakpoint = breakpoint.clone();
 8133                        move |_window, cx| {
 8134                            weak_editor
 8135                                .update(cx, |this, cx| {
 8136                                    this.edit_breakpoint_at_anchor(
 8137                                        anchor,
 8138                                        breakpoint.as_ref().clone(),
 8139                                        BreakpointEditAction::InvertState,
 8140                                        cx,
 8141                                    );
 8142                                })
 8143                                .log_err();
 8144                        }
 8145                    })
 8146                })
 8147                .entry(set_breakpoint_msg, None, {
 8148                    let weak_editor = weak_editor.clone();
 8149                    let breakpoint = breakpoint.clone();
 8150                    move |_window, cx| {
 8151                        weak_editor
 8152                            .update(cx, |this, cx| {
 8153                                this.edit_breakpoint_at_anchor(
 8154                                    anchor,
 8155                                    breakpoint.as_ref().clone(),
 8156                                    BreakpointEditAction::Toggle,
 8157                                    cx,
 8158                                );
 8159                            })
 8160                            .log_err();
 8161                    }
 8162                })
 8163                .entry(log_breakpoint_msg, None, {
 8164                    let breakpoint = breakpoint.clone();
 8165                    let weak_editor = weak_editor.clone();
 8166                    move |window, cx| {
 8167                        weak_editor
 8168                            .update(cx, |this, cx| {
 8169                                this.add_edit_breakpoint_block(
 8170                                    anchor,
 8171                                    breakpoint.as_ref(),
 8172                                    BreakpointPromptEditAction::Log,
 8173                                    window,
 8174                                    cx,
 8175                                );
 8176                            })
 8177                            .log_err();
 8178                    }
 8179                })
 8180                .entry(condition_breakpoint_msg, None, {
 8181                    let breakpoint = breakpoint.clone();
 8182                    let weak_editor = weak_editor.clone();
 8183                    move |window, cx| {
 8184                        weak_editor
 8185                            .update(cx, |this, cx| {
 8186                                this.add_edit_breakpoint_block(
 8187                                    anchor,
 8188                                    breakpoint.as_ref(),
 8189                                    BreakpointPromptEditAction::Condition,
 8190                                    window,
 8191                                    cx,
 8192                                );
 8193                            })
 8194                            .log_err();
 8195                    }
 8196                })
 8197                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8198                    weak_editor
 8199                        .update(cx, |this, cx| {
 8200                            this.add_edit_breakpoint_block(
 8201                                anchor,
 8202                                breakpoint.as_ref(),
 8203                                BreakpointPromptEditAction::HitCondition,
 8204                                window,
 8205                                cx,
 8206                            );
 8207                        })
 8208                        .log_err();
 8209                })
 8210        })
 8211    }
 8212
 8213    fn render_breakpoint(
 8214        &self,
 8215        position: Anchor,
 8216        row: DisplayRow,
 8217        breakpoint: &Breakpoint,
 8218        state: Option<BreakpointSessionState>,
 8219        cx: &mut Context<Self>,
 8220    ) -> IconButton {
 8221        let is_rejected = state.is_some_and(|s| !s.verified);
 8222        // Is it a breakpoint that shows up when hovering over gutter?
 8223        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8224            (false, false),
 8225            |PhantomBreakpointIndicator {
 8226                 is_active,
 8227                 display_row,
 8228                 collides_with_existing_breakpoint,
 8229             }| {
 8230                (
 8231                    is_active && display_row == row,
 8232                    collides_with_existing_breakpoint,
 8233                )
 8234            },
 8235        );
 8236
 8237        let (color, icon) = {
 8238            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8239                (false, false) => ui::IconName::DebugBreakpoint,
 8240                (true, false) => ui::IconName::DebugLogBreakpoint,
 8241                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8242                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8243            };
 8244
 8245            let color = if is_phantom {
 8246                Color::Hint
 8247            } else if is_rejected {
 8248                Color::Disabled
 8249            } else {
 8250                Color::Debugger
 8251            };
 8252
 8253            (color, icon)
 8254        };
 8255
 8256        let breakpoint = Arc::from(breakpoint.clone());
 8257
 8258        let alt_as_text = gpui::Keystroke {
 8259            modifiers: Modifiers::secondary_key(),
 8260            ..Default::default()
 8261        };
 8262        let primary_action_text = if breakpoint.is_disabled() {
 8263            "Enable breakpoint"
 8264        } else if is_phantom && !collides_with_existing {
 8265            "Set breakpoint"
 8266        } else {
 8267            "Unset breakpoint"
 8268        };
 8269        let focus_handle = self.focus_handle.clone();
 8270
 8271        let meta = if is_rejected {
 8272            SharedString::from("No executable code is associated with this line.")
 8273        } else if collides_with_existing && !breakpoint.is_disabled() {
 8274            SharedString::from(format!(
 8275                "{alt_as_text}-click to disable,\nright-click for more options."
 8276            ))
 8277        } else {
 8278            SharedString::from("Right-click for more options.")
 8279        };
 8280        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8281            .icon_size(IconSize::XSmall)
 8282            .size(ui::ButtonSize::None)
 8283            .when(is_rejected, |this| {
 8284                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8285            })
 8286            .icon_color(color)
 8287            .style(ButtonStyle::Transparent)
 8288            .on_click(cx.listener({
 8289                move |editor, event: &ClickEvent, window, cx| {
 8290                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8291                        BreakpointEditAction::InvertState
 8292                    } else {
 8293                        BreakpointEditAction::Toggle
 8294                    };
 8295
 8296                    window.focus(&editor.focus_handle(cx));
 8297                    editor.edit_breakpoint_at_anchor(
 8298                        position,
 8299                        breakpoint.as_ref().clone(),
 8300                        edit_action,
 8301                        cx,
 8302                    );
 8303                }
 8304            }))
 8305            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8306                editor.set_breakpoint_context_menu(
 8307                    row,
 8308                    Some(position),
 8309                    event.position(),
 8310                    window,
 8311                    cx,
 8312                );
 8313            }))
 8314            .tooltip(move |window, cx| {
 8315                Tooltip::with_meta_in(
 8316                    primary_action_text,
 8317                    Some(&ToggleBreakpoint),
 8318                    meta.clone(),
 8319                    &focus_handle,
 8320                    window,
 8321                    cx,
 8322                )
 8323            })
 8324    }
 8325
 8326    fn build_tasks_context(
 8327        project: &Entity<Project>,
 8328        buffer: &Entity<Buffer>,
 8329        buffer_row: u32,
 8330        tasks: &Arc<RunnableTasks>,
 8331        cx: &mut Context<Self>,
 8332    ) -> Task<Option<task::TaskContext>> {
 8333        let position = Point::new(buffer_row, tasks.column);
 8334        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8335        let location = Location {
 8336            buffer: buffer.clone(),
 8337            range: range_start..range_start,
 8338        };
 8339        // Fill in the environmental variables from the tree-sitter captures
 8340        let mut captured_task_variables = TaskVariables::default();
 8341        for (capture_name, value) in tasks.extra_variables.clone() {
 8342            captured_task_variables.insert(
 8343                task::VariableName::Custom(capture_name.into()),
 8344                value.clone(),
 8345            );
 8346        }
 8347        project.update(cx, |project, cx| {
 8348            project.task_store().update(cx, |task_store, cx| {
 8349                task_store.task_context_for_location(captured_task_variables, location, cx)
 8350            })
 8351        })
 8352    }
 8353
 8354    pub fn spawn_nearest_task(
 8355        &mut self,
 8356        action: &SpawnNearestTask,
 8357        window: &mut Window,
 8358        cx: &mut Context<Self>,
 8359    ) {
 8360        let Some((workspace, _)) = self.workspace.clone() else {
 8361            return;
 8362        };
 8363        let Some(project) = self.project.clone() else {
 8364            return;
 8365        };
 8366
 8367        // Try to find a closest, enclosing node using tree-sitter that has a task
 8368        let Some((buffer, buffer_row, tasks)) = self
 8369            .find_enclosing_node_task(cx)
 8370            // Or find the task that's closest in row-distance.
 8371            .or_else(|| self.find_closest_task(cx))
 8372        else {
 8373            return;
 8374        };
 8375
 8376        let reveal_strategy = action.reveal;
 8377        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8378        cx.spawn_in(window, async move |_, cx| {
 8379            let context = task_context.await?;
 8380            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8381
 8382            let resolved = &mut resolved_task.resolved;
 8383            resolved.reveal = reveal_strategy;
 8384
 8385            workspace
 8386                .update_in(cx, |workspace, window, cx| {
 8387                    workspace.schedule_resolved_task(
 8388                        task_source_kind,
 8389                        resolved_task,
 8390                        false,
 8391                        window,
 8392                        cx,
 8393                    );
 8394                })
 8395                .ok()
 8396        })
 8397        .detach();
 8398    }
 8399
 8400    fn find_closest_task(
 8401        &mut self,
 8402        cx: &mut Context<Self>,
 8403    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8404        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8405
 8406        let ((buffer_id, row), tasks) = self
 8407            .tasks
 8408            .iter()
 8409            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8410
 8411        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8412        let tasks = Arc::new(tasks.to_owned());
 8413        Some((buffer, *row, tasks))
 8414    }
 8415
 8416    fn find_enclosing_node_task(
 8417        &mut self,
 8418        cx: &mut Context<Self>,
 8419    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8420        let snapshot = self.buffer.read(cx).snapshot(cx);
 8421        let offset = self.selections.newest::<usize>(cx).head();
 8422        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8423        let buffer_id = excerpt.buffer().remote_id();
 8424
 8425        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8426        let mut cursor = layer.node().walk();
 8427
 8428        while cursor.goto_first_child_for_byte(offset).is_some() {
 8429            if cursor.node().end_byte() == offset {
 8430                cursor.goto_next_sibling();
 8431            }
 8432        }
 8433
 8434        // Ascend to the smallest ancestor that contains the range and has a task.
 8435        loop {
 8436            let node = cursor.node();
 8437            let node_range = node.byte_range();
 8438            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8439
 8440            // Check if this node contains our offset
 8441            if node_range.start <= offset && node_range.end >= offset {
 8442                // If it contains offset, check for task
 8443                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8444                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8445                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8446                }
 8447            }
 8448
 8449            if !cursor.goto_parent() {
 8450                break;
 8451            }
 8452        }
 8453        None
 8454    }
 8455
 8456    fn render_run_indicator(
 8457        &self,
 8458        _style: &EditorStyle,
 8459        is_active: bool,
 8460        row: DisplayRow,
 8461        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8462        cx: &mut Context<Self>,
 8463    ) -> IconButton {
 8464        let color = Color::Muted;
 8465        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8466
 8467        IconButton::new(
 8468            ("run_indicator", row.0 as usize),
 8469            ui::IconName::PlayOutlined,
 8470        )
 8471        .shape(ui::IconButtonShape::Square)
 8472        .icon_size(IconSize::XSmall)
 8473        .icon_color(color)
 8474        .toggle_state(is_active)
 8475        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8476            let quick_launch = match e {
 8477                ClickEvent::Keyboard(_) => true,
 8478                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8479            };
 8480
 8481            window.focus(&editor.focus_handle(cx));
 8482            editor.toggle_code_actions(
 8483                &ToggleCodeActions {
 8484                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8485                    quick_launch,
 8486                },
 8487                window,
 8488                cx,
 8489            );
 8490        }))
 8491        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8492            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8493        }))
 8494    }
 8495
 8496    pub fn context_menu_visible(&self) -> bool {
 8497        !self.edit_prediction_preview_is_active()
 8498            && self
 8499                .context_menu
 8500                .borrow()
 8501                .as_ref()
 8502                .is_some_and(|menu| menu.visible())
 8503    }
 8504
 8505    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8506        self.context_menu
 8507            .borrow()
 8508            .as_ref()
 8509            .map(|menu| menu.origin())
 8510    }
 8511
 8512    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8513        self.context_menu_options = Some(options);
 8514    }
 8515
 8516    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8517    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8518
 8519    fn render_edit_prediction_popover(
 8520        &mut self,
 8521        text_bounds: &Bounds<Pixels>,
 8522        content_origin: gpui::Point<Pixels>,
 8523        right_margin: Pixels,
 8524        editor_snapshot: &EditorSnapshot,
 8525        visible_row_range: Range<DisplayRow>,
 8526        scroll_top: f32,
 8527        scroll_bottom: f32,
 8528        line_layouts: &[LineWithInvisibles],
 8529        line_height: Pixels,
 8530        scroll_pixel_position: gpui::Point<Pixels>,
 8531        newest_selection_head: Option<DisplayPoint>,
 8532        editor_width: Pixels,
 8533        style: &EditorStyle,
 8534        window: &mut Window,
 8535        cx: &mut App,
 8536    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8537        if self.mode().is_minimap() {
 8538            return None;
 8539        }
 8540        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8541
 8542        if self.edit_prediction_visible_in_cursor_popover(true) {
 8543            return None;
 8544        }
 8545
 8546        match &active_edit_prediction.completion {
 8547            EditPrediction::Move { target, .. } => {
 8548                let target_display_point = target.to_display_point(editor_snapshot);
 8549
 8550                if self.edit_prediction_requires_modifier() {
 8551                    if !self.edit_prediction_preview_is_active() {
 8552                        return None;
 8553                    }
 8554
 8555                    self.render_edit_prediction_modifier_jump_popover(
 8556                        text_bounds,
 8557                        content_origin,
 8558                        visible_row_range,
 8559                        line_layouts,
 8560                        line_height,
 8561                        scroll_pixel_position,
 8562                        newest_selection_head,
 8563                        target_display_point,
 8564                        window,
 8565                        cx,
 8566                    )
 8567                } else {
 8568                    self.render_edit_prediction_eager_jump_popover(
 8569                        text_bounds,
 8570                        content_origin,
 8571                        editor_snapshot,
 8572                        visible_row_range,
 8573                        scroll_top,
 8574                        scroll_bottom,
 8575                        line_height,
 8576                        scroll_pixel_position,
 8577                        target_display_point,
 8578                        editor_width,
 8579                        window,
 8580                        cx,
 8581                    )
 8582                }
 8583            }
 8584            EditPrediction::Edit {
 8585                display_mode: EditDisplayMode::Inline,
 8586                ..
 8587            } => None,
 8588            EditPrediction::Edit {
 8589                display_mode: EditDisplayMode::TabAccept,
 8590                edits,
 8591                ..
 8592            } => {
 8593                let range = &edits.first()?.0;
 8594                let target_display_point = range.end.to_display_point(editor_snapshot);
 8595
 8596                self.render_edit_prediction_end_of_line_popover(
 8597                    "Accept",
 8598                    editor_snapshot,
 8599                    visible_row_range,
 8600                    target_display_point,
 8601                    line_height,
 8602                    scroll_pixel_position,
 8603                    content_origin,
 8604                    editor_width,
 8605                    window,
 8606                    cx,
 8607                )
 8608            }
 8609            EditPrediction::Edit {
 8610                edits,
 8611                edit_preview,
 8612                display_mode: EditDisplayMode::DiffPopover,
 8613                snapshot,
 8614            } => self.render_edit_prediction_diff_popover(
 8615                text_bounds,
 8616                content_origin,
 8617                right_margin,
 8618                editor_snapshot,
 8619                visible_row_range,
 8620                line_layouts,
 8621                line_height,
 8622                scroll_pixel_position,
 8623                newest_selection_head,
 8624                editor_width,
 8625                style,
 8626                edits,
 8627                edit_preview,
 8628                snapshot,
 8629                window,
 8630                cx,
 8631            ),
 8632        }
 8633    }
 8634
 8635    fn render_edit_prediction_modifier_jump_popover(
 8636        &mut self,
 8637        text_bounds: &Bounds<Pixels>,
 8638        content_origin: gpui::Point<Pixels>,
 8639        visible_row_range: Range<DisplayRow>,
 8640        line_layouts: &[LineWithInvisibles],
 8641        line_height: Pixels,
 8642        scroll_pixel_position: gpui::Point<Pixels>,
 8643        newest_selection_head: Option<DisplayPoint>,
 8644        target_display_point: DisplayPoint,
 8645        window: &mut Window,
 8646        cx: &mut App,
 8647    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8648        let scrolled_content_origin =
 8649            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8650
 8651        const SCROLL_PADDING_Y: Pixels = px(12.);
 8652
 8653        if target_display_point.row() < visible_row_range.start {
 8654            return self.render_edit_prediction_scroll_popover(
 8655                |_| SCROLL_PADDING_Y,
 8656                IconName::ArrowUp,
 8657                visible_row_range,
 8658                line_layouts,
 8659                newest_selection_head,
 8660                scrolled_content_origin,
 8661                window,
 8662                cx,
 8663            );
 8664        } else if target_display_point.row() >= visible_row_range.end {
 8665            return self.render_edit_prediction_scroll_popover(
 8666                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8667                IconName::ArrowDown,
 8668                visible_row_range,
 8669                line_layouts,
 8670                newest_selection_head,
 8671                scrolled_content_origin,
 8672                window,
 8673                cx,
 8674            );
 8675        }
 8676
 8677        const POLE_WIDTH: Pixels = px(2.);
 8678
 8679        let line_layout =
 8680            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8681        let target_column = target_display_point.column() as usize;
 8682
 8683        let target_x = line_layout.x_for_index(target_column);
 8684        let target_y =
 8685            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8686
 8687        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8688
 8689        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8690        border_color.l += 0.001;
 8691
 8692        let mut element = v_flex()
 8693            .items_end()
 8694            .when(flag_on_right, |el| el.items_start())
 8695            .child(if flag_on_right {
 8696                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8697                    .rounded_bl(px(0.))
 8698                    .rounded_tl(px(0.))
 8699                    .border_l_2()
 8700                    .border_color(border_color)
 8701            } else {
 8702                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8703                    .rounded_br(px(0.))
 8704                    .rounded_tr(px(0.))
 8705                    .border_r_2()
 8706                    .border_color(border_color)
 8707            })
 8708            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8709            .into_any();
 8710
 8711        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8712
 8713        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8714            - point(
 8715                if flag_on_right {
 8716                    POLE_WIDTH
 8717                } else {
 8718                    size.width - POLE_WIDTH
 8719                },
 8720                size.height - line_height,
 8721            );
 8722
 8723        origin.x = origin.x.max(content_origin.x);
 8724
 8725        element.prepaint_at(origin, window, cx);
 8726
 8727        Some((element, origin))
 8728    }
 8729
 8730    fn render_edit_prediction_scroll_popover(
 8731        &mut self,
 8732        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8733        scroll_icon: IconName,
 8734        visible_row_range: Range<DisplayRow>,
 8735        line_layouts: &[LineWithInvisibles],
 8736        newest_selection_head: Option<DisplayPoint>,
 8737        scrolled_content_origin: gpui::Point<Pixels>,
 8738        window: &mut Window,
 8739        cx: &mut App,
 8740    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8741        let mut element = self
 8742            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8743            .into_any();
 8744
 8745        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8746
 8747        let cursor = newest_selection_head?;
 8748        let cursor_row_layout =
 8749            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8750        let cursor_column = cursor.column() as usize;
 8751
 8752        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8753
 8754        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8755
 8756        element.prepaint_at(origin, window, cx);
 8757        Some((element, origin))
 8758    }
 8759
 8760    fn render_edit_prediction_eager_jump_popover(
 8761        &mut self,
 8762        text_bounds: &Bounds<Pixels>,
 8763        content_origin: gpui::Point<Pixels>,
 8764        editor_snapshot: &EditorSnapshot,
 8765        visible_row_range: Range<DisplayRow>,
 8766        scroll_top: f32,
 8767        scroll_bottom: f32,
 8768        line_height: Pixels,
 8769        scroll_pixel_position: gpui::Point<Pixels>,
 8770        target_display_point: DisplayPoint,
 8771        editor_width: Pixels,
 8772        window: &mut Window,
 8773        cx: &mut App,
 8774    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8775        if target_display_point.row().as_f32() < scroll_top {
 8776            let mut element = self
 8777                .render_edit_prediction_line_popover(
 8778                    "Jump to Edit",
 8779                    Some(IconName::ArrowUp),
 8780                    window,
 8781                    cx,
 8782                )?
 8783                .into_any();
 8784
 8785            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8786            let offset = point(
 8787                (text_bounds.size.width - size.width) / 2.,
 8788                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8789            );
 8790
 8791            let origin = text_bounds.origin + offset;
 8792            element.prepaint_at(origin, window, cx);
 8793            Some((element, origin))
 8794        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8795            let mut element = self
 8796                .render_edit_prediction_line_popover(
 8797                    "Jump to Edit",
 8798                    Some(IconName::ArrowDown),
 8799                    window,
 8800                    cx,
 8801                )?
 8802                .into_any();
 8803
 8804            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8805            let offset = point(
 8806                (text_bounds.size.width - size.width) / 2.,
 8807                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8808            );
 8809
 8810            let origin = text_bounds.origin + offset;
 8811            element.prepaint_at(origin, window, cx);
 8812            Some((element, origin))
 8813        } else {
 8814            self.render_edit_prediction_end_of_line_popover(
 8815                "Jump to Edit",
 8816                editor_snapshot,
 8817                visible_row_range,
 8818                target_display_point,
 8819                line_height,
 8820                scroll_pixel_position,
 8821                content_origin,
 8822                editor_width,
 8823                window,
 8824                cx,
 8825            )
 8826        }
 8827    }
 8828
 8829    fn render_edit_prediction_end_of_line_popover(
 8830        self: &mut Editor,
 8831        label: &'static str,
 8832        editor_snapshot: &EditorSnapshot,
 8833        visible_row_range: Range<DisplayRow>,
 8834        target_display_point: DisplayPoint,
 8835        line_height: Pixels,
 8836        scroll_pixel_position: gpui::Point<Pixels>,
 8837        content_origin: gpui::Point<Pixels>,
 8838        editor_width: Pixels,
 8839        window: &mut Window,
 8840        cx: &mut App,
 8841    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8842        let target_line_end = DisplayPoint::new(
 8843            target_display_point.row(),
 8844            editor_snapshot.line_len(target_display_point.row()),
 8845        );
 8846
 8847        let mut element = self
 8848            .render_edit_prediction_line_popover(label, None, window, cx)?
 8849            .into_any();
 8850
 8851        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8852
 8853        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8854
 8855        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8856        let mut origin = start_point
 8857            + line_origin
 8858            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8859        origin.x = origin.x.max(content_origin.x);
 8860
 8861        let max_x = content_origin.x + editor_width - size.width;
 8862
 8863        if origin.x > max_x {
 8864            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8865
 8866            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8867                origin.y += offset;
 8868                IconName::ArrowUp
 8869            } else {
 8870                origin.y -= offset;
 8871                IconName::ArrowDown
 8872            };
 8873
 8874            element = self
 8875                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8876                .into_any();
 8877
 8878            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8879
 8880            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8881        }
 8882
 8883        element.prepaint_at(origin, window, cx);
 8884        Some((element, origin))
 8885    }
 8886
 8887    fn render_edit_prediction_diff_popover(
 8888        self: &Editor,
 8889        text_bounds: &Bounds<Pixels>,
 8890        content_origin: gpui::Point<Pixels>,
 8891        right_margin: Pixels,
 8892        editor_snapshot: &EditorSnapshot,
 8893        visible_row_range: Range<DisplayRow>,
 8894        line_layouts: &[LineWithInvisibles],
 8895        line_height: Pixels,
 8896        scroll_pixel_position: gpui::Point<Pixels>,
 8897        newest_selection_head: Option<DisplayPoint>,
 8898        editor_width: Pixels,
 8899        style: &EditorStyle,
 8900        edits: &Vec<(Range<Anchor>, String)>,
 8901        edit_preview: &Option<language::EditPreview>,
 8902        snapshot: &language::BufferSnapshot,
 8903        window: &mut Window,
 8904        cx: &mut App,
 8905    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8906        let edit_start = edits
 8907            .first()
 8908            .unwrap()
 8909            .0
 8910            .start
 8911            .to_display_point(editor_snapshot);
 8912        let edit_end = edits
 8913            .last()
 8914            .unwrap()
 8915            .0
 8916            .end
 8917            .to_display_point(editor_snapshot);
 8918
 8919        let is_visible = visible_row_range.contains(&edit_start.row())
 8920            || visible_row_range.contains(&edit_end.row());
 8921        if !is_visible {
 8922            return None;
 8923        }
 8924
 8925        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8926            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8927        } else {
 8928            // Fallback for providers without edit_preview
 8929            crate::edit_prediction_fallback_text(edits, cx)
 8930        };
 8931
 8932        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8933        let line_count = highlighted_edits.text.lines().count();
 8934
 8935        const BORDER_WIDTH: Pixels = px(1.);
 8936
 8937        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8938        let has_keybind = keybind.is_some();
 8939
 8940        let mut element = h_flex()
 8941            .items_start()
 8942            .child(
 8943                h_flex()
 8944                    .bg(cx.theme().colors().editor_background)
 8945                    .border(BORDER_WIDTH)
 8946                    .shadow_xs()
 8947                    .border_color(cx.theme().colors().border)
 8948                    .rounded_l_lg()
 8949                    .when(line_count > 1, |el| el.rounded_br_lg())
 8950                    .pr_1()
 8951                    .child(styled_text),
 8952            )
 8953            .child(
 8954                h_flex()
 8955                    .h(line_height + BORDER_WIDTH * 2.)
 8956                    .px_1p5()
 8957                    .gap_1()
 8958                    // Workaround: For some reason, there's a gap if we don't do this
 8959                    .ml(-BORDER_WIDTH)
 8960                    .shadow(vec![gpui::BoxShadow {
 8961                        color: gpui::black().opacity(0.05),
 8962                        offset: point(px(1.), px(1.)),
 8963                        blur_radius: px(2.),
 8964                        spread_radius: px(0.),
 8965                    }])
 8966                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8967                    .border(BORDER_WIDTH)
 8968                    .border_color(cx.theme().colors().border)
 8969                    .rounded_r_lg()
 8970                    .id("edit_prediction_diff_popover_keybind")
 8971                    .when(!has_keybind, |el| {
 8972                        let status_colors = cx.theme().status();
 8973
 8974                        el.bg(status_colors.error_background)
 8975                            .border_color(status_colors.error.opacity(0.6))
 8976                            .child(Icon::new(IconName::Info).color(Color::Error))
 8977                            .cursor_default()
 8978                            .hoverable_tooltip(move |_window, cx| {
 8979                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8980                            })
 8981                    })
 8982                    .children(keybind),
 8983            )
 8984            .into_any();
 8985
 8986        let longest_row =
 8987            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8988        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8989            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8990        } else {
 8991            layout_line(
 8992                longest_row,
 8993                editor_snapshot,
 8994                style,
 8995                editor_width,
 8996                |_| false,
 8997                window,
 8998                cx,
 8999            )
 9000            .width
 9001        };
 9002
 9003        let viewport_bounds =
 9004            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9005                right: -right_margin,
 9006                ..Default::default()
 9007            });
 9008
 9009        let x_after_longest =
 9010            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9011                - scroll_pixel_position.x;
 9012
 9013        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9014
 9015        // Fully visible if it can be displayed within the window (allow overlapping other
 9016        // panes). However, this is only allowed if the popover starts within text_bounds.
 9017        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9018            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9019
 9020        let mut origin = if can_position_to_the_right {
 9021            point(
 9022                x_after_longest,
 9023                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9024                    - scroll_pixel_position.y,
 9025            )
 9026        } else {
 9027            let cursor_row = newest_selection_head.map(|head| head.row());
 9028            let above_edit = edit_start
 9029                .row()
 9030                .0
 9031                .checked_sub(line_count as u32)
 9032                .map(DisplayRow);
 9033            let below_edit = Some(edit_end.row() + 1);
 9034            let above_cursor =
 9035                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9036            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9037
 9038            // Place the edit popover adjacent to the edit if there is a location
 9039            // available that is onscreen and does not obscure the cursor. Otherwise,
 9040            // place it adjacent to the cursor.
 9041            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9042                .into_iter()
 9043                .flatten()
 9044                .find(|&start_row| {
 9045                    let end_row = start_row + line_count as u32;
 9046                    visible_row_range.contains(&start_row)
 9047                        && visible_row_range.contains(&end_row)
 9048                        && cursor_row
 9049                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9050                })?;
 9051
 9052            content_origin
 9053                + point(
 9054                    -scroll_pixel_position.x,
 9055                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9056                )
 9057        };
 9058
 9059        origin.x -= BORDER_WIDTH;
 9060
 9061        window.defer_draw(element, origin, 1);
 9062
 9063        // Do not return an element, since it will already be drawn due to defer_draw.
 9064        None
 9065    }
 9066
 9067    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9068        px(30.)
 9069    }
 9070
 9071    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9072        if self.read_only(cx) {
 9073            cx.theme().players().read_only()
 9074        } else {
 9075            self.style.as_ref().unwrap().local_player
 9076        }
 9077    }
 9078
 9079    fn render_edit_prediction_accept_keybind(
 9080        &self,
 9081        window: &mut Window,
 9082        cx: &App,
 9083    ) -> Option<AnyElement> {
 9084        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9085        let accept_keystroke = accept_binding.keystroke()?;
 9086
 9087        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9088
 9089        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9090            Color::Accent
 9091        } else {
 9092            Color::Muted
 9093        };
 9094
 9095        h_flex()
 9096            .px_0p5()
 9097            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9098            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9099            .text_size(TextSize::XSmall.rems(cx))
 9100            .child(h_flex().children(ui::render_modifiers(
 9101                accept_keystroke.modifiers(),
 9102                PlatformStyle::platform(),
 9103                Some(modifiers_color),
 9104                Some(IconSize::XSmall.rems().into()),
 9105                true,
 9106            )))
 9107            .when(is_platform_style_mac, |parent| {
 9108                parent.child(accept_keystroke.key().to_string())
 9109            })
 9110            .when(!is_platform_style_mac, |parent| {
 9111                parent.child(
 9112                    Key::new(
 9113                        util::capitalize(accept_keystroke.key()),
 9114                        Some(Color::Default),
 9115                    )
 9116                    .size(Some(IconSize::XSmall.rems().into())),
 9117                )
 9118            })
 9119            .into_any()
 9120            .into()
 9121    }
 9122
 9123    fn render_edit_prediction_line_popover(
 9124        &self,
 9125        label: impl Into<SharedString>,
 9126        icon: Option<IconName>,
 9127        window: &mut Window,
 9128        cx: &App,
 9129    ) -> Option<Stateful<Div>> {
 9130        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9131
 9132        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9133        let has_keybind = keybind.is_some();
 9134
 9135        let result = h_flex()
 9136            .id("ep-line-popover")
 9137            .py_0p5()
 9138            .pl_1()
 9139            .pr(padding_right)
 9140            .gap_1()
 9141            .rounded_md()
 9142            .border_1()
 9143            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9144            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9145            .shadow_xs()
 9146            .when(!has_keybind, |el| {
 9147                let status_colors = cx.theme().status();
 9148
 9149                el.bg(status_colors.error_background)
 9150                    .border_color(status_colors.error.opacity(0.6))
 9151                    .pl_2()
 9152                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9153                    .cursor_default()
 9154                    .hoverable_tooltip(move |_window, cx| {
 9155                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9156                    })
 9157            })
 9158            .children(keybind)
 9159            .child(
 9160                Label::new(label)
 9161                    .size(LabelSize::Small)
 9162                    .when(!has_keybind, |el| {
 9163                        el.color(cx.theme().status().error.into()).strikethrough()
 9164                    }),
 9165            )
 9166            .when(!has_keybind, |el| {
 9167                el.child(
 9168                    h_flex().ml_1().child(
 9169                        Icon::new(IconName::Info)
 9170                            .size(IconSize::Small)
 9171                            .color(cx.theme().status().error.into()),
 9172                    ),
 9173                )
 9174            })
 9175            .when_some(icon, |element, icon| {
 9176                element.child(
 9177                    div()
 9178                        .mt(px(1.5))
 9179                        .child(Icon::new(icon).size(IconSize::Small)),
 9180                )
 9181            });
 9182
 9183        Some(result)
 9184    }
 9185
 9186    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9187        let accent_color = cx.theme().colors().text_accent;
 9188        let editor_bg_color = cx.theme().colors().editor_background;
 9189        editor_bg_color.blend(accent_color.opacity(0.1))
 9190    }
 9191
 9192    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9193        let accent_color = cx.theme().colors().text_accent;
 9194        let editor_bg_color = cx.theme().colors().editor_background;
 9195        editor_bg_color.blend(accent_color.opacity(0.6))
 9196    }
 9197    fn get_prediction_provider_icon_name(
 9198        provider: &Option<RegisteredEditPredictionProvider>,
 9199    ) -> IconName {
 9200        match provider {
 9201            Some(provider) => match provider.provider.name() {
 9202                "copilot" => IconName::Copilot,
 9203                "supermaven" => IconName::Supermaven,
 9204                _ => IconName::ZedPredict,
 9205            },
 9206            None => IconName::ZedPredict,
 9207        }
 9208    }
 9209
 9210    fn render_edit_prediction_cursor_popover(
 9211        &self,
 9212        min_width: Pixels,
 9213        max_width: Pixels,
 9214        cursor_point: Point,
 9215        style: &EditorStyle,
 9216        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9217        _window: &Window,
 9218        cx: &mut Context<Editor>,
 9219    ) -> Option<AnyElement> {
 9220        let provider = self.edit_prediction_provider.as_ref()?;
 9221        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9222
 9223        let is_refreshing = provider.provider.is_refreshing(cx);
 9224
 9225        fn pending_completion_container(icon: IconName) -> Div {
 9226            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9227        }
 9228
 9229        let completion = match &self.active_edit_prediction {
 9230            Some(prediction) => {
 9231                if !self.has_visible_completions_menu() {
 9232                    const RADIUS: Pixels = px(6.);
 9233                    const BORDER_WIDTH: Pixels = px(1.);
 9234
 9235                    return Some(
 9236                        h_flex()
 9237                            .elevation_2(cx)
 9238                            .border(BORDER_WIDTH)
 9239                            .border_color(cx.theme().colors().border)
 9240                            .when(accept_keystroke.is_none(), |el| {
 9241                                el.border_color(cx.theme().status().error)
 9242                            })
 9243                            .rounded(RADIUS)
 9244                            .rounded_tl(px(0.))
 9245                            .overflow_hidden()
 9246                            .child(div().px_1p5().child(match &prediction.completion {
 9247                                EditPrediction::Move { target, snapshot } => {
 9248                                    use text::ToPoint as _;
 9249                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9250                                    {
 9251                                        Icon::new(IconName::ZedPredictDown)
 9252                                    } else {
 9253                                        Icon::new(IconName::ZedPredictUp)
 9254                                    }
 9255                                }
 9256                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9257                            }))
 9258                            .child(
 9259                                h_flex()
 9260                                    .gap_1()
 9261                                    .py_1()
 9262                                    .px_2()
 9263                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9264                                    .border_l_1()
 9265                                    .border_color(cx.theme().colors().border)
 9266                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9267                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9268                                        el.child(
 9269                                            Label::new("Hold")
 9270                                                .size(LabelSize::Small)
 9271                                                .when(accept_keystroke.is_none(), |el| {
 9272                                                    el.strikethrough()
 9273                                                })
 9274                                                .line_height_style(LineHeightStyle::UiLabel),
 9275                                        )
 9276                                    })
 9277                                    .id("edit_prediction_cursor_popover_keybind")
 9278                                    .when(accept_keystroke.is_none(), |el| {
 9279                                        let status_colors = cx.theme().status();
 9280
 9281                                        el.bg(status_colors.error_background)
 9282                                            .border_color(status_colors.error.opacity(0.6))
 9283                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9284                                            .cursor_default()
 9285                                            .hoverable_tooltip(move |_window, cx| {
 9286                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9287                                                    .into()
 9288                                            })
 9289                                    })
 9290                                    .when_some(
 9291                                        accept_keystroke.as_ref(),
 9292                                        |el, accept_keystroke| {
 9293                                            el.child(h_flex().children(ui::render_modifiers(
 9294                                                accept_keystroke.modifiers(),
 9295                                                PlatformStyle::platform(),
 9296                                                Some(Color::Default),
 9297                                                Some(IconSize::XSmall.rems().into()),
 9298                                                false,
 9299                                            )))
 9300                                        },
 9301                                    ),
 9302                            )
 9303                            .into_any(),
 9304                    );
 9305                }
 9306
 9307                self.render_edit_prediction_cursor_popover_preview(
 9308                    prediction,
 9309                    cursor_point,
 9310                    style,
 9311                    cx,
 9312                )?
 9313            }
 9314
 9315            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9316                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9317                    stale_completion,
 9318                    cursor_point,
 9319                    style,
 9320                    cx,
 9321                )?,
 9322
 9323                None => pending_completion_container(provider_icon)
 9324                    .child(Label::new("...").size(LabelSize::Small)),
 9325            },
 9326
 9327            None => pending_completion_container(provider_icon)
 9328                .child(Label::new("...").size(LabelSize::Small)),
 9329        };
 9330
 9331        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9332            completion
 9333                .with_animation(
 9334                    "loading-completion",
 9335                    Animation::new(Duration::from_secs(2))
 9336                        .repeat()
 9337                        .with_easing(pulsating_between(0.4, 0.8)),
 9338                    |label, delta| label.opacity(delta),
 9339                )
 9340                .into_any_element()
 9341        } else {
 9342            completion.into_any_element()
 9343        };
 9344
 9345        let has_completion = self.active_edit_prediction.is_some();
 9346
 9347        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9348        Some(
 9349            h_flex()
 9350                .min_w(min_width)
 9351                .max_w(max_width)
 9352                .flex_1()
 9353                .elevation_2(cx)
 9354                .border_color(cx.theme().colors().border)
 9355                .child(
 9356                    div()
 9357                        .flex_1()
 9358                        .py_1()
 9359                        .px_2()
 9360                        .overflow_hidden()
 9361                        .child(completion),
 9362                )
 9363                .when_some(accept_keystroke, |el, accept_keystroke| {
 9364                    if !accept_keystroke.modifiers().modified() {
 9365                        return el;
 9366                    }
 9367
 9368                    el.child(
 9369                        h_flex()
 9370                            .h_full()
 9371                            .border_l_1()
 9372                            .rounded_r_lg()
 9373                            .border_color(cx.theme().colors().border)
 9374                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9375                            .gap_1()
 9376                            .py_1()
 9377                            .px_2()
 9378                            .child(
 9379                                h_flex()
 9380                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9381                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9382                                    .child(h_flex().children(ui::render_modifiers(
 9383                                        accept_keystroke.modifiers(),
 9384                                        PlatformStyle::platform(),
 9385                                        Some(if !has_completion {
 9386                                            Color::Muted
 9387                                        } else {
 9388                                            Color::Default
 9389                                        }),
 9390                                        None,
 9391                                        false,
 9392                                    ))),
 9393                            )
 9394                            .child(Label::new("Preview").into_any_element())
 9395                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9396                    )
 9397                })
 9398                .into_any(),
 9399        )
 9400    }
 9401
 9402    fn render_edit_prediction_cursor_popover_preview(
 9403        &self,
 9404        completion: &EditPredictionState,
 9405        cursor_point: Point,
 9406        style: &EditorStyle,
 9407        cx: &mut Context<Editor>,
 9408    ) -> Option<Div> {
 9409        use text::ToPoint as _;
 9410
 9411        fn render_relative_row_jump(
 9412            prefix: impl Into<String>,
 9413            current_row: u32,
 9414            target_row: u32,
 9415        ) -> Div {
 9416            let (row_diff, arrow) = if target_row < current_row {
 9417                (current_row - target_row, IconName::ArrowUp)
 9418            } else {
 9419                (target_row - current_row, IconName::ArrowDown)
 9420            };
 9421
 9422            h_flex()
 9423                .child(
 9424                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9425                        .color(Color::Muted)
 9426                        .size(LabelSize::Small),
 9427                )
 9428                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9429        }
 9430
 9431        let supports_jump = self
 9432            .edit_prediction_provider
 9433            .as_ref()
 9434            .map(|provider| provider.provider.supports_jump_to_edit())
 9435            .unwrap_or(true);
 9436
 9437        match &completion.completion {
 9438            EditPrediction::Move {
 9439                target, snapshot, ..
 9440            } => {
 9441                if !supports_jump {
 9442                    return None;
 9443                }
 9444
 9445                Some(
 9446                    h_flex()
 9447                        .px_2()
 9448                        .gap_2()
 9449                        .flex_1()
 9450                        .child(
 9451                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9452                                Icon::new(IconName::ZedPredictDown)
 9453                            } else {
 9454                                Icon::new(IconName::ZedPredictUp)
 9455                            },
 9456                        )
 9457                        .child(Label::new("Jump to Edit")),
 9458                )
 9459            }
 9460
 9461            EditPrediction::Edit {
 9462                edits,
 9463                edit_preview,
 9464                snapshot,
 9465                display_mode: _,
 9466            } => {
 9467                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9468
 9469                let (highlighted_edits, has_more_lines) =
 9470                    if let Some(edit_preview) = edit_preview.as_ref() {
 9471                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9472                            .first_line_preview()
 9473                    } else {
 9474                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9475                    };
 9476
 9477                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9478                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9479
 9480                let preview = h_flex()
 9481                    .gap_1()
 9482                    .min_w_16()
 9483                    .child(styled_text)
 9484                    .when(has_more_lines, |parent| parent.child(""));
 9485
 9486                let left = if supports_jump && first_edit_row != cursor_point.row {
 9487                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9488                        .into_any_element()
 9489                } else {
 9490                    let icon_name =
 9491                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9492                    Icon::new(icon_name).into_any_element()
 9493                };
 9494
 9495                Some(
 9496                    h_flex()
 9497                        .h_full()
 9498                        .flex_1()
 9499                        .gap_2()
 9500                        .pr_1()
 9501                        .overflow_x_hidden()
 9502                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9503                        .child(left)
 9504                        .child(preview),
 9505                )
 9506            }
 9507        }
 9508    }
 9509
 9510    pub fn render_context_menu(
 9511        &self,
 9512        style: &EditorStyle,
 9513        max_height_in_lines: u32,
 9514        window: &mut Window,
 9515        cx: &mut Context<Editor>,
 9516    ) -> Option<AnyElement> {
 9517        let menu = self.context_menu.borrow();
 9518        let menu = menu.as_ref()?;
 9519        if !menu.visible() {
 9520            return None;
 9521        };
 9522        Some(menu.render(style, max_height_in_lines, window, cx))
 9523    }
 9524
 9525    fn render_context_menu_aside(
 9526        &mut self,
 9527        max_size: Size<Pixels>,
 9528        window: &mut Window,
 9529        cx: &mut Context<Editor>,
 9530    ) -> Option<AnyElement> {
 9531        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9532            if menu.visible() {
 9533                menu.render_aside(max_size, window, cx)
 9534            } else {
 9535                None
 9536            }
 9537        })
 9538    }
 9539
 9540    fn hide_context_menu(
 9541        &mut self,
 9542        window: &mut Window,
 9543        cx: &mut Context<Self>,
 9544    ) -> Option<CodeContextMenu> {
 9545        cx.notify();
 9546        self.completion_tasks.clear();
 9547        let context_menu = self.context_menu.borrow_mut().take();
 9548        self.stale_edit_prediction_in_menu.take();
 9549        self.update_visible_edit_prediction(window, cx);
 9550        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9551            && let Some(completion_provider) = &self.completion_provider
 9552        {
 9553            completion_provider.selection_changed(None, window, cx);
 9554        }
 9555        context_menu
 9556    }
 9557
 9558    fn show_snippet_choices(
 9559        &mut self,
 9560        choices: &Vec<String>,
 9561        selection: Range<Anchor>,
 9562        cx: &mut Context<Self>,
 9563    ) {
 9564        let Some((_, buffer, _)) = self
 9565            .buffer()
 9566            .read(cx)
 9567            .excerpt_containing(selection.start, cx)
 9568        else {
 9569            return;
 9570        };
 9571        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9572        else {
 9573            return;
 9574        };
 9575        if buffer != end_buffer {
 9576            log::error!("expected anchor range to have matching buffer IDs");
 9577            return;
 9578        }
 9579
 9580        let id = post_inc(&mut self.next_completion_id);
 9581        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9582        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9583            CompletionsMenu::new_snippet_choices(
 9584                id,
 9585                true,
 9586                choices,
 9587                selection,
 9588                buffer,
 9589                snippet_sort_order,
 9590            ),
 9591        ));
 9592    }
 9593
 9594    pub fn insert_snippet(
 9595        &mut self,
 9596        insertion_ranges: &[Range<usize>],
 9597        snippet: Snippet,
 9598        window: &mut Window,
 9599        cx: &mut Context<Self>,
 9600    ) -> Result<()> {
 9601        struct Tabstop<T> {
 9602            is_end_tabstop: bool,
 9603            ranges: Vec<Range<T>>,
 9604            choices: Option<Vec<String>>,
 9605        }
 9606
 9607        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9608            let snippet_text: Arc<str> = snippet.text.clone().into();
 9609            let edits = insertion_ranges
 9610                .iter()
 9611                .cloned()
 9612                .map(|range| (range, snippet_text.clone()));
 9613            let autoindent_mode = AutoindentMode::Block {
 9614                original_indent_columns: Vec::new(),
 9615            };
 9616            buffer.edit(edits, Some(autoindent_mode), cx);
 9617
 9618            let snapshot = &*buffer.read(cx);
 9619            let snippet = &snippet;
 9620            snippet
 9621                .tabstops
 9622                .iter()
 9623                .map(|tabstop| {
 9624                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9625                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9626                    });
 9627                    let mut tabstop_ranges = tabstop
 9628                        .ranges
 9629                        .iter()
 9630                        .flat_map(|tabstop_range| {
 9631                            let mut delta = 0_isize;
 9632                            insertion_ranges.iter().map(move |insertion_range| {
 9633                                let insertion_start = insertion_range.start as isize + delta;
 9634                                delta +=
 9635                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9636
 9637                                let start = ((insertion_start + tabstop_range.start) as usize)
 9638                                    .min(snapshot.len());
 9639                                let end = ((insertion_start + tabstop_range.end) as usize)
 9640                                    .min(snapshot.len());
 9641                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9642                            })
 9643                        })
 9644                        .collect::<Vec<_>>();
 9645                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9646
 9647                    Tabstop {
 9648                        is_end_tabstop,
 9649                        ranges: tabstop_ranges,
 9650                        choices: tabstop.choices.clone(),
 9651                    }
 9652                })
 9653                .collect::<Vec<_>>()
 9654        });
 9655        if let Some(tabstop) = tabstops.first() {
 9656            self.change_selections(Default::default(), window, cx, |s| {
 9657                // Reverse order so that the first range is the newest created selection.
 9658                // Completions will use it and autoscroll will prioritize it.
 9659                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9660            });
 9661
 9662            if let Some(choices) = &tabstop.choices
 9663                && let Some(selection) = tabstop.ranges.first()
 9664            {
 9665                self.show_snippet_choices(choices, selection.clone(), cx)
 9666            }
 9667
 9668            // If we're already at the last tabstop and it's at the end of the snippet,
 9669            // we're done, we don't need to keep the state around.
 9670            if !tabstop.is_end_tabstop {
 9671                let choices = tabstops
 9672                    .iter()
 9673                    .map(|tabstop| tabstop.choices.clone())
 9674                    .collect();
 9675
 9676                let ranges = tabstops
 9677                    .into_iter()
 9678                    .map(|tabstop| tabstop.ranges)
 9679                    .collect::<Vec<_>>();
 9680
 9681                self.snippet_stack.push(SnippetState {
 9682                    active_index: 0,
 9683                    ranges,
 9684                    choices,
 9685                });
 9686            }
 9687
 9688            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9689            if self.autoclose_regions.is_empty() {
 9690                let snapshot = self.buffer.read(cx).snapshot(cx);
 9691                let mut all_selections = self.selections.all::<Point>(cx);
 9692                for selection in &mut all_selections {
 9693                    let selection_head = selection.head();
 9694                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9695                        continue;
 9696                    };
 9697
 9698                    let mut bracket_pair = None;
 9699                    let max_lookup_length = scope
 9700                        .brackets()
 9701                        .map(|(pair, _)| {
 9702                            pair.start
 9703                                .as_str()
 9704                                .chars()
 9705                                .count()
 9706                                .max(pair.end.as_str().chars().count())
 9707                        })
 9708                        .max();
 9709                    if let Some(max_lookup_length) = max_lookup_length {
 9710                        let next_text = snapshot
 9711                            .chars_at(selection_head)
 9712                            .take(max_lookup_length)
 9713                            .collect::<String>();
 9714                        let prev_text = snapshot
 9715                            .reversed_chars_at(selection_head)
 9716                            .take(max_lookup_length)
 9717                            .collect::<String>();
 9718
 9719                        for (pair, enabled) in scope.brackets() {
 9720                            if enabled
 9721                                && pair.close
 9722                                && prev_text.starts_with(pair.start.as_str())
 9723                                && next_text.starts_with(pair.end.as_str())
 9724                            {
 9725                                bracket_pair = Some(pair.clone());
 9726                                break;
 9727                            }
 9728                        }
 9729                    }
 9730
 9731                    if let Some(pair) = bracket_pair {
 9732                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9733                        let autoclose_enabled =
 9734                            self.use_autoclose && snapshot_settings.use_autoclose;
 9735                        if autoclose_enabled {
 9736                            let start = snapshot.anchor_after(selection_head);
 9737                            let end = snapshot.anchor_after(selection_head);
 9738                            self.autoclose_regions.push(AutocloseRegion {
 9739                                selection_id: selection.id,
 9740                                range: start..end,
 9741                                pair,
 9742                            });
 9743                        }
 9744                    }
 9745                }
 9746            }
 9747        }
 9748        Ok(())
 9749    }
 9750
 9751    pub fn move_to_next_snippet_tabstop(
 9752        &mut self,
 9753        window: &mut Window,
 9754        cx: &mut Context<Self>,
 9755    ) -> bool {
 9756        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9757    }
 9758
 9759    pub fn move_to_prev_snippet_tabstop(
 9760        &mut self,
 9761        window: &mut Window,
 9762        cx: &mut Context<Self>,
 9763    ) -> bool {
 9764        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9765    }
 9766
 9767    pub fn move_to_snippet_tabstop(
 9768        &mut self,
 9769        bias: Bias,
 9770        window: &mut Window,
 9771        cx: &mut Context<Self>,
 9772    ) -> bool {
 9773        if let Some(mut snippet) = self.snippet_stack.pop() {
 9774            match bias {
 9775                Bias::Left => {
 9776                    if snippet.active_index > 0 {
 9777                        snippet.active_index -= 1;
 9778                    } else {
 9779                        self.snippet_stack.push(snippet);
 9780                        return false;
 9781                    }
 9782                }
 9783                Bias::Right => {
 9784                    if snippet.active_index + 1 < snippet.ranges.len() {
 9785                        snippet.active_index += 1;
 9786                    } else {
 9787                        self.snippet_stack.push(snippet);
 9788                        return false;
 9789                    }
 9790                }
 9791            }
 9792            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9793                self.change_selections(Default::default(), window, cx, |s| {
 9794                    // Reverse order so that the first range is the newest created selection.
 9795                    // Completions will use it and autoscroll will prioritize it.
 9796                    s.select_ranges(current_ranges.iter().rev().cloned())
 9797                });
 9798
 9799                if let Some(choices) = &snippet.choices[snippet.active_index]
 9800                    && let Some(selection) = current_ranges.first()
 9801                {
 9802                    self.show_snippet_choices(choices, selection.clone(), cx);
 9803                }
 9804
 9805                // If snippet state is not at the last tabstop, push it back on the stack
 9806                if snippet.active_index + 1 < snippet.ranges.len() {
 9807                    self.snippet_stack.push(snippet);
 9808                }
 9809                return true;
 9810            }
 9811        }
 9812
 9813        false
 9814    }
 9815
 9816    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9817        self.transact(window, cx, |this, window, cx| {
 9818            this.select_all(&SelectAll, window, cx);
 9819            this.insert("", window, cx);
 9820        });
 9821    }
 9822
 9823    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9824        if self.read_only(cx) {
 9825            return;
 9826        }
 9827        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9828        self.transact(window, cx, |this, window, cx| {
 9829            this.select_autoclose_pair(window, cx);
 9830            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9831            if !this.linked_edit_ranges.is_empty() {
 9832                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9833                let snapshot = this.buffer.read(cx).snapshot(cx);
 9834
 9835                for selection in selections.iter() {
 9836                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9837                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9838                    if selection_start.buffer_id != selection_end.buffer_id {
 9839                        continue;
 9840                    }
 9841                    if let Some(ranges) =
 9842                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9843                    {
 9844                        for (buffer, entries) in ranges {
 9845                            linked_ranges.entry(buffer).or_default().extend(entries);
 9846                        }
 9847                    }
 9848                }
 9849            }
 9850
 9851            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9852            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9853            for selection in &mut selections {
 9854                if selection.is_empty() {
 9855                    let old_head = selection.head();
 9856                    let mut new_head =
 9857                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9858                            .to_point(&display_map);
 9859                    if let Some((buffer, line_buffer_range)) = display_map
 9860                        .buffer_snapshot
 9861                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9862                    {
 9863                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9864                        let indent_len = match indent_size.kind {
 9865                            IndentKind::Space => {
 9866                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9867                            }
 9868                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9869                        };
 9870                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9871                            let indent_len = indent_len.get();
 9872                            new_head = cmp::min(
 9873                                new_head,
 9874                                MultiBufferPoint::new(
 9875                                    old_head.row,
 9876                                    ((old_head.column - 1) / indent_len) * indent_len,
 9877                                ),
 9878                            );
 9879                        }
 9880                    }
 9881
 9882                    selection.set_head(new_head, SelectionGoal::None);
 9883                }
 9884            }
 9885
 9886            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9887            this.insert("", window, cx);
 9888            let empty_str: Arc<str> = Arc::from("");
 9889            for (buffer, edits) in linked_ranges {
 9890                let snapshot = buffer.read(cx).snapshot();
 9891                use text::ToPoint as TP;
 9892
 9893                let edits = edits
 9894                    .into_iter()
 9895                    .map(|range| {
 9896                        let end_point = TP::to_point(&range.end, &snapshot);
 9897                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9898
 9899                        if end_point == start_point {
 9900                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9901                                .saturating_sub(1);
 9902                            start_point =
 9903                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9904                        };
 9905
 9906                        (start_point..end_point, empty_str.clone())
 9907                    })
 9908                    .sorted_by_key(|(range, _)| range.start)
 9909                    .collect::<Vec<_>>();
 9910                buffer.update(cx, |this, cx| {
 9911                    this.edit(edits, None, cx);
 9912                })
 9913            }
 9914            this.refresh_edit_prediction(true, false, window, cx);
 9915            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9916        });
 9917    }
 9918
 9919    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9920        if self.read_only(cx) {
 9921            return;
 9922        }
 9923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9924        self.transact(window, cx, |this, window, cx| {
 9925            this.change_selections(Default::default(), window, cx, |s| {
 9926                s.move_with(|map, selection| {
 9927                    if selection.is_empty() {
 9928                        let cursor = movement::right(map, selection.head());
 9929                        selection.end = cursor;
 9930                        selection.reversed = true;
 9931                        selection.goal = SelectionGoal::None;
 9932                    }
 9933                })
 9934            });
 9935            this.insert("", window, cx);
 9936            this.refresh_edit_prediction(true, false, window, cx);
 9937        });
 9938    }
 9939
 9940    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9941        if self.mode.is_single_line() {
 9942            cx.propagate();
 9943            return;
 9944        }
 9945
 9946        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9947        if self.move_to_prev_snippet_tabstop(window, cx) {
 9948            return;
 9949        }
 9950        self.outdent(&Outdent, window, cx);
 9951    }
 9952
 9953    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9954        if self.mode.is_single_line() {
 9955            cx.propagate();
 9956            return;
 9957        }
 9958
 9959        if self.move_to_next_snippet_tabstop(window, cx) {
 9960            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9961            return;
 9962        }
 9963        if self.read_only(cx) {
 9964            return;
 9965        }
 9966        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9967        let mut selections = self.selections.all_adjusted(cx);
 9968        let buffer = self.buffer.read(cx);
 9969        let snapshot = buffer.snapshot(cx);
 9970        let rows_iter = selections.iter().map(|s| s.head().row);
 9971        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9972
 9973        let has_some_cursor_in_whitespace = selections
 9974            .iter()
 9975            .filter(|selection| selection.is_empty())
 9976            .any(|selection| {
 9977                let cursor = selection.head();
 9978                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9979                cursor.column < current_indent.len
 9980            });
 9981
 9982        let mut edits = Vec::new();
 9983        let mut prev_edited_row = 0;
 9984        let mut row_delta = 0;
 9985        for selection in &mut selections {
 9986            if selection.start.row != prev_edited_row {
 9987                row_delta = 0;
 9988            }
 9989            prev_edited_row = selection.end.row;
 9990
 9991            // If the selection is non-empty, then increase the indentation of the selected lines.
 9992            if !selection.is_empty() {
 9993                row_delta =
 9994                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9995                continue;
 9996            }
 9997
 9998            let cursor = selection.head();
 9999            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10000            if let Some(suggested_indent) =
10001                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10002            {
10003                // Don't do anything if already at suggested indent
10004                // and there is any other cursor which is not
10005                if has_some_cursor_in_whitespace
10006                    && cursor.column == current_indent.len
10007                    && current_indent.len == suggested_indent.len
10008                {
10009                    continue;
10010                }
10011
10012                // Adjust line and move cursor to suggested indent
10013                // if cursor is not at suggested indent
10014                if cursor.column < suggested_indent.len
10015                    && cursor.column <= current_indent.len
10016                    && current_indent.len <= suggested_indent.len
10017                {
10018                    selection.start = Point::new(cursor.row, suggested_indent.len);
10019                    selection.end = selection.start;
10020                    if row_delta == 0 {
10021                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10022                            cursor.row,
10023                            current_indent,
10024                            suggested_indent,
10025                        ));
10026                        row_delta = suggested_indent.len - current_indent.len;
10027                    }
10028                    continue;
10029                }
10030
10031                // If current indent is more than suggested indent
10032                // only move cursor to current indent and skip indent
10033                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10034                    selection.start = Point::new(cursor.row, current_indent.len);
10035                    selection.end = selection.start;
10036                    continue;
10037                }
10038            }
10039
10040            // Otherwise, insert a hard or soft tab.
10041            let settings = buffer.language_settings_at(cursor, cx);
10042            let tab_size = if settings.hard_tabs {
10043                IndentSize::tab()
10044            } else {
10045                let tab_size = settings.tab_size.get();
10046                let indent_remainder = snapshot
10047                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10048                    .flat_map(str::chars)
10049                    .fold(row_delta % tab_size, |counter: u32, c| {
10050                        if c == '\t' {
10051                            0
10052                        } else {
10053                            (counter + 1) % tab_size
10054                        }
10055                    });
10056
10057                let chars_to_next_tab_stop = tab_size - indent_remainder;
10058                IndentSize::spaces(chars_to_next_tab_stop)
10059            };
10060            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10061            selection.end = selection.start;
10062            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10063            row_delta += tab_size.len;
10064        }
10065
10066        self.transact(window, cx, |this, window, cx| {
10067            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10068            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10069            this.refresh_edit_prediction(true, false, window, cx);
10070        });
10071    }
10072
10073    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10074        if self.read_only(cx) {
10075            return;
10076        }
10077        if self.mode.is_single_line() {
10078            cx.propagate();
10079            return;
10080        }
10081
10082        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10083        let mut selections = self.selections.all::<Point>(cx);
10084        let mut prev_edited_row = 0;
10085        let mut row_delta = 0;
10086        let mut edits = Vec::new();
10087        let buffer = self.buffer.read(cx);
10088        let snapshot = buffer.snapshot(cx);
10089        for selection in &mut selections {
10090            if selection.start.row != prev_edited_row {
10091                row_delta = 0;
10092            }
10093            prev_edited_row = selection.end.row;
10094
10095            row_delta =
10096                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10097        }
10098
10099        self.transact(window, cx, |this, window, cx| {
10100            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10101            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10102        });
10103    }
10104
10105    fn indent_selection(
10106        buffer: &MultiBuffer,
10107        snapshot: &MultiBufferSnapshot,
10108        selection: &mut Selection<Point>,
10109        edits: &mut Vec<(Range<Point>, String)>,
10110        delta_for_start_row: u32,
10111        cx: &App,
10112    ) -> u32 {
10113        let settings = buffer.language_settings_at(selection.start, cx);
10114        let tab_size = settings.tab_size.get();
10115        let indent_kind = if settings.hard_tabs {
10116            IndentKind::Tab
10117        } else {
10118            IndentKind::Space
10119        };
10120        let mut start_row = selection.start.row;
10121        let mut end_row = selection.end.row + 1;
10122
10123        // If a selection ends at the beginning of a line, don't indent
10124        // that last line.
10125        if selection.end.column == 0 && selection.end.row > selection.start.row {
10126            end_row -= 1;
10127        }
10128
10129        // Avoid re-indenting a row that has already been indented by a
10130        // previous selection, but still update this selection's column
10131        // to reflect that indentation.
10132        if delta_for_start_row > 0 {
10133            start_row += 1;
10134            selection.start.column += delta_for_start_row;
10135            if selection.end.row == selection.start.row {
10136                selection.end.column += delta_for_start_row;
10137            }
10138        }
10139
10140        let mut delta_for_end_row = 0;
10141        let has_multiple_rows = start_row + 1 != end_row;
10142        for row in start_row..end_row {
10143            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10144            let indent_delta = match (current_indent.kind, indent_kind) {
10145                (IndentKind::Space, IndentKind::Space) => {
10146                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10147                    IndentSize::spaces(columns_to_next_tab_stop)
10148                }
10149                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10150                (_, IndentKind::Tab) => IndentSize::tab(),
10151            };
10152
10153            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10154                0
10155            } else {
10156                selection.start.column
10157            };
10158            let row_start = Point::new(row, start);
10159            edits.push((
10160                row_start..row_start,
10161                indent_delta.chars().collect::<String>(),
10162            ));
10163
10164            // Update this selection's endpoints to reflect the indentation.
10165            if row == selection.start.row {
10166                selection.start.column += indent_delta.len;
10167            }
10168            if row == selection.end.row {
10169                selection.end.column += indent_delta.len;
10170                delta_for_end_row = indent_delta.len;
10171            }
10172        }
10173
10174        if selection.start.row == selection.end.row {
10175            delta_for_start_row + delta_for_end_row
10176        } else {
10177            delta_for_end_row
10178        }
10179    }
10180
10181    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10182        if self.read_only(cx) {
10183            return;
10184        }
10185        if self.mode.is_single_line() {
10186            cx.propagate();
10187            return;
10188        }
10189
10190        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10191        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10192        let selections = self.selections.all::<Point>(cx);
10193        let mut deletion_ranges = Vec::new();
10194        let mut last_outdent = None;
10195        {
10196            let buffer = self.buffer.read(cx);
10197            let snapshot = buffer.snapshot(cx);
10198            for selection in &selections {
10199                let settings = buffer.language_settings_at(selection.start, cx);
10200                let tab_size = settings.tab_size.get();
10201                let mut rows = selection.spanned_rows(false, &display_map);
10202
10203                // Avoid re-outdenting a row that has already been outdented by a
10204                // previous selection.
10205                if let Some(last_row) = last_outdent
10206                    && last_row == rows.start
10207                {
10208                    rows.start = rows.start.next_row();
10209                }
10210                let has_multiple_rows = rows.len() > 1;
10211                for row in rows.iter_rows() {
10212                    let indent_size = snapshot.indent_size_for_line(row);
10213                    if indent_size.len > 0 {
10214                        let deletion_len = match indent_size.kind {
10215                            IndentKind::Space => {
10216                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10217                                if columns_to_prev_tab_stop == 0 {
10218                                    tab_size
10219                                } else {
10220                                    columns_to_prev_tab_stop
10221                                }
10222                            }
10223                            IndentKind::Tab => 1,
10224                        };
10225                        let start = if has_multiple_rows
10226                            || deletion_len > selection.start.column
10227                            || indent_size.len < selection.start.column
10228                        {
10229                            0
10230                        } else {
10231                            selection.start.column - deletion_len
10232                        };
10233                        deletion_ranges.push(
10234                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10235                        );
10236                        last_outdent = Some(row);
10237                    }
10238                }
10239            }
10240        }
10241
10242        self.transact(window, cx, |this, window, cx| {
10243            this.buffer.update(cx, |buffer, cx| {
10244                let empty_str: Arc<str> = Arc::default();
10245                buffer.edit(
10246                    deletion_ranges
10247                        .into_iter()
10248                        .map(|range| (range, empty_str.clone())),
10249                    None,
10250                    cx,
10251                );
10252            });
10253            let selections = this.selections.all::<usize>(cx);
10254            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10255        });
10256    }
10257
10258    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10259        if self.read_only(cx) {
10260            return;
10261        }
10262        if self.mode.is_single_line() {
10263            cx.propagate();
10264            return;
10265        }
10266
10267        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10268        let selections = self
10269            .selections
10270            .all::<usize>(cx)
10271            .into_iter()
10272            .map(|s| s.range());
10273
10274        self.transact(window, cx, |this, window, cx| {
10275            this.buffer.update(cx, |buffer, cx| {
10276                buffer.autoindent_ranges(selections, cx);
10277            });
10278            let selections = this.selections.all::<usize>(cx);
10279            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10280        });
10281    }
10282
10283    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10284        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10285        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10286        let selections = self.selections.all::<Point>(cx);
10287
10288        let mut new_cursors = Vec::new();
10289        let mut edit_ranges = Vec::new();
10290        let mut selections = selections.iter().peekable();
10291        while let Some(selection) = selections.next() {
10292            let mut rows = selection.spanned_rows(false, &display_map);
10293            let goal_display_column = selection.head().to_display_point(&display_map).column();
10294
10295            // Accumulate contiguous regions of rows that we want to delete.
10296            while let Some(next_selection) = selections.peek() {
10297                let next_rows = next_selection.spanned_rows(false, &display_map);
10298                if next_rows.start <= rows.end {
10299                    rows.end = next_rows.end;
10300                    selections.next().unwrap();
10301                } else {
10302                    break;
10303                }
10304            }
10305
10306            let buffer = &display_map.buffer_snapshot;
10307            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10308            let edit_end;
10309            let cursor_buffer_row;
10310            if buffer.max_point().row >= rows.end.0 {
10311                // If there's a line after the range, delete the \n from the end of the row range
10312                // and position the cursor on the next line.
10313                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10314                cursor_buffer_row = rows.end;
10315            } else {
10316                // If there isn't a line after the range, delete the \n from the line before the
10317                // start of the row range and position the cursor there.
10318                edit_start = edit_start.saturating_sub(1);
10319                edit_end = buffer.len();
10320                cursor_buffer_row = rows.start.previous_row();
10321            }
10322
10323            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10324            *cursor.column_mut() =
10325                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10326
10327            new_cursors.push((
10328                selection.id,
10329                buffer.anchor_after(cursor.to_point(&display_map)),
10330            ));
10331            edit_ranges.push(edit_start..edit_end);
10332        }
10333
10334        self.transact(window, cx, |this, window, cx| {
10335            let buffer = this.buffer.update(cx, |buffer, cx| {
10336                let empty_str: Arc<str> = Arc::default();
10337                buffer.edit(
10338                    edit_ranges
10339                        .into_iter()
10340                        .map(|range| (range, empty_str.clone())),
10341                    None,
10342                    cx,
10343                );
10344                buffer.snapshot(cx)
10345            });
10346            let new_selections = new_cursors
10347                .into_iter()
10348                .map(|(id, cursor)| {
10349                    let cursor = cursor.to_point(&buffer);
10350                    Selection {
10351                        id,
10352                        start: cursor,
10353                        end: cursor,
10354                        reversed: false,
10355                        goal: SelectionGoal::None,
10356                    }
10357                })
10358                .collect();
10359
10360            this.change_selections(Default::default(), window, cx, |s| {
10361                s.select(new_selections);
10362            });
10363        });
10364    }
10365
10366    pub fn join_lines_impl(
10367        &mut self,
10368        insert_whitespace: bool,
10369        window: &mut Window,
10370        cx: &mut Context<Self>,
10371    ) {
10372        if self.read_only(cx) {
10373            return;
10374        }
10375        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10376        for selection in self.selections.all::<Point>(cx) {
10377            let start = MultiBufferRow(selection.start.row);
10378            // Treat single line selections as if they include the next line. Otherwise this action
10379            // would do nothing for single line selections individual cursors.
10380            let end = if selection.start.row == selection.end.row {
10381                MultiBufferRow(selection.start.row + 1)
10382            } else {
10383                MultiBufferRow(selection.end.row)
10384            };
10385
10386            if let Some(last_row_range) = row_ranges.last_mut()
10387                && start <= last_row_range.end
10388            {
10389                last_row_range.end = end;
10390                continue;
10391            }
10392            row_ranges.push(start..end);
10393        }
10394
10395        let snapshot = self.buffer.read(cx).snapshot(cx);
10396        let mut cursor_positions = Vec::new();
10397        for row_range in &row_ranges {
10398            let anchor = snapshot.anchor_before(Point::new(
10399                row_range.end.previous_row().0,
10400                snapshot.line_len(row_range.end.previous_row()),
10401            ));
10402            cursor_positions.push(anchor..anchor);
10403        }
10404
10405        self.transact(window, cx, |this, window, cx| {
10406            for row_range in row_ranges.into_iter().rev() {
10407                for row in row_range.iter_rows().rev() {
10408                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10409                    let next_line_row = row.next_row();
10410                    let indent = snapshot.indent_size_for_line(next_line_row);
10411                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10412
10413                    let replace =
10414                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10415                            " "
10416                        } else {
10417                            ""
10418                        };
10419
10420                    this.buffer.update(cx, |buffer, cx| {
10421                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10422                    });
10423                }
10424            }
10425
10426            this.change_selections(Default::default(), window, cx, |s| {
10427                s.select_anchor_ranges(cursor_positions)
10428            });
10429        });
10430    }
10431
10432    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10433        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10434        self.join_lines_impl(true, window, cx);
10435    }
10436
10437    pub fn sort_lines_case_sensitive(
10438        &mut self,
10439        _: &SortLinesCaseSensitive,
10440        window: &mut Window,
10441        cx: &mut Context<Self>,
10442    ) {
10443        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10444    }
10445
10446    pub fn sort_lines_by_length(
10447        &mut self,
10448        _: &SortLinesByLength,
10449        window: &mut Window,
10450        cx: &mut Context<Self>,
10451    ) {
10452        self.manipulate_immutable_lines(window, cx, |lines| {
10453            lines.sort_by_key(|&line| line.chars().count())
10454        })
10455    }
10456
10457    pub fn sort_lines_case_insensitive(
10458        &mut self,
10459        _: &SortLinesCaseInsensitive,
10460        window: &mut Window,
10461        cx: &mut Context<Self>,
10462    ) {
10463        self.manipulate_immutable_lines(window, cx, |lines| {
10464            lines.sort_by_key(|line| line.to_lowercase())
10465        })
10466    }
10467
10468    pub fn unique_lines_case_insensitive(
10469        &mut self,
10470        _: &UniqueLinesCaseInsensitive,
10471        window: &mut Window,
10472        cx: &mut Context<Self>,
10473    ) {
10474        self.manipulate_immutable_lines(window, cx, |lines| {
10475            let mut seen = HashSet::default();
10476            lines.retain(|line| seen.insert(line.to_lowercase()));
10477        })
10478    }
10479
10480    pub fn unique_lines_case_sensitive(
10481        &mut self,
10482        _: &UniqueLinesCaseSensitive,
10483        window: &mut Window,
10484        cx: &mut Context<Self>,
10485    ) {
10486        self.manipulate_immutable_lines(window, cx, |lines| {
10487            let mut seen = HashSet::default();
10488            lines.retain(|line| seen.insert(*line));
10489        })
10490    }
10491
10492    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10493        let snapshot = self.buffer.read(cx).snapshot(cx);
10494        for selection in self.selections.disjoint_anchors().iter() {
10495            if snapshot
10496                .language_at(selection.start)
10497                .and_then(|lang| lang.config().wrap_characters.as_ref())
10498                .is_some()
10499            {
10500                return true;
10501            }
10502        }
10503        false
10504    }
10505
10506    fn wrap_selections_in_tag(
10507        &mut self,
10508        _: &WrapSelectionsInTag,
10509        window: &mut Window,
10510        cx: &mut Context<Self>,
10511    ) {
10512        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10513
10514        let snapshot = self.buffer.read(cx).snapshot(cx);
10515
10516        let mut edits = Vec::new();
10517        let mut boundaries = Vec::new();
10518
10519        for selection in self.selections.all::<Point>(cx).iter() {
10520            let Some(wrap_config) = snapshot
10521                .language_at(selection.start)
10522                .and_then(|lang| lang.config().wrap_characters.clone())
10523            else {
10524                continue;
10525            };
10526
10527            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10528            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10529
10530            let start_before = snapshot.anchor_before(selection.start);
10531            let end_after = snapshot.anchor_after(selection.end);
10532
10533            edits.push((start_before..start_before, open_tag));
10534            edits.push((end_after..end_after, close_tag));
10535
10536            boundaries.push((
10537                start_before,
10538                end_after,
10539                wrap_config.start_prefix.len(),
10540                wrap_config.end_suffix.len(),
10541            ));
10542        }
10543
10544        if edits.is_empty() {
10545            return;
10546        }
10547
10548        self.transact(window, cx, |this, window, cx| {
10549            let buffer = this.buffer.update(cx, |buffer, cx| {
10550                buffer.edit(edits, None, cx);
10551                buffer.snapshot(cx)
10552            });
10553
10554            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10555            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10556                boundaries.into_iter()
10557            {
10558                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10559                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10560                new_selections.push(open_offset..open_offset);
10561                new_selections.push(close_offset..close_offset);
10562            }
10563
10564            this.change_selections(Default::default(), window, cx, |s| {
10565                s.select_ranges(new_selections);
10566            });
10567
10568            this.request_autoscroll(Autoscroll::fit(), cx);
10569        });
10570    }
10571
10572    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10573        let Some(project) = self.project.clone() else {
10574            return;
10575        };
10576        self.reload(project, window, cx)
10577            .detach_and_notify_err(window, cx);
10578    }
10579
10580    pub fn restore_file(
10581        &mut self,
10582        _: &::git::RestoreFile,
10583        window: &mut Window,
10584        cx: &mut Context<Self>,
10585    ) {
10586        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10587        let mut buffer_ids = HashSet::default();
10588        let snapshot = self.buffer().read(cx).snapshot(cx);
10589        for selection in self.selections.all::<usize>(cx) {
10590            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10591        }
10592
10593        let buffer = self.buffer().read(cx);
10594        let ranges = buffer_ids
10595            .into_iter()
10596            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10597            .collect::<Vec<_>>();
10598
10599        self.restore_hunks_in_ranges(ranges, window, cx);
10600    }
10601
10602    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10603        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10604        let selections = self
10605            .selections
10606            .all(cx)
10607            .into_iter()
10608            .map(|s| s.range())
10609            .collect();
10610        self.restore_hunks_in_ranges(selections, window, cx);
10611    }
10612
10613    pub fn restore_hunks_in_ranges(
10614        &mut self,
10615        ranges: Vec<Range<Point>>,
10616        window: &mut Window,
10617        cx: &mut Context<Editor>,
10618    ) {
10619        let mut revert_changes = HashMap::default();
10620        let chunk_by = self
10621            .snapshot(window, cx)
10622            .hunks_for_ranges(ranges)
10623            .into_iter()
10624            .chunk_by(|hunk| hunk.buffer_id);
10625        for (buffer_id, hunks) in &chunk_by {
10626            let hunks = hunks.collect::<Vec<_>>();
10627            for hunk in &hunks {
10628                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10629            }
10630            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10631        }
10632        drop(chunk_by);
10633        if !revert_changes.is_empty() {
10634            self.transact(window, cx, |editor, window, cx| {
10635                editor.restore(revert_changes, window, cx);
10636            });
10637        }
10638    }
10639
10640    pub fn open_active_item_in_terminal(
10641        &mut self,
10642        _: &OpenInTerminal,
10643        window: &mut Window,
10644        cx: &mut Context<Self>,
10645    ) {
10646        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10647            let project_path = buffer.read(cx).project_path(cx)?;
10648            let project = self.project()?.read(cx);
10649            let entry = project.entry_for_path(&project_path, cx)?;
10650            let parent = match &entry.canonical_path {
10651                Some(canonical_path) => canonical_path.to_path_buf(),
10652                None => project.absolute_path(&project_path, cx)?,
10653            }
10654            .parent()?
10655            .to_path_buf();
10656            Some(parent)
10657        }) {
10658            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10659        }
10660    }
10661
10662    fn set_breakpoint_context_menu(
10663        &mut self,
10664        display_row: DisplayRow,
10665        position: Option<Anchor>,
10666        clicked_point: gpui::Point<Pixels>,
10667        window: &mut Window,
10668        cx: &mut Context<Self>,
10669    ) {
10670        let source = self
10671            .buffer
10672            .read(cx)
10673            .snapshot(cx)
10674            .anchor_before(Point::new(display_row.0, 0u32));
10675
10676        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10677
10678        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10679            self,
10680            source,
10681            clicked_point,
10682            context_menu,
10683            window,
10684            cx,
10685        );
10686    }
10687
10688    fn add_edit_breakpoint_block(
10689        &mut self,
10690        anchor: Anchor,
10691        breakpoint: &Breakpoint,
10692        edit_action: BreakpointPromptEditAction,
10693        window: &mut Window,
10694        cx: &mut Context<Self>,
10695    ) {
10696        let weak_editor = cx.weak_entity();
10697        let bp_prompt = cx.new(|cx| {
10698            BreakpointPromptEditor::new(
10699                weak_editor,
10700                anchor,
10701                breakpoint.clone(),
10702                edit_action,
10703                window,
10704                cx,
10705            )
10706        });
10707
10708        let height = bp_prompt.update(cx, |this, cx| {
10709            this.prompt
10710                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10711        });
10712        let cloned_prompt = bp_prompt.clone();
10713        let blocks = vec![BlockProperties {
10714            style: BlockStyle::Sticky,
10715            placement: BlockPlacement::Above(anchor),
10716            height: Some(height),
10717            render: Arc::new(move |cx| {
10718                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10719                cloned_prompt.clone().into_any_element()
10720            }),
10721            priority: 0,
10722        }];
10723
10724        let focus_handle = bp_prompt.focus_handle(cx);
10725        window.focus(&focus_handle);
10726
10727        let block_ids = self.insert_blocks(blocks, None, cx);
10728        bp_prompt.update(cx, |prompt, _| {
10729            prompt.add_block_ids(block_ids);
10730        });
10731    }
10732
10733    pub(crate) fn breakpoint_at_row(
10734        &self,
10735        row: u32,
10736        window: &mut Window,
10737        cx: &mut Context<Self>,
10738    ) -> Option<(Anchor, Breakpoint)> {
10739        let snapshot = self.snapshot(window, cx);
10740        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10741
10742        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10743    }
10744
10745    pub(crate) fn breakpoint_at_anchor(
10746        &self,
10747        breakpoint_position: Anchor,
10748        snapshot: &EditorSnapshot,
10749        cx: &mut Context<Self>,
10750    ) -> Option<(Anchor, Breakpoint)> {
10751        let buffer = self
10752            .buffer
10753            .read(cx)
10754            .buffer_for_anchor(breakpoint_position, cx)?;
10755
10756        let enclosing_excerpt = breakpoint_position.excerpt_id;
10757        let buffer_snapshot = buffer.read(cx).snapshot();
10758
10759        let row = buffer_snapshot
10760            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10761            .row;
10762
10763        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10764        let anchor_end = snapshot
10765            .buffer_snapshot
10766            .anchor_after(Point::new(row, line_len));
10767
10768        self.breakpoint_store
10769            .as_ref()?
10770            .read_with(cx, |breakpoint_store, cx| {
10771                breakpoint_store
10772                    .breakpoints(
10773                        &buffer,
10774                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10775                        &buffer_snapshot,
10776                        cx,
10777                    )
10778                    .next()
10779                    .and_then(|(bp, _)| {
10780                        let breakpoint_row = buffer_snapshot
10781                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10782                            .row;
10783
10784                        if breakpoint_row == row {
10785                            snapshot
10786                                .buffer_snapshot
10787                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10788                                .map(|position| (position, bp.bp.clone()))
10789                        } else {
10790                            None
10791                        }
10792                    })
10793            })
10794    }
10795
10796    pub fn edit_log_breakpoint(
10797        &mut self,
10798        _: &EditLogBreakpoint,
10799        window: &mut Window,
10800        cx: &mut Context<Self>,
10801    ) {
10802        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10803            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10804                message: None,
10805                state: BreakpointState::Enabled,
10806                condition: None,
10807                hit_condition: None,
10808            });
10809
10810            self.add_edit_breakpoint_block(
10811                anchor,
10812                &breakpoint,
10813                BreakpointPromptEditAction::Log,
10814                window,
10815                cx,
10816            );
10817        }
10818    }
10819
10820    fn breakpoints_at_cursors(
10821        &self,
10822        window: &mut Window,
10823        cx: &mut Context<Self>,
10824    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10825        let snapshot = self.snapshot(window, cx);
10826        let cursors = self
10827            .selections
10828            .disjoint_anchors()
10829            .iter()
10830            .map(|selection| {
10831                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10832
10833                let breakpoint_position = self
10834                    .breakpoint_at_row(cursor_position.row, window, cx)
10835                    .map(|bp| bp.0)
10836                    .unwrap_or_else(|| {
10837                        snapshot
10838                            .display_snapshot
10839                            .buffer_snapshot
10840                            .anchor_after(Point::new(cursor_position.row, 0))
10841                    });
10842
10843                let breakpoint = self
10844                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10845                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10846
10847                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10848            })
10849            // There might be multiple cursors on the same line; all of them should have the same anchors though as their breakpoints positions, which makes it possible to sort and dedup the list.
10850            .collect::<HashMap<Anchor, _>>();
10851
10852        cursors.into_iter().collect()
10853    }
10854
10855    pub fn enable_breakpoint(
10856        &mut self,
10857        _: &crate::actions::EnableBreakpoint,
10858        window: &mut Window,
10859        cx: &mut Context<Self>,
10860    ) {
10861        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10862            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10863                continue;
10864            };
10865            self.edit_breakpoint_at_anchor(
10866                anchor,
10867                breakpoint,
10868                BreakpointEditAction::InvertState,
10869                cx,
10870            );
10871        }
10872    }
10873
10874    pub fn disable_breakpoint(
10875        &mut self,
10876        _: &crate::actions::DisableBreakpoint,
10877        window: &mut Window,
10878        cx: &mut Context<Self>,
10879    ) {
10880        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10881            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10882                continue;
10883            };
10884            self.edit_breakpoint_at_anchor(
10885                anchor,
10886                breakpoint,
10887                BreakpointEditAction::InvertState,
10888                cx,
10889            );
10890        }
10891    }
10892
10893    pub fn toggle_breakpoint(
10894        &mut self,
10895        _: &crate::actions::ToggleBreakpoint,
10896        window: &mut Window,
10897        cx: &mut Context<Self>,
10898    ) {
10899        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10900            if let Some(breakpoint) = breakpoint {
10901                self.edit_breakpoint_at_anchor(
10902                    anchor,
10903                    breakpoint,
10904                    BreakpointEditAction::Toggle,
10905                    cx,
10906                );
10907            } else {
10908                self.edit_breakpoint_at_anchor(
10909                    anchor,
10910                    Breakpoint::new_standard(),
10911                    BreakpointEditAction::Toggle,
10912                    cx,
10913                );
10914            }
10915        }
10916    }
10917
10918    pub fn edit_breakpoint_at_anchor(
10919        &mut self,
10920        breakpoint_position: Anchor,
10921        breakpoint: Breakpoint,
10922        edit_action: BreakpointEditAction,
10923        cx: &mut Context<Self>,
10924    ) {
10925        let Some(breakpoint_store) = &self.breakpoint_store else {
10926            return;
10927        };
10928
10929        let Some(buffer) = self
10930            .buffer
10931            .read(cx)
10932            .buffer_for_anchor(breakpoint_position, cx)
10933        else {
10934            return;
10935        };
10936
10937        breakpoint_store.update(cx, |breakpoint_store, cx| {
10938            breakpoint_store.toggle_breakpoint(
10939                buffer,
10940                BreakpointWithPosition {
10941                    position: breakpoint_position.text_anchor,
10942                    bp: breakpoint,
10943                },
10944                edit_action,
10945                cx,
10946            );
10947        });
10948
10949        cx.notify();
10950    }
10951
10952    #[cfg(any(test, feature = "test-support"))]
10953    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10954        self.breakpoint_store.clone()
10955    }
10956
10957    pub fn prepare_restore_change(
10958        &self,
10959        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10960        hunk: &MultiBufferDiffHunk,
10961        cx: &mut App,
10962    ) -> Option<()> {
10963        if hunk.is_created_file() {
10964            return None;
10965        }
10966        let buffer = self.buffer.read(cx);
10967        let diff = buffer.diff_for(hunk.buffer_id)?;
10968        let buffer = buffer.buffer(hunk.buffer_id)?;
10969        let buffer = buffer.read(cx);
10970        let original_text = diff
10971            .read(cx)
10972            .base_text()
10973            .as_rope()
10974            .slice(hunk.diff_base_byte_range.clone());
10975        let buffer_snapshot = buffer.snapshot();
10976        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10977        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10978            probe
10979                .0
10980                .start
10981                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10982                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10983        }) {
10984            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10985            Some(())
10986        } else {
10987            None
10988        }
10989    }
10990
10991    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10992        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10993    }
10994
10995    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10996        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
10997    }
10998
10999    fn manipulate_lines<M>(
11000        &mut self,
11001        window: &mut Window,
11002        cx: &mut Context<Self>,
11003        mut manipulate: M,
11004    ) where
11005        M: FnMut(&str) -> LineManipulationResult,
11006    {
11007        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11008
11009        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11010        let buffer = self.buffer.read(cx).snapshot(cx);
11011
11012        let mut edits = Vec::new();
11013
11014        let selections = self.selections.all::<Point>(cx);
11015        let mut selections = selections.iter().peekable();
11016        let mut contiguous_row_selections = Vec::new();
11017        let mut new_selections = Vec::new();
11018        let mut added_lines = 0;
11019        let mut removed_lines = 0;
11020
11021        while let Some(selection) = selections.next() {
11022            let (start_row, end_row) = consume_contiguous_rows(
11023                &mut contiguous_row_selections,
11024                selection,
11025                &display_map,
11026                &mut selections,
11027            );
11028
11029            let start_point = Point::new(start_row.0, 0);
11030            let end_point = Point::new(
11031                end_row.previous_row().0,
11032                buffer.line_len(end_row.previous_row()),
11033            );
11034            let text = buffer
11035                .text_for_range(start_point..end_point)
11036                .collect::<String>();
11037
11038            let LineManipulationResult {
11039                new_text,
11040                line_count_before,
11041                line_count_after,
11042            } = manipulate(&text);
11043
11044            edits.push((start_point..end_point, new_text));
11045
11046            // Selections must change based on added and removed line count
11047            let start_row =
11048                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11049            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11050            new_selections.push(Selection {
11051                id: selection.id,
11052                start: start_row,
11053                end: end_row,
11054                goal: SelectionGoal::None,
11055                reversed: selection.reversed,
11056            });
11057
11058            if line_count_after > line_count_before {
11059                added_lines += line_count_after - line_count_before;
11060            } else if line_count_before > line_count_after {
11061                removed_lines += line_count_before - line_count_after;
11062            }
11063        }
11064
11065        self.transact(window, cx, |this, window, cx| {
11066            let buffer = this.buffer.update(cx, |buffer, cx| {
11067                buffer.edit(edits, None, cx);
11068                buffer.snapshot(cx)
11069            });
11070
11071            // Recalculate offsets on newly edited buffer
11072            let new_selections = new_selections
11073                .iter()
11074                .map(|s| {
11075                    let start_point = Point::new(s.start.0, 0);
11076                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11077                    Selection {
11078                        id: s.id,
11079                        start: buffer.point_to_offset(start_point),
11080                        end: buffer.point_to_offset(end_point),
11081                        goal: s.goal,
11082                        reversed: s.reversed,
11083                    }
11084                })
11085                .collect();
11086
11087            this.change_selections(Default::default(), window, cx, |s| {
11088                s.select(new_selections);
11089            });
11090
11091            this.request_autoscroll(Autoscroll::fit(), cx);
11092        });
11093    }
11094
11095    fn manipulate_immutable_lines<Fn>(
11096        &mut self,
11097        window: &mut Window,
11098        cx: &mut Context<Self>,
11099        mut callback: Fn,
11100    ) where
11101        Fn: FnMut(&mut Vec<&str>),
11102    {
11103        self.manipulate_lines(window, cx, |text| {
11104            let mut lines: Vec<&str> = text.split('\n').collect();
11105            let line_count_before = lines.len();
11106
11107            callback(&mut lines);
11108
11109            LineManipulationResult {
11110                new_text: lines.join("\n"),
11111                line_count_before,
11112                line_count_after: lines.len(),
11113            }
11114        });
11115    }
11116
11117    fn manipulate_mutable_lines<Fn>(
11118        &mut self,
11119        window: &mut Window,
11120        cx: &mut Context<Self>,
11121        mut callback: Fn,
11122    ) where
11123        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11124    {
11125        self.manipulate_lines(window, cx, |text| {
11126            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11127            let line_count_before = lines.len();
11128
11129            callback(&mut lines);
11130
11131            LineManipulationResult {
11132                new_text: lines.join("\n"),
11133                line_count_before,
11134                line_count_after: lines.len(),
11135            }
11136        });
11137    }
11138
11139    pub fn convert_indentation_to_spaces(
11140        &mut self,
11141        _: &ConvertIndentationToSpaces,
11142        window: &mut Window,
11143        cx: &mut Context<Self>,
11144    ) {
11145        let settings = self.buffer.read(cx).language_settings(cx);
11146        let tab_size = settings.tab_size.get() as usize;
11147
11148        self.manipulate_mutable_lines(window, cx, |lines| {
11149            // Allocates a reasonably sized scratch buffer once for the whole loop
11150            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11151            // Avoids recomputing spaces that could be inserted many times
11152            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11153                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11154                .collect();
11155
11156            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11157                let mut chars = line.as_ref().chars();
11158                let mut col = 0;
11159                let mut changed = false;
11160
11161                for ch in chars.by_ref() {
11162                    match ch {
11163                        ' ' => {
11164                            reindented_line.push(' ');
11165                            col += 1;
11166                        }
11167                        '\t' => {
11168                            // \t are converted to spaces depending on the current column
11169                            let spaces_len = tab_size - (col % tab_size);
11170                            reindented_line.extend(&space_cache[spaces_len - 1]);
11171                            col += spaces_len;
11172                            changed = true;
11173                        }
11174                        _ => {
11175                            // If we dont append before break, the character is consumed
11176                            reindented_line.push(ch);
11177                            break;
11178                        }
11179                    }
11180                }
11181
11182                if !changed {
11183                    reindented_line.clear();
11184                    continue;
11185                }
11186                // Append the rest of the line and replace old reference with new one
11187                reindented_line.extend(chars);
11188                *line = Cow::Owned(reindented_line.clone());
11189                reindented_line.clear();
11190            }
11191        });
11192    }
11193
11194    pub fn convert_indentation_to_tabs(
11195        &mut self,
11196        _: &ConvertIndentationToTabs,
11197        window: &mut Window,
11198        cx: &mut Context<Self>,
11199    ) {
11200        let settings = self.buffer.read(cx).language_settings(cx);
11201        let tab_size = settings.tab_size.get() as usize;
11202
11203        self.manipulate_mutable_lines(window, cx, |lines| {
11204            // Allocates a reasonably sized buffer once for the whole loop
11205            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11206            // Avoids recomputing spaces that could be inserted many times
11207            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11208                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11209                .collect();
11210
11211            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11212                let mut chars = line.chars();
11213                let mut spaces_count = 0;
11214                let mut first_non_indent_char = None;
11215                let mut changed = false;
11216
11217                for ch in chars.by_ref() {
11218                    match ch {
11219                        ' ' => {
11220                            // Keep track of spaces. Append \t when we reach tab_size
11221                            spaces_count += 1;
11222                            changed = true;
11223                            if spaces_count == tab_size {
11224                                reindented_line.push('\t');
11225                                spaces_count = 0;
11226                            }
11227                        }
11228                        '\t' => {
11229                            reindented_line.push('\t');
11230                            spaces_count = 0;
11231                        }
11232                        _ => {
11233                            // Dont append it yet, we might have remaining spaces
11234                            first_non_indent_char = Some(ch);
11235                            break;
11236                        }
11237                    }
11238                }
11239
11240                if !changed {
11241                    reindented_line.clear();
11242                    continue;
11243                }
11244                // Remaining spaces that didn't make a full tab stop
11245                if spaces_count > 0 {
11246                    reindented_line.extend(&space_cache[spaces_count - 1]);
11247                }
11248                // If we consume an extra character that was not indentation, add it back
11249                if let Some(extra_char) = first_non_indent_char {
11250                    reindented_line.push(extra_char);
11251                }
11252                // Append the rest of the line and replace old reference with new one
11253                reindented_line.extend(chars);
11254                *line = Cow::Owned(reindented_line.clone());
11255                reindented_line.clear();
11256            }
11257        });
11258    }
11259
11260    pub fn convert_to_upper_case(
11261        &mut self,
11262        _: &ConvertToUpperCase,
11263        window: &mut Window,
11264        cx: &mut Context<Self>,
11265    ) {
11266        self.manipulate_text(window, cx, |text| text.to_uppercase())
11267    }
11268
11269    pub fn convert_to_lower_case(
11270        &mut self,
11271        _: &ConvertToLowerCase,
11272        window: &mut Window,
11273        cx: &mut Context<Self>,
11274    ) {
11275        self.manipulate_text(window, cx, |text| text.to_lowercase())
11276    }
11277
11278    pub fn convert_to_title_case(
11279        &mut self,
11280        _: &ConvertToTitleCase,
11281        window: &mut Window,
11282        cx: &mut Context<Self>,
11283    ) {
11284        self.manipulate_text(window, cx, |text| {
11285            text.split('\n')
11286                .map(|line| line.to_case(Case::Title))
11287                .join("\n")
11288        })
11289    }
11290
11291    pub fn convert_to_snake_case(
11292        &mut self,
11293        _: &ConvertToSnakeCase,
11294        window: &mut Window,
11295        cx: &mut Context<Self>,
11296    ) {
11297        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11298    }
11299
11300    pub fn convert_to_kebab_case(
11301        &mut self,
11302        _: &ConvertToKebabCase,
11303        window: &mut Window,
11304        cx: &mut Context<Self>,
11305    ) {
11306        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11307    }
11308
11309    pub fn convert_to_upper_camel_case(
11310        &mut self,
11311        _: &ConvertToUpperCamelCase,
11312        window: &mut Window,
11313        cx: &mut Context<Self>,
11314    ) {
11315        self.manipulate_text(window, cx, |text| {
11316            text.split('\n')
11317                .map(|line| line.to_case(Case::UpperCamel))
11318                .join("\n")
11319        })
11320    }
11321
11322    pub fn convert_to_lower_camel_case(
11323        &mut self,
11324        _: &ConvertToLowerCamelCase,
11325        window: &mut Window,
11326        cx: &mut Context<Self>,
11327    ) {
11328        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11329    }
11330
11331    pub fn convert_to_opposite_case(
11332        &mut self,
11333        _: &ConvertToOppositeCase,
11334        window: &mut Window,
11335        cx: &mut Context<Self>,
11336    ) {
11337        self.manipulate_text(window, cx, |text| {
11338            text.chars()
11339                .fold(String::with_capacity(text.len()), |mut t, c| {
11340                    if c.is_uppercase() {
11341                        t.extend(c.to_lowercase());
11342                    } else {
11343                        t.extend(c.to_uppercase());
11344                    }
11345                    t
11346                })
11347        })
11348    }
11349
11350    pub fn convert_to_sentence_case(
11351        &mut self,
11352        _: &ConvertToSentenceCase,
11353        window: &mut Window,
11354        cx: &mut Context<Self>,
11355    ) {
11356        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11357    }
11358
11359    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11360        self.manipulate_text(window, cx, |text| {
11361            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11362            if has_upper_case_characters {
11363                text.to_lowercase()
11364            } else {
11365                text.to_uppercase()
11366            }
11367        })
11368    }
11369
11370    pub fn convert_to_rot13(
11371        &mut self,
11372        _: &ConvertToRot13,
11373        window: &mut Window,
11374        cx: &mut Context<Self>,
11375    ) {
11376        self.manipulate_text(window, cx, |text| {
11377            text.chars()
11378                .map(|c| match c {
11379                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11380                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11381                    _ => c,
11382                })
11383                .collect()
11384        })
11385    }
11386
11387    pub fn convert_to_rot47(
11388        &mut self,
11389        _: &ConvertToRot47,
11390        window: &mut Window,
11391        cx: &mut Context<Self>,
11392    ) {
11393        self.manipulate_text(window, cx, |text| {
11394            text.chars()
11395                .map(|c| {
11396                    let code_point = c as u32;
11397                    if code_point >= 33 && code_point <= 126 {
11398                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11399                    }
11400                    c
11401                })
11402                .collect()
11403        })
11404    }
11405
11406    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11407    where
11408        Fn: FnMut(&str) -> String,
11409    {
11410        let buffer = self.buffer.read(cx).snapshot(cx);
11411
11412        let mut new_selections = Vec::new();
11413        let mut edits = Vec::new();
11414        let mut selection_adjustment = 0i32;
11415
11416        for selection in self.selections.all_adjusted(cx) {
11417            let selection_is_empty = selection.is_empty();
11418
11419            let (start, end) = if selection_is_empty {
11420                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11421                (word_range.start, word_range.end)
11422            } else {
11423                (
11424                    buffer.point_to_offset(selection.start),
11425                    buffer.point_to_offset(selection.end),
11426                )
11427            };
11428
11429            let text = buffer.text_for_range(start..end).collect::<String>();
11430            let old_length = text.len() as i32;
11431            let text = callback(&text);
11432
11433            new_selections.push(Selection {
11434                start: (start as i32 - selection_adjustment) as usize,
11435                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11436                goal: SelectionGoal::None,
11437                id: selection.id,
11438                reversed: selection.reversed,
11439            });
11440
11441            selection_adjustment += old_length - text.len() as i32;
11442
11443            edits.push((start..end, text));
11444        }
11445
11446        self.transact(window, cx, |this, window, cx| {
11447            this.buffer.update(cx, |buffer, cx| {
11448                buffer.edit(edits, None, cx);
11449            });
11450
11451            this.change_selections(Default::default(), window, cx, |s| {
11452                s.select(new_selections);
11453            });
11454
11455            this.request_autoscroll(Autoscroll::fit(), cx);
11456        });
11457    }
11458
11459    pub fn move_selection_on_drop(
11460        &mut self,
11461        selection: &Selection<Anchor>,
11462        target: DisplayPoint,
11463        is_cut: bool,
11464        window: &mut Window,
11465        cx: &mut Context<Self>,
11466    ) {
11467        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11468        let buffer = &display_map.buffer_snapshot;
11469        let mut edits = Vec::new();
11470        let insert_point = display_map
11471            .clip_point(target, Bias::Left)
11472            .to_point(&display_map);
11473        let text = buffer
11474            .text_for_range(selection.start..selection.end)
11475            .collect::<String>();
11476        if is_cut {
11477            edits.push(((selection.start..selection.end), String::new()));
11478        }
11479        let insert_anchor = buffer.anchor_before(insert_point);
11480        edits.push(((insert_anchor..insert_anchor), text));
11481        let last_edit_start = insert_anchor.bias_left(buffer);
11482        let last_edit_end = insert_anchor.bias_right(buffer);
11483        self.transact(window, cx, |this, window, cx| {
11484            this.buffer.update(cx, |buffer, cx| {
11485                buffer.edit(edits, None, cx);
11486            });
11487            this.change_selections(Default::default(), window, cx, |s| {
11488                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11489            });
11490        });
11491    }
11492
11493    pub fn clear_selection_drag_state(&mut self) {
11494        self.selection_drag_state = SelectionDragState::None;
11495    }
11496
11497    pub fn duplicate(
11498        &mut self,
11499        upwards: bool,
11500        whole_lines: bool,
11501        window: &mut Window,
11502        cx: &mut Context<Self>,
11503    ) {
11504        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11505
11506        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11507        let buffer = &display_map.buffer_snapshot;
11508        let selections = self.selections.all::<Point>(cx);
11509
11510        let mut edits = Vec::new();
11511        let mut selections_iter = selections.iter().peekable();
11512        while let Some(selection) = selections_iter.next() {
11513            let mut rows = selection.spanned_rows(false, &display_map);
11514            // duplicate line-wise
11515            if whole_lines || selection.start == selection.end {
11516                // Avoid duplicating the same lines twice.
11517                while let Some(next_selection) = selections_iter.peek() {
11518                    let next_rows = next_selection.spanned_rows(false, &display_map);
11519                    if next_rows.start < rows.end {
11520                        rows.end = next_rows.end;
11521                        selections_iter.next().unwrap();
11522                    } else {
11523                        break;
11524                    }
11525                }
11526
11527                // Copy the text from the selected row region and splice it either at the start
11528                // or end of the region.
11529                let start = Point::new(rows.start.0, 0);
11530                let end = Point::new(
11531                    rows.end.previous_row().0,
11532                    buffer.line_len(rows.end.previous_row()),
11533                );
11534                let text = buffer
11535                    .text_for_range(start..end)
11536                    .chain(Some("\n"))
11537                    .collect::<String>();
11538                let insert_location = if upwards {
11539                    Point::new(rows.end.0, 0)
11540                } else {
11541                    start
11542                };
11543                edits.push((insert_location..insert_location, text));
11544            } else {
11545                // duplicate character-wise
11546                let start = selection.start;
11547                let end = selection.end;
11548                let text = buffer.text_for_range(start..end).collect::<String>();
11549                edits.push((selection.end..selection.end, text));
11550            }
11551        }
11552
11553        self.transact(window, cx, |this, _, cx| {
11554            this.buffer.update(cx, |buffer, cx| {
11555                buffer.edit(edits, None, cx);
11556            });
11557
11558            this.request_autoscroll(Autoscroll::fit(), cx);
11559        });
11560    }
11561
11562    pub fn duplicate_line_up(
11563        &mut self,
11564        _: &DuplicateLineUp,
11565        window: &mut Window,
11566        cx: &mut Context<Self>,
11567    ) {
11568        self.duplicate(true, true, window, cx);
11569    }
11570
11571    pub fn duplicate_line_down(
11572        &mut self,
11573        _: &DuplicateLineDown,
11574        window: &mut Window,
11575        cx: &mut Context<Self>,
11576    ) {
11577        self.duplicate(false, true, window, cx);
11578    }
11579
11580    pub fn duplicate_selection(
11581        &mut self,
11582        _: &DuplicateSelection,
11583        window: &mut Window,
11584        cx: &mut Context<Self>,
11585    ) {
11586        self.duplicate(false, false, window, cx);
11587    }
11588
11589    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11590        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11591        if self.mode.is_single_line() {
11592            cx.propagate();
11593            return;
11594        }
11595
11596        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11597        let buffer = self.buffer.read(cx).snapshot(cx);
11598
11599        let mut edits = Vec::new();
11600        let mut unfold_ranges = Vec::new();
11601        let mut refold_creases = Vec::new();
11602
11603        let selections = self.selections.all::<Point>(cx);
11604        let mut selections = selections.iter().peekable();
11605        let mut contiguous_row_selections = Vec::new();
11606        let mut new_selections = Vec::new();
11607
11608        while let Some(selection) = selections.next() {
11609            // Find all the selections that span a contiguous row range
11610            let (start_row, end_row) = consume_contiguous_rows(
11611                &mut contiguous_row_selections,
11612                selection,
11613                &display_map,
11614                &mut selections,
11615            );
11616
11617            // Move the text spanned by the row range to be before the line preceding the row range
11618            if start_row.0 > 0 {
11619                let range_to_move = Point::new(
11620                    start_row.previous_row().0,
11621                    buffer.line_len(start_row.previous_row()),
11622                )
11623                    ..Point::new(
11624                        end_row.previous_row().0,
11625                        buffer.line_len(end_row.previous_row()),
11626                    );
11627                let insertion_point = display_map
11628                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11629                    .0;
11630
11631                // Don't move lines across excerpts
11632                if buffer
11633                    .excerpt_containing(insertion_point..range_to_move.end)
11634                    .is_some()
11635                {
11636                    let text = buffer
11637                        .text_for_range(range_to_move.clone())
11638                        .flat_map(|s| s.chars())
11639                        .skip(1)
11640                        .chain(['\n'])
11641                        .collect::<String>();
11642
11643                    edits.push((
11644                        buffer.anchor_after(range_to_move.start)
11645                            ..buffer.anchor_before(range_to_move.end),
11646                        String::new(),
11647                    ));
11648                    let insertion_anchor = buffer.anchor_after(insertion_point);
11649                    edits.push((insertion_anchor..insertion_anchor, text));
11650
11651                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11652
11653                    // Move selections up
11654                    new_selections.extend(contiguous_row_selections.drain(..).map(
11655                        |mut selection| {
11656                            selection.start.row -= row_delta;
11657                            selection.end.row -= row_delta;
11658                            selection
11659                        },
11660                    ));
11661
11662                    // Move folds up
11663                    unfold_ranges.push(range_to_move.clone());
11664                    for fold in display_map.folds_in_range(
11665                        buffer.anchor_before(range_to_move.start)
11666                            ..buffer.anchor_after(range_to_move.end),
11667                    ) {
11668                        let mut start = fold.range.start.to_point(&buffer);
11669                        let mut end = fold.range.end.to_point(&buffer);
11670                        start.row -= row_delta;
11671                        end.row -= row_delta;
11672                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11673                    }
11674                }
11675            }
11676
11677            // If we didn't move line(s), preserve the existing selections
11678            new_selections.append(&mut contiguous_row_selections);
11679        }
11680
11681        self.transact(window, cx, |this, window, cx| {
11682            this.unfold_ranges(&unfold_ranges, true, true, cx);
11683            this.buffer.update(cx, |buffer, cx| {
11684                for (range, text) in edits {
11685                    buffer.edit([(range, text)], None, cx);
11686                }
11687            });
11688            this.fold_creases(refold_creases, true, window, cx);
11689            this.change_selections(Default::default(), window, cx, |s| {
11690                s.select(new_selections);
11691            })
11692        });
11693    }
11694
11695    pub fn move_line_down(
11696        &mut self,
11697        _: &MoveLineDown,
11698        window: &mut Window,
11699        cx: &mut Context<Self>,
11700    ) {
11701        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11702        if self.mode.is_single_line() {
11703            cx.propagate();
11704            return;
11705        }
11706
11707        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11708        let buffer = self.buffer.read(cx).snapshot(cx);
11709
11710        let mut edits = Vec::new();
11711        let mut unfold_ranges = Vec::new();
11712        let mut refold_creases = Vec::new();
11713
11714        let selections = self.selections.all::<Point>(cx);
11715        let mut selections = selections.iter().peekable();
11716        let mut contiguous_row_selections = Vec::new();
11717        let mut new_selections = Vec::new();
11718
11719        while let Some(selection) = selections.next() {
11720            // Find all the selections that span a contiguous row range
11721            let (start_row, end_row) = consume_contiguous_rows(
11722                &mut contiguous_row_selections,
11723                selection,
11724                &display_map,
11725                &mut selections,
11726            );
11727
11728            // Move the text spanned by the row range to be after the last line of the row range
11729            if end_row.0 <= buffer.max_point().row {
11730                let range_to_move =
11731                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11732                let insertion_point = display_map
11733                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11734                    .0;
11735
11736                // Don't move lines across excerpt boundaries
11737                if buffer
11738                    .excerpt_containing(range_to_move.start..insertion_point)
11739                    .is_some()
11740                {
11741                    let mut text = String::from("\n");
11742                    text.extend(buffer.text_for_range(range_to_move.clone()));
11743                    text.pop(); // Drop trailing newline
11744                    edits.push((
11745                        buffer.anchor_after(range_to_move.start)
11746                            ..buffer.anchor_before(range_to_move.end),
11747                        String::new(),
11748                    ));
11749                    let insertion_anchor = buffer.anchor_after(insertion_point);
11750                    edits.push((insertion_anchor..insertion_anchor, text));
11751
11752                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11753
11754                    // Move selections down
11755                    new_selections.extend(contiguous_row_selections.drain(..).map(
11756                        |mut selection| {
11757                            selection.start.row += row_delta;
11758                            selection.end.row += row_delta;
11759                            selection
11760                        },
11761                    ));
11762
11763                    // Move folds down
11764                    unfold_ranges.push(range_to_move.clone());
11765                    for fold in display_map.folds_in_range(
11766                        buffer.anchor_before(range_to_move.start)
11767                            ..buffer.anchor_after(range_to_move.end),
11768                    ) {
11769                        let mut start = fold.range.start.to_point(&buffer);
11770                        let mut end = fold.range.end.to_point(&buffer);
11771                        start.row += row_delta;
11772                        end.row += row_delta;
11773                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11774                    }
11775                }
11776            }
11777
11778            // If we didn't move line(s), preserve the existing selections
11779            new_selections.append(&mut contiguous_row_selections);
11780        }
11781
11782        self.transact(window, cx, |this, window, cx| {
11783            this.unfold_ranges(&unfold_ranges, true, true, cx);
11784            this.buffer.update(cx, |buffer, cx| {
11785                for (range, text) in edits {
11786                    buffer.edit([(range, text)], None, cx);
11787                }
11788            });
11789            this.fold_creases(refold_creases, true, window, cx);
11790            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11791        });
11792    }
11793
11794    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11795        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11796        let text_layout_details = &self.text_layout_details(window);
11797        self.transact(window, cx, |this, window, cx| {
11798            let edits = this.change_selections(Default::default(), window, cx, |s| {
11799                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11800                s.move_with(|display_map, selection| {
11801                    if !selection.is_empty() {
11802                        return;
11803                    }
11804
11805                    let mut head = selection.head();
11806                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11807                    if head.column() == display_map.line_len(head.row()) {
11808                        transpose_offset = display_map
11809                            .buffer_snapshot
11810                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11811                    }
11812
11813                    if transpose_offset == 0 {
11814                        return;
11815                    }
11816
11817                    *head.column_mut() += 1;
11818                    head = display_map.clip_point(head, Bias::Right);
11819                    let goal = SelectionGoal::HorizontalPosition(
11820                        display_map
11821                            .x_for_display_point(head, text_layout_details)
11822                            .into(),
11823                    );
11824                    selection.collapse_to(head, goal);
11825
11826                    let transpose_start = display_map
11827                        .buffer_snapshot
11828                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11829                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11830                        let transpose_end = display_map
11831                            .buffer_snapshot
11832                            .clip_offset(transpose_offset + 1, Bias::Right);
11833                        if let Some(ch) =
11834                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11835                        {
11836                            edits.push((transpose_start..transpose_offset, String::new()));
11837                            edits.push((transpose_end..transpose_end, ch.to_string()));
11838                        }
11839                    }
11840                });
11841                edits
11842            });
11843            this.buffer
11844                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11845            let selections = this.selections.all::<usize>(cx);
11846            this.change_selections(Default::default(), window, cx, |s| {
11847                s.select(selections);
11848            });
11849        });
11850    }
11851
11852    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11854        if self.mode.is_single_line() {
11855            cx.propagate();
11856            return;
11857        }
11858
11859        self.rewrap_impl(RewrapOptions::default(), cx)
11860    }
11861
11862    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11863        let buffer = self.buffer.read(cx).snapshot(cx);
11864        let selections = self.selections.all::<Point>(cx);
11865
11866        #[derive(Clone, Debug, PartialEq)]
11867        enum CommentFormat {
11868            /// single line comment, with prefix for line
11869            Line(String),
11870            /// single line within a block comment, with prefix for line
11871            BlockLine(String),
11872            /// a single line of a block comment that includes the initial delimiter
11873            BlockCommentWithStart(BlockCommentConfig),
11874            /// a single line of a block comment that includes the ending delimiter
11875            BlockCommentWithEnd(BlockCommentConfig),
11876        }
11877
11878        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11879        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11880            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11881                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11882                .peekable();
11883
11884            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11885                row
11886            } else {
11887                return Vec::new();
11888            };
11889
11890            let language_settings = buffer.language_settings_at(selection.head(), cx);
11891            let language_scope = buffer.language_scope_at(selection.head());
11892
11893            let indent_and_prefix_for_row =
11894                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11895                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11896                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11897                        &language_scope
11898                    {
11899                        let indent_end = Point::new(row, indent.len);
11900                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11901                        let line_text_after_indent = buffer
11902                            .text_for_range(indent_end..line_end)
11903                            .collect::<String>();
11904
11905                        let is_within_comment_override = buffer
11906                            .language_scope_at(indent_end)
11907                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11908                        let comment_delimiters = if is_within_comment_override {
11909                            // we are within a comment syntax node, but we don't
11910                            // yet know what kind of comment: block, doc or line
11911                            match (
11912                                language_scope.documentation_comment(),
11913                                language_scope.block_comment(),
11914                            ) {
11915                                (Some(config), _) | (_, Some(config))
11916                                    if buffer.contains_str_at(indent_end, &config.start) =>
11917                                {
11918                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11919                                }
11920                                (Some(config), _) | (_, Some(config))
11921                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11922                                {
11923                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11924                                }
11925                                (Some(config), _) | (_, Some(config))
11926                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11927                                {
11928                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11929                                }
11930                                (_, _) => language_scope
11931                                    .line_comment_prefixes()
11932                                    .iter()
11933                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11934                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11935                            }
11936                        } else {
11937                            // we not in an overridden comment node, but we may
11938                            // be within a non-overridden line comment node
11939                            language_scope
11940                                .line_comment_prefixes()
11941                                .iter()
11942                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11943                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11944                        };
11945
11946                        let rewrap_prefix = language_scope
11947                            .rewrap_prefixes()
11948                            .iter()
11949                            .find_map(|prefix_regex| {
11950                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11951                                    if mat.start() == 0 {
11952                                        Some(mat.as_str().to_string())
11953                                    } else {
11954                                        None
11955                                    }
11956                                })
11957                            })
11958                            .flatten();
11959                        (comment_delimiters, rewrap_prefix)
11960                    } else {
11961                        (None, None)
11962                    };
11963                    (indent, comment_prefix, rewrap_prefix)
11964                };
11965
11966            let mut ranges = Vec::new();
11967            let from_empty_selection = selection.is_empty();
11968
11969            let mut current_range_start = first_row;
11970            let mut prev_row = first_row;
11971            let (
11972                mut current_range_indent,
11973                mut current_range_comment_delimiters,
11974                mut current_range_rewrap_prefix,
11975            ) = indent_and_prefix_for_row(first_row);
11976
11977            for row in non_blank_rows_iter.skip(1) {
11978                let has_paragraph_break = row > prev_row + 1;
11979
11980                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
11981                    indent_and_prefix_for_row(row);
11982
11983                let has_indent_change = row_indent != current_range_indent;
11984                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
11985
11986                let has_boundary_change = has_comment_change
11987                    || row_rewrap_prefix.is_some()
11988                    || (has_indent_change && current_range_comment_delimiters.is_some());
11989
11990                if has_paragraph_break || has_boundary_change {
11991                    ranges.push((
11992                        language_settings.clone(),
11993                        Point::new(current_range_start, 0)
11994                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11995                        current_range_indent,
11996                        current_range_comment_delimiters.clone(),
11997                        current_range_rewrap_prefix.clone(),
11998                        from_empty_selection,
11999                    ));
12000                    current_range_start = row;
12001                    current_range_indent = row_indent;
12002                    current_range_comment_delimiters = row_comment_delimiters;
12003                    current_range_rewrap_prefix = row_rewrap_prefix;
12004                }
12005                prev_row = row;
12006            }
12007
12008            ranges.push((
12009                language_settings.clone(),
12010                Point::new(current_range_start, 0)
12011                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12012                current_range_indent,
12013                current_range_comment_delimiters,
12014                current_range_rewrap_prefix,
12015                from_empty_selection,
12016            ));
12017
12018            ranges
12019        });
12020
12021        let mut edits = Vec::new();
12022        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12023
12024        for (
12025            language_settings,
12026            wrap_range,
12027            mut indent_size,
12028            comment_prefix,
12029            rewrap_prefix,
12030            from_empty_selection,
12031        ) in wrap_ranges
12032        {
12033            let mut start_row = wrap_range.start.row;
12034            let mut end_row = wrap_range.end.row;
12035
12036            // Skip selections that overlap with a range that has already been rewrapped.
12037            let selection_range = start_row..end_row;
12038            if rewrapped_row_ranges
12039                .iter()
12040                .any(|range| range.overlaps(&selection_range))
12041            {
12042                continue;
12043            }
12044
12045            let tab_size = language_settings.tab_size;
12046
12047            let (line_prefix, inside_comment) = match &comment_prefix {
12048                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12049                    (Some(prefix.as_str()), true)
12050                }
12051                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12052                    (Some(prefix.as_ref()), true)
12053                }
12054                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12055                    start: _,
12056                    end: _,
12057                    prefix,
12058                    tab_size,
12059                })) => {
12060                    indent_size.len += tab_size;
12061                    (Some(prefix.as_ref()), true)
12062                }
12063                None => (None, false),
12064            };
12065            let indent_prefix = indent_size.chars().collect::<String>();
12066            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12067
12068            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12069                RewrapBehavior::InComments => inside_comment,
12070                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12071                RewrapBehavior::Anywhere => true,
12072            };
12073
12074            let should_rewrap = options.override_language_settings
12075                || allow_rewrap_based_on_language
12076                || self.hard_wrap.is_some();
12077            if !should_rewrap {
12078                continue;
12079            }
12080
12081            if from_empty_selection {
12082                'expand_upwards: while start_row > 0 {
12083                    let prev_row = start_row - 1;
12084                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12085                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12086                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12087                    {
12088                        start_row = prev_row;
12089                    } else {
12090                        break 'expand_upwards;
12091                    }
12092                }
12093
12094                'expand_downwards: while end_row < buffer.max_point().row {
12095                    let next_row = end_row + 1;
12096                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12097                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12098                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12099                    {
12100                        end_row = next_row;
12101                    } else {
12102                        break 'expand_downwards;
12103                    }
12104                }
12105            }
12106
12107            let start = Point::new(start_row, 0);
12108            let start_offset = start.to_offset(&buffer);
12109            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12110            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12111            let mut first_line_delimiter = None;
12112            let mut last_line_delimiter = None;
12113            let Some(lines_without_prefixes) = selection_text
12114                .lines()
12115                .enumerate()
12116                .map(|(ix, line)| {
12117                    let line_trimmed = line.trim_start();
12118                    if rewrap_prefix.is_some() && ix > 0 {
12119                        Ok(line_trimmed)
12120                    } else if let Some(
12121                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12122                            start,
12123                            prefix,
12124                            end,
12125                            tab_size,
12126                        })
12127                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12128                            start,
12129                            prefix,
12130                            end,
12131                            tab_size,
12132                        }),
12133                    ) = &comment_prefix
12134                    {
12135                        let line_trimmed = line_trimmed
12136                            .strip_prefix(start.as_ref())
12137                            .map(|s| {
12138                                let mut indent_size = indent_size;
12139                                indent_size.len -= tab_size;
12140                                let indent_prefix: String = indent_size.chars().collect();
12141                                first_line_delimiter = Some((indent_prefix, start));
12142                                s.trim_start()
12143                            })
12144                            .unwrap_or(line_trimmed);
12145                        let line_trimmed = line_trimmed
12146                            .strip_suffix(end.as_ref())
12147                            .map(|s| {
12148                                last_line_delimiter = Some(end);
12149                                s.trim_end()
12150                            })
12151                            .unwrap_or(line_trimmed);
12152                        let line_trimmed = line_trimmed
12153                            .strip_prefix(prefix.as_ref())
12154                            .unwrap_or(line_trimmed);
12155                        Ok(line_trimmed)
12156                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12157                        line_trimmed.strip_prefix(prefix).with_context(|| {
12158                            format!("line did not start with prefix {prefix:?}: {line:?}")
12159                        })
12160                    } else {
12161                        line_trimmed
12162                            .strip_prefix(&line_prefix.trim_start())
12163                            .with_context(|| {
12164                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12165                            })
12166                    }
12167                })
12168                .collect::<Result<Vec<_>, _>>()
12169                .log_err()
12170            else {
12171                continue;
12172            };
12173
12174            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12175                buffer
12176                    .language_settings_at(Point::new(start_row, 0), cx)
12177                    .preferred_line_length as usize
12178            });
12179
12180            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12181                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12182            } else {
12183                line_prefix.clone()
12184            };
12185
12186            let wrapped_text = {
12187                let mut wrapped_text = wrap_with_prefix(
12188                    line_prefix,
12189                    subsequent_lines_prefix,
12190                    lines_without_prefixes.join("\n"),
12191                    wrap_column,
12192                    tab_size,
12193                    options.preserve_existing_whitespace,
12194                );
12195
12196                if let Some((indent, delimiter)) = first_line_delimiter {
12197                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12198                }
12199                if let Some(last_line) = last_line_delimiter {
12200                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12201                }
12202
12203                wrapped_text
12204            };
12205
12206            // TODO: should always use char-based diff while still supporting cursor behavior that
12207            // matches vim.
12208            let mut diff_options = DiffOptions::default();
12209            if options.override_language_settings {
12210                diff_options.max_word_diff_len = 0;
12211                diff_options.max_word_diff_line_count = 0;
12212            } else {
12213                diff_options.max_word_diff_len = usize::MAX;
12214                diff_options.max_word_diff_line_count = usize::MAX;
12215            }
12216
12217            for (old_range, new_text) in
12218                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12219            {
12220                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12221                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12222                edits.push((edit_start..edit_end, new_text));
12223            }
12224
12225            rewrapped_row_ranges.push(start_row..=end_row);
12226        }
12227
12228        self.buffer
12229            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12230    }
12231
12232    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
12233        let mut text = String::new();
12234        let buffer = self.buffer.read(cx).snapshot(cx);
12235        let mut selections = self.selections.all::<Point>(cx);
12236        let mut clipboard_selections = Vec::with_capacity(selections.len());
12237        {
12238            let max_point = buffer.max_point();
12239            let mut is_first = true;
12240            for selection in &mut selections {
12241                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12242                if is_entire_line {
12243                    selection.start = Point::new(selection.start.row, 0);
12244                    if !selection.is_empty() && selection.end.column == 0 {
12245                        selection.end = cmp::min(max_point, selection.end);
12246                    } else {
12247                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12248                    }
12249                    selection.goal = SelectionGoal::None;
12250                }
12251                if is_first {
12252                    is_first = false;
12253                } else {
12254                    text += "\n";
12255                }
12256                let mut len = 0;
12257                for chunk in buffer.text_for_range(selection.start..selection.end) {
12258                    text.push_str(chunk);
12259                    len += chunk.len();
12260                }
12261                clipboard_selections.push(ClipboardSelection {
12262                    len,
12263                    is_entire_line,
12264                    first_line_indent: buffer
12265                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12266                        .len,
12267                });
12268            }
12269        }
12270
12271        self.transact(window, cx, |this, window, cx| {
12272            this.change_selections(Default::default(), window, cx, |s| {
12273                s.select(selections);
12274            });
12275            this.insert("", window, cx);
12276        });
12277        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12278    }
12279
12280    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12281        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12282        let item = self.cut_common(window, cx);
12283        cx.write_to_clipboard(item);
12284    }
12285
12286    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12287        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12288        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12289            s.move_with(|snapshot, sel| {
12290                if sel.is_empty() {
12291                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12292                }
12293            });
12294        });
12295        let item = self.cut_common(window, cx);
12296        cx.set_global(KillRing(item))
12297    }
12298
12299    pub fn kill_ring_yank(
12300        &mut self,
12301        _: &KillRingYank,
12302        window: &mut Window,
12303        cx: &mut Context<Self>,
12304    ) {
12305        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12306        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12307            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12308                (kill_ring.text().to_string(), kill_ring.metadata_json())
12309            } else {
12310                return;
12311            }
12312        } else {
12313            return;
12314        };
12315        self.do_paste(&text, metadata, false, window, cx);
12316    }
12317
12318    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12319        self.do_copy(true, cx);
12320    }
12321
12322    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12323        self.do_copy(false, cx);
12324    }
12325
12326    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12327        let selections = self.selections.all::<Point>(cx);
12328        let buffer = self.buffer.read(cx).read(cx);
12329        let mut text = String::new();
12330
12331        let mut clipboard_selections = Vec::with_capacity(selections.len());
12332        {
12333            let max_point = buffer.max_point();
12334            let mut is_first = true;
12335            for selection in &selections {
12336                let mut start = selection.start;
12337                let mut end = selection.end;
12338                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12339                if is_entire_line {
12340                    start = Point::new(start.row, 0);
12341                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12342                }
12343
12344                let mut trimmed_selections = Vec::new();
12345                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12346                    let row = MultiBufferRow(start.row);
12347                    let first_indent = buffer.indent_size_for_line(row);
12348                    if first_indent.len == 0 || start.column > first_indent.len {
12349                        trimmed_selections.push(start..end);
12350                    } else {
12351                        trimmed_selections.push(
12352                            Point::new(row.0, first_indent.len)
12353                                ..Point::new(row.0, buffer.line_len(row)),
12354                        );
12355                        for row in start.row + 1..=end.row {
12356                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12357                            if row == end.row {
12358                                line_len = end.column;
12359                            }
12360                            if line_len == 0 {
12361                                trimmed_selections
12362                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12363                                continue;
12364                            }
12365                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12366                            if row_indent_size.len >= first_indent.len {
12367                                trimmed_selections.push(
12368                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12369                                );
12370                            } else {
12371                                trimmed_selections.clear();
12372                                trimmed_selections.push(start..end);
12373                                break;
12374                            }
12375                        }
12376                    }
12377                } else {
12378                    trimmed_selections.push(start..end);
12379                }
12380
12381                for trimmed_range in trimmed_selections {
12382                    if is_first {
12383                        is_first = false;
12384                    } else {
12385                        text += "\n";
12386                    }
12387                    let mut len = 0;
12388                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12389                        text.push_str(chunk);
12390                        len += chunk.len();
12391                    }
12392                    clipboard_selections.push(ClipboardSelection {
12393                        len,
12394                        is_entire_line,
12395                        first_line_indent: buffer
12396                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12397                            .len,
12398                    });
12399                }
12400            }
12401        }
12402
12403        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12404            text,
12405            clipboard_selections,
12406        ));
12407    }
12408
12409    pub fn do_paste(
12410        &mut self,
12411        text: &String,
12412        clipboard_selections: Option<Vec<ClipboardSelection>>,
12413        handle_entire_lines: bool,
12414        window: &mut Window,
12415        cx: &mut Context<Self>,
12416    ) {
12417        if self.read_only(cx) {
12418            return;
12419        }
12420
12421        let clipboard_text = Cow::Borrowed(text);
12422
12423        self.transact(window, cx, |this, window, cx| {
12424            let had_active_edit_prediction = this.has_active_edit_prediction();
12425
12426            if let Some(mut clipboard_selections) = clipboard_selections {
12427                let old_selections = this.selections.all::<usize>(cx);
12428                let all_selections_were_entire_line =
12429                    clipboard_selections.iter().all(|s| s.is_entire_line);
12430                let first_selection_indent_column =
12431                    clipboard_selections.first().map(|s| s.first_line_indent);
12432                if clipboard_selections.len() != old_selections.len() {
12433                    clipboard_selections.drain(..);
12434                }
12435                let cursor_offset = this.selections.last::<usize>(cx).head();
12436                let mut auto_indent_on_paste = true;
12437
12438                this.buffer.update(cx, |buffer, cx| {
12439                    let snapshot = buffer.read(cx);
12440                    auto_indent_on_paste = snapshot
12441                        .language_settings_at(cursor_offset, cx)
12442                        .auto_indent_on_paste;
12443
12444                    let mut start_offset = 0;
12445                    let mut edits = Vec::new();
12446                    let mut original_indent_columns = Vec::new();
12447                    for (ix, selection) in old_selections.iter().enumerate() {
12448                        let to_insert;
12449                        let entire_line;
12450                        let original_indent_column;
12451                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12452                            let end_offset = start_offset + clipboard_selection.len;
12453                            to_insert = &clipboard_text[start_offset..end_offset];
12454                            entire_line = clipboard_selection.is_entire_line;
12455                            start_offset = end_offset + 1;
12456                            original_indent_column = Some(clipboard_selection.first_line_indent);
12457                        } else {
12458                            to_insert = clipboard_text.as_str();
12459                            entire_line = all_selections_were_entire_line;
12460                            original_indent_column = first_selection_indent_column
12461                        }
12462
12463                        // If the corresponding selection was empty when this slice of the
12464                        // clipboard text was written, then the entire line containing the
12465                        // selection was copied. If this selection is also currently empty,
12466                        // then paste the line before the current line of the buffer.
12467                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12468                            let column = selection.start.to_point(&snapshot).column as usize;
12469                            let line_start = selection.start - column;
12470                            line_start..line_start
12471                        } else {
12472                            selection.range()
12473                        };
12474
12475                        edits.push((range, to_insert));
12476                        original_indent_columns.push(original_indent_column);
12477                    }
12478                    drop(snapshot);
12479
12480                    buffer.edit(
12481                        edits,
12482                        if auto_indent_on_paste {
12483                            Some(AutoindentMode::Block {
12484                                original_indent_columns,
12485                            })
12486                        } else {
12487                            None
12488                        },
12489                        cx,
12490                    );
12491                });
12492
12493                let selections = this.selections.all::<usize>(cx);
12494                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12495            } else {
12496                this.insert(&clipboard_text, window, cx);
12497            }
12498
12499            let trigger_in_words =
12500                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12501
12502            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12503        });
12504    }
12505
12506    pub fn diff_clipboard_with_selection(
12507        &mut self,
12508        _: &DiffClipboardWithSelection,
12509        window: &mut Window,
12510        cx: &mut Context<Self>,
12511    ) {
12512        let selections = self.selections.all::<usize>(cx);
12513
12514        if selections.is_empty() {
12515            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12516            return;
12517        };
12518
12519        let clipboard_text = match cx.read_from_clipboard() {
12520            Some(item) => match item.entries().first() {
12521                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12522                _ => None,
12523            },
12524            None => None,
12525        };
12526
12527        let Some(clipboard_text) = clipboard_text else {
12528            log::warn!("Clipboard doesn't contain text.");
12529            return;
12530        };
12531
12532        window.dispatch_action(
12533            Box::new(DiffClipboardWithSelectionData {
12534                clipboard_text,
12535                editor: cx.entity(),
12536            }),
12537            cx,
12538        );
12539    }
12540
12541    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12542        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12543        if let Some(item) = cx.read_from_clipboard() {
12544            let entries = item.entries();
12545
12546            match entries.first() {
12547                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12548                // of all the pasted entries.
12549                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12550                    .do_paste(
12551                        clipboard_string.text(),
12552                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12553                        true,
12554                        window,
12555                        cx,
12556                    ),
12557                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12558            }
12559        }
12560    }
12561
12562    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12563        if self.read_only(cx) {
12564            return;
12565        }
12566
12567        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12568
12569        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12570            if let Some((selections, _)) =
12571                self.selection_history.transaction(transaction_id).cloned()
12572            {
12573                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12574                    s.select_anchors(selections.to_vec());
12575                });
12576            } else {
12577                log::error!(
12578                    "No entry in selection_history found for undo. \
12579                     This may correspond to a bug where undo does not update the selection. \
12580                     If this is occurring, please add details to \
12581                     https://github.com/zed-industries/zed/issues/22692"
12582                );
12583            }
12584            self.request_autoscroll(Autoscroll::fit(), cx);
12585            self.unmark_text(window, cx);
12586            self.refresh_edit_prediction(true, false, window, cx);
12587            cx.emit(EditorEvent::Edited { transaction_id });
12588            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12589        }
12590    }
12591
12592    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12593        if self.read_only(cx) {
12594            return;
12595        }
12596
12597        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12598
12599        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12600            if let Some((_, Some(selections))) =
12601                self.selection_history.transaction(transaction_id).cloned()
12602            {
12603                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12604                    s.select_anchors(selections.to_vec());
12605                });
12606            } else {
12607                log::error!(
12608                    "No entry in selection_history found for redo. \
12609                     This may correspond to a bug where undo does not update the selection. \
12610                     If this is occurring, please add details to \
12611                     https://github.com/zed-industries/zed/issues/22692"
12612                );
12613            }
12614            self.request_autoscroll(Autoscroll::fit(), cx);
12615            self.unmark_text(window, cx);
12616            self.refresh_edit_prediction(true, false, window, cx);
12617            cx.emit(EditorEvent::Edited { transaction_id });
12618        }
12619    }
12620
12621    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12622        self.buffer
12623            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12624    }
12625
12626    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12627        self.buffer
12628            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12629    }
12630
12631    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12632        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12633        self.change_selections(Default::default(), window, cx, |s| {
12634            s.move_with(|map, selection| {
12635                let cursor = if selection.is_empty() {
12636                    movement::left(map, selection.start)
12637                } else {
12638                    selection.start
12639                };
12640                selection.collapse_to(cursor, SelectionGoal::None);
12641            });
12642        })
12643    }
12644
12645    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12646        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12647        self.change_selections(Default::default(), window, cx, |s| {
12648            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12649        })
12650    }
12651
12652    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12653        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12654        self.change_selections(Default::default(), window, cx, |s| {
12655            s.move_with(|map, selection| {
12656                let cursor = if selection.is_empty() {
12657                    movement::right(map, selection.end)
12658                } else {
12659                    selection.end
12660                };
12661                selection.collapse_to(cursor, SelectionGoal::None)
12662            });
12663        })
12664    }
12665
12666    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12667        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12668        self.change_selections(Default::default(), window, cx, |s| {
12669            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12670        })
12671    }
12672
12673    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12674        if self.take_rename(true, window, cx).is_some() {
12675            return;
12676        }
12677
12678        if self.mode.is_single_line() {
12679            cx.propagate();
12680            return;
12681        }
12682
12683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12684
12685        let text_layout_details = &self.text_layout_details(window);
12686        let selection_count = self.selections.count();
12687        let first_selection = self.selections.first_anchor();
12688
12689        self.change_selections(Default::default(), window, cx, |s| {
12690            s.move_with(|map, selection| {
12691                if !selection.is_empty() {
12692                    selection.goal = SelectionGoal::None;
12693                }
12694                let (cursor, goal) = movement::up(
12695                    map,
12696                    selection.start,
12697                    selection.goal,
12698                    false,
12699                    text_layout_details,
12700                );
12701                selection.collapse_to(cursor, goal);
12702            });
12703        });
12704
12705        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12706        {
12707            cx.propagate();
12708        }
12709    }
12710
12711    pub fn move_up_by_lines(
12712        &mut self,
12713        action: &MoveUpByLines,
12714        window: &mut Window,
12715        cx: &mut Context<Self>,
12716    ) {
12717        if self.take_rename(true, window, cx).is_some() {
12718            return;
12719        }
12720
12721        if self.mode.is_single_line() {
12722            cx.propagate();
12723            return;
12724        }
12725
12726        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12727
12728        let text_layout_details = &self.text_layout_details(window);
12729
12730        self.change_selections(Default::default(), window, cx, |s| {
12731            s.move_with(|map, selection| {
12732                if !selection.is_empty() {
12733                    selection.goal = SelectionGoal::None;
12734                }
12735                let (cursor, goal) = movement::up_by_rows(
12736                    map,
12737                    selection.start,
12738                    action.lines,
12739                    selection.goal,
12740                    false,
12741                    text_layout_details,
12742                );
12743                selection.collapse_to(cursor, goal);
12744            });
12745        })
12746    }
12747
12748    pub fn move_down_by_lines(
12749        &mut self,
12750        action: &MoveDownByLines,
12751        window: &mut Window,
12752        cx: &mut Context<Self>,
12753    ) {
12754        if self.take_rename(true, window, cx).is_some() {
12755            return;
12756        }
12757
12758        if self.mode.is_single_line() {
12759            cx.propagate();
12760            return;
12761        }
12762
12763        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12764
12765        let text_layout_details = &self.text_layout_details(window);
12766
12767        self.change_selections(Default::default(), window, cx, |s| {
12768            s.move_with(|map, selection| {
12769                if !selection.is_empty() {
12770                    selection.goal = SelectionGoal::None;
12771                }
12772                let (cursor, goal) = movement::down_by_rows(
12773                    map,
12774                    selection.start,
12775                    action.lines,
12776                    selection.goal,
12777                    false,
12778                    text_layout_details,
12779                );
12780                selection.collapse_to(cursor, goal);
12781            });
12782        })
12783    }
12784
12785    pub fn select_down_by_lines(
12786        &mut self,
12787        action: &SelectDownByLines,
12788        window: &mut Window,
12789        cx: &mut Context<Self>,
12790    ) {
12791        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12792        let text_layout_details = &self.text_layout_details(window);
12793        self.change_selections(Default::default(), window, cx, |s| {
12794            s.move_heads_with(|map, head, goal| {
12795                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12796            })
12797        })
12798    }
12799
12800    pub fn select_up_by_lines(
12801        &mut self,
12802        action: &SelectUpByLines,
12803        window: &mut Window,
12804        cx: &mut Context<Self>,
12805    ) {
12806        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12807        let text_layout_details = &self.text_layout_details(window);
12808        self.change_selections(Default::default(), window, cx, |s| {
12809            s.move_heads_with(|map, head, goal| {
12810                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12811            })
12812        })
12813    }
12814
12815    pub fn select_page_up(
12816        &mut self,
12817        _: &SelectPageUp,
12818        window: &mut Window,
12819        cx: &mut Context<Self>,
12820    ) {
12821        let Some(row_count) = self.visible_row_count() else {
12822            return;
12823        };
12824
12825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12826
12827        let text_layout_details = &self.text_layout_details(window);
12828
12829        self.change_selections(Default::default(), window, cx, |s| {
12830            s.move_heads_with(|map, head, goal| {
12831                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12832            })
12833        })
12834    }
12835
12836    pub fn move_page_up(
12837        &mut self,
12838        action: &MovePageUp,
12839        window: &mut Window,
12840        cx: &mut Context<Self>,
12841    ) {
12842        if self.take_rename(true, window, cx).is_some() {
12843            return;
12844        }
12845
12846        if self
12847            .context_menu
12848            .borrow_mut()
12849            .as_mut()
12850            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12851            .unwrap_or(false)
12852        {
12853            return;
12854        }
12855
12856        if matches!(self.mode, EditorMode::SingleLine) {
12857            cx.propagate();
12858            return;
12859        }
12860
12861        let Some(row_count) = self.visible_row_count() else {
12862            return;
12863        };
12864
12865        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12866
12867        let effects = if action.center_cursor {
12868            SelectionEffects::scroll(Autoscroll::center())
12869        } else {
12870            SelectionEffects::default()
12871        };
12872
12873        let text_layout_details = &self.text_layout_details(window);
12874
12875        self.change_selections(effects, window, cx, |s| {
12876            s.move_with(|map, selection| {
12877                if !selection.is_empty() {
12878                    selection.goal = SelectionGoal::None;
12879                }
12880                let (cursor, goal) = movement::up_by_rows(
12881                    map,
12882                    selection.end,
12883                    row_count,
12884                    selection.goal,
12885                    false,
12886                    text_layout_details,
12887                );
12888                selection.collapse_to(cursor, goal);
12889            });
12890        });
12891    }
12892
12893    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12894        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12895        let text_layout_details = &self.text_layout_details(window);
12896        self.change_selections(Default::default(), window, cx, |s| {
12897            s.move_heads_with(|map, head, goal| {
12898                movement::up(map, head, goal, false, text_layout_details)
12899            })
12900        })
12901    }
12902
12903    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12904        self.take_rename(true, window, cx);
12905
12906        if self.mode.is_single_line() {
12907            cx.propagate();
12908            return;
12909        }
12910
12911        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12912
12913        let text_layout_details = &self.text_layout_details(window);
12914        let selection_count = self.selections.count();
12915        let first_selection = self.selections.first_anchor();
12916
12917        self.change_selections(Default::default(), window, cx, |s| {
12918            s.move_with(|map, selection| {
12919                if !selection.is_empty() {
12920                    selection.goal = SelectionGoal::None;
12921                }
12922                let (cursor, goal) = movement::down(
12923                    map,
12924                    selection.end,
12925                    selection.goal,
12926                    false,
12927                    text_layout_details,
12928                );
12929                selection.collapse_to(cursor, goal);
12930            });
12931        });
12932
12933        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12934        {
12935            cx.propagate();
12936        }
12937    }
12938
12939    pub fn select_page_down(
12940        &mut self,
12941        _: &SelectPageDown,
12942        window: &mut Window,
12943        cx: &mut Context<Self>,
12944    ) {
12945        let Some(row_count) = self.visible_row_count() else {
12946            return;
12947        };
12948
12949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12950
12951        let text_layout_details = &self.text_layout_details(window);
12952
12953        self.change_selections(Default::default(), window, cx, |s| {
12954            s.move_heads_with(|map, head, goal| {
12955                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12956            })
12957        })
12958    }
12959
12960    pub fn move_page_down(
12961        &mut self,
12962        action: &MovePageDown,
12963        window: &mut Window,
12964        cx: &mut Context<Self>,
12965    ) {
12966        if self.take_rename(true, window, cx).is_some() {
12967            return;
12968        }
12969
12970        if self
12971            .context_menu
12972            .borrow_mut()
12973            .as_mut()
12974            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12975            .unwrap_or(false)
12976        {
12977            return;
12978        }
12979
12980        if matches!(self.mode, EditorMode::SingleLine) {
12981            cx.propagate();
12982            return;
12983        }
12984
12985        let Some(row_count) = self.visible_row_count() else {
12986            return;
12987        };
12988
12989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12990
12991        let effects = if action.center_cursor {
12992            SelectionEffects::scroll(Autoscroll::center())
12993        } else {
12994            SelectionEffects::default()
12995        };
12996
12997        let text_layout_details = &self.text_layout_details(window);
12998        self.change_selections(effects, window, cx, |s| {
12999            s.move_with(|map, selection| {
13000                if !selection.is_empty() {
13001                    selection.goal = SelectionGoal::None;
13002                }
13003                let (cursor, goal) = movement::down_by_rows(
13004                    map,
13005                    selection.end,
13006                    row_count,
13007                    selection.goal,
13008                    false,
13009                    text_layout_details,
13010                );
13011                selection.collapse_to(cursor, goal);
13012            });
13013        });
13014    }
13015
13016    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13017        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13018        let text_layout_details = &self.text_layout_details(window);
13019        self.change_selections(Default::default(), window, cx, |s| {
13020            s.move_heads_with(|map, head, goal| {
13021                movement::down(map, head, goal, false, text_layout_details)
13022            })
13023        });
13024    }
13025
13026    pub fn context_menu_first(
13027        &mut self,
13028        _: &ContextMenuFirst,
13029        window: &mut Window,
13030        cx: &mut Context<Self>,
13031    ) {
13032        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13033            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13034        }
13035    }
13036
13037    pub fn context_menu_prev(
13038        &mut self,
13039        _: &ContextMenuPrevious,
13040        window: &mut Window,
13041        cx: &mut Context<Self>,
13042    ) {
13043        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13044            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13045        }
13046    }
13047
13048    pub fn context_menu_next(
13049        &mut self,
13050        _: &ContextMenuNext,
13051        window: &mut Window,
13052        cx: &mut Context<Self>,
13053    ) {
13054        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13055            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13056        }
13057    }
13058
13059    pub fn context_menu_last(
13060        &mut self,
13061        _: &ContextMenuLast,
13062        window: &mut Window,
13063        cx: &mut Context<Self>,
13064    ) {
13065        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13066            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13067        }
13068    }
13069
13070    pub fn signature_help_prev(
13071        &mut self,
13072        _: &SignatureHelpPrevious,
13073        _: &mut Window,
13074        cx: &mut Context<Self>,
13075    ) {
13076        if let Some(popover) = self.signature_help_state.popover_mut() {
13077            if popover.current_signature == 0 {
13078                popover.current_signature = popover.signatures.len() - 1;
13079            } else {
13080                popover.current_signature -= 1;
13081            }
13082            cx.notify();
13083        }
13084    }
13085
13086    pub fn signature_help_next(
13087        &mut self,
13088        _: &SignatureHelpNext,
13089        _: &mut Window,
13090        cx: &mut Context<Self>,
13091    ) {
13092        if let Some(popover) = self.signature_help_state.popover_mut() {
13093            if popover.current_signature + 1 == popover.signatures.len() {
13094                popover.current_signature = 0;
13095            } else {
13096                popover.current_signature += 1;
13097            }
13098            cx.notify();
13099        }
13100    }
13101
13102    pub fn move_to_previous_word_start(
13103        &mut self,
13104        _: &MoveToPreviousWordStart,
13105        window: &mut Window,
13106        cx: &mut Context<Self>,
13107    ) {
13108        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13109        self.change_selections(Default::default(), window, cx, |s| {
13110            s.move_cursors_with(|map, head, _| {
13111                (
13112                    movement::previous_word_start(map, head),
13113                    SelectionGoal::None,
13114                )
13115            });
13116        })
13117    }
13118
13119    pub fn move_to_previous_subword_start(
13120        &mut self,
13121        _: &MoveToPreviousSubwordStart,
13122        window: &mut Window,
13123        cx: &mut Context<Self>,
13124    ) {
13125        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13126        self.change_selections(Default::default(), window, cx, |s| {
13127            s.move_cursors_with(|map, head, _| {
13128                (
13129                    movement::previous_subword_start(map, head),
13130                    SelectionGoal::None,
13131                )
13132            });
13133        })
13134    }
13135
13136    pub fn select_to_previous_word_start(
13137        &mut self,
13138        _: &SelectToPreviousWordStart,
13139        window: &mut Window,
13140        cx: &mut Context<Self>,
13141    ) {
13142        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13143        self.change_selections(Default::default(), window, cx, |s| {
13144            s.move_heads_with(|map, head, _| {
13145                (
13146                    movement::previous_word_start(map, head),
13147                    SelectionGoal::None,
13148                )
13149            });
13150        })
13151    }
13152
13153    pub fn select_to_previous_subword_start(
13154        &mut self,
13155        _: &SelectToPreviousSubwordStart,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13160        self.change_selections(Default::default(), window, cx, |s| {
13161            s.move_heads_with(|map, head, _| {
13162                (
13163                    movement::previous_subword_start(map, head),
13164                    SelectionGoal::None,
13165                )
13166            });
13167        })
13168    }
13169
13170    pub fn delete_to_previous_word_start(
13171        &mut self,
13172        action: &DeleteToPreviousWordStart,
13173        window: &mut Window,
13174        cx: &mut Context<Self>,
13175    ) {
13176        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13177        self.transact(window, cx, |this, window, cx| {
13178            this.select_autoclose_pair(window, cx);
13179            this.change_selections(Default::default(), window, cx, |s| {
13180                s.move_with(|map, selection| {
13181                    if selection.is_empty() {
13182                        let mut cursor = if action.ignore_newlines {
13183                            movement::previous_word_start(map, selection.head())
13184                        } else {
13185                            movement::previous_word_start_or_newline(map, selection.head())
13186                        };
13187                        cursor = movement::adjust_greedy_deletion(
13188                            map,
13189                            selection.head(),
13190                            cursor,
13191                            action.ignore_brackets,
13192                        );
13193                        selection.set_head(cursor, SelectionGoal::None);
13194                    }
13195                });
13196            });
13197            this.insert("", window, cx);
13198        });
13199    }
13200
13201    pub fn delete_to_previous_subword_start(
13202        &mut self,
13203        _: &DeleteToPreviousSubwordStart,
13204        window: &mut Window,
13205        cx: &mut Context<Self>,
13206    ) {
13207        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13208        self.transact(window, cx, |this, window, cx| {
13209            this.select_autoclose_pair(window, cx);
13210            this.change_selections(Default::default(), window, cx, |s| {
13211                s.move_with(|map, selection| {
13212                    if selection.is_empty() {
13213                        let mut cursor = movement::previous_subword_start(map, selection.head());
13214                        cursor =
13215                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13216                        selection.set_head(cursor, SelectionGoal::None);
13217                    }
13218                });
13219            });
13220            this.insert("", window, cx);
13221        });
13222    }
13223
13224    pub fn move_to_next_word_end(
13225        &mut self,
13226        _: &MoveToNextWordEnd,
13227        window: &mut Window,
13228        cx: &mut Context<Self>,
13229    ) {
13230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13231        self.change_selections(Default::default(), window, cx, |s| {
13232            s.move_cursors_with(|map, head, _| {
13233                (movement::next_word_end(map, head), SelectionGoal::None)
13234            });
13235        })
13236    }
13237
13238    pub fn move_to_next_subword_end(
13239        &mut self,
13240        _: &MoveToNextSubwordEnd,
13241        window: &mut Window,
13242        cx: &mut Context<Self>,
13243    ) {
13244        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13245        self.change_selections(Default::default(), window, cx, |s| {
13246            s.move_cursors_with(|map, head, _| {
13247                (movement::next_subword_end(map, head), SelectionGoal::None)
13248            });
13249        })
13250    }
13251
13252    pub fn select_to_next_word_end(
13253        &mut self,
13254        _: &SelectToNextWordEnd,
13255        window: &mut Window,
13256        cx: &mut Context<Self>,
13257    ) {
13258        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13259        self.change_selections(Default::default(), window, cx, |s| {
13260            s.move_heads_with(|map, head, _| {
13261                (movement::next_word_end(map, head), SelectionGoal::None)
13262            });
13263        })
13264    }
13265
13266    pub fn select_to_next_subword_end(
13267        &mut self,
13268        _: &SelectToNextSubwordEnd,
13269        window: &mut Window,
13270        cx: &mut Context<Self>,
13271    ) {
13272        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13273        self.change_selections(Default::default(), window, cx, |s| {
13274            s.move_heads_with(|map, head, _| {
13275                (movement::next_subword_end(map, head), SelectionGoal::None)
13276            });
13277        })
13278    }
13279
13280    pub fn delete_to_next_word_end(
13281        &mut self,
13282        action: &DeleteToNextWordEnd,
13283        window: &mut Window,
13284        cx: &mut Context<Self>,
13285    ) {
13286        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13287        self.transact(window, cx, |this, window, cx| {
13288            this.change_selections(Default::default(), window, cx, |s| {
13289                s.move_with(|map, selection| {
13290                    if selection.is_empty() {
13291                        let mut cursor = if action.ignore_newlines {
13292                            movement::next_word_end(map, selection.head())
13293                        } else {
13294                            movement::next_word_end_or_newline(map, selection.head())
13295                        };
13296                        cursor = movement::adjust_greedy_deletion(
13297                            map,
13298                            selection.head(),
13299                            cursor,
13300                            action.ignore_brackets,
13301                        );
13302                        selection.set_head(cursor, SelectionGoal::None);
13303                    }
13304                });
13305            });
13306            this.insert("", window, cx);
13307        });
13308    }
13309
13310    pub fn delete_to_next_subword_end(
13311        &mut self,
13312        _: &DeleteToNextSubwordEnd,
13313        window: &mut Window,
13314        cx: &mut Context<Self>,
13315    ) {
13316        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13317        self.transact(window, cx, |this, window, cx| {
13318            this.change_selections(Default::default(), window, cx, |s| {
13319                s.move_with(|map, selection| {
13320                    if selection.is_empty() {
13321                        let mut cursor = movement::next_subword_end(map, selection.head());
13322                        cursor =
13323                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13324                        selection.set_head(cursor, SelectionGoal::None);
13325                    }
13326                });
13327            });
13328            this.insert("", window, cx);
13329        });
13330    }
13331
13332    pub fn move_to_beginning_of_line(
13333        &mut self,
13334        action: &MoveToBeginningOfLine,
13335        window: &mut Window,
13336        cx: &mut Context<Self>,
13337    ) {
13338        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13339        self.change_selections(Default::default(), window, cx, |s| {
13340            s.move_cursors_with(|map, head, _| {
13341                (
13342                    movement::indented_line_beginning(
13343                        map,
13344                        head,
13345                        action.stop_at_soft_wraps,
13346                        action.stop_at_indent,
13347                    ),
13348                    SelectionGoal::None,
13349                )
13350            });
13351        })
13352    }
13353
13354    pub fn select_to_beginning_of_line(
13355        &mut self,
13356        action: &SelectToBeginningOfLine,
13357        window: &mut Window,
13358        cx: &mut Context<Self>,
13359    ) {
13360        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13361        self.change_selections(Default::default(), window, cx, |s| {
13362            s.move_heads_with(|map, head, _| {
13363                (
13364                    movement::indented_line_beginning(
13365                        map,
13366                        head,
13367                        action.stop_at_soft_wraps,
13368                        action.stop_at_indent,
13369                    ),
13370                    SelectionGoal::None,
13371                )
13372            });
13373        });
13374    }
13375
13376    pub fn delete_to_beginning_of_line(
13377        &mut self,
13378        action: &DeleteToBeginningOfLine,
13379        window: &mut Window,
13380        cx: &mut Context<Self>,
13381    ) {
13382        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13383        self.transact(window, cx, |this, window, cx| {
13384            this.change_selections(Default::default(), window, cx, |s| {
13385                s.move_with(|_, selection| {
13386                    selection.reversed = true;
13387                });
13388            });
13389
13390            this.select_to_beginning_of_line(
13391                &SelectToBeginningOfLine {
13392                    stop_at_soft_wraps: false,
13393                    stop_at_indent: action.stop_at_indent,
13394                },
13395                window,
13396                cx,
13397            );
13398            this.backspace(&Backspace, window, cx);
13399        });
13400    }
13401
13402    pub fn move_to_end_of_line(
13403        &mut self,
13404        action: &MoveToEndOfLine,
13405        window: &mut Window,
13406        cx: &mut Context<Self>,
13407    ) {
13408        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13409        self.change_selections(Default::default(), window, cx, |s| {
13410            s.move_cursors_with(|map, head, _| {
13411                (
13412                    movement::line_end(map, head, action.stop_at_soft_wraps),
13413                    SelectionGoal::None,
13414                )
13415            });
13416        })
13417    }
13418
13419    pub fn select_to_end_of_line(
13420        &mut self,
13421        action: &SelectToEndOfLine,
13422        window: &mut Window,
13423        cx: &mut Context<Self>,
13424    ) {
13425        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13426        self.change_selections(Default::default(), window, cx, |s| {
13427            s.move_heads_with(|map, head, _| {
13428                (
13429                    movement::line_end(map, head, action.stop_at_soft_wraps),
13430                    SelectionGoal::None,
13431                )
13432            });
13433        })
13434    }
13435
13436    pub fn delete_to_end_of_line(
13437        &mut self,
13438        _: &DeleteToEndOfLine,
13439        window: &mut Window,
13440        cx: &mut Context<Self>,
13441    ) {
13442        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13443        self.transact(window, cx, |this, window, cx| {
13444            this.select_to_end_of_line(
13445                &SelectToEndOfLine {
13446                    stop_at_soft_wraps: false,
13447                },
13448                window,
13449                cx,
13450            );
13451            this.delete(&Delete, window, cx);
13452        });
13453    }
13454
13455    pub fn cut_to_end_of_line(
13456        &mut self,
13457        _: &CutToEndOfLine,
13458        window: &mut Window,
13459        cx: &mut Context<Self>,
13460    ) {
13461        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13462        self.transact(window, cx, |this, window, cx| {
13463            this.select_to_end_of_line(
13464                &SelectToEndOfLine {
13465                    stop_at_soft_wraps: false,
13466                },
13467                window,
13468                cx,
13469            );
13470            this.cut(&Cut, window, cx);
13471        });
13472    }
13473
13474    pub fn move_to_start_of_paragraph(
13475        &mut self,
13476        _: &MoveToStartOfParagraph,
13477        window: &mut Window,
13478        cx: &mut Context<Self>,
13479    ) {
13480        if matches!(self.mode, EditorMode::SingleLine) {
13481            cx.propagate();
13482            return;
13483        }
13484        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13485        self.change_selections(Default::default(), window, cx, |s| {
13486            s.move_with(|map, selection| {
13487                selection.collapse_to(
13488                    movement::start_of_paragraph(map, selection.head(), 1),
13489                    SelectionGoal::None,
13490                )
13491            });
13492        })
13493    }
13494
13495    pub fn move_to_end_of_paragraph(
13496        &mut self,
13497        _: &MoveToEndOfParagraph,
13498        window: &mut Window,
13499        cx: &mut Context<Self>,
13500    ) {
13501        if matches!(self.mode, EditorMode::SingleLine) {
13502            cx.propagate();
13503            return;
13504        }
13505        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13506        self.change_selections(Default::default(), window, cx, |s| {
13507            s.move_with(|map, selection| {
13508                selection.collapse_to(
13509                    movement::end_of_paragraph(map, selection.head(), 1),
13510                    SelectionGoal::None,
13511                )
13512            });
13513        })
13514    }
13515
13516    pub fn select_to_start_of_paragraph(
13517        &mut self,
13518        _: &SelectToStartOfParagraph,
13519        window: &mut Window,
13520        cx: &mut Context<Self>,
13521    ) {
13522        if matches!(self.mode, EditorMode::SingleLine) {
13523            cx.propagate();
13524            return;
13525        }
13526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13527        self.change_selections(Default::default(), window, cx, |s| {
13528            s.move_heads_with(|map, head, _| {
13529                (
13530                    movement::start_of_paragraph(map, head, 1),
13531                    SelectionGoal::None,
13532                )
13533            });
13534        })
13535    }
13536
13537    pub fn select_to_end_of_paragraph(
13538        &mut self,
13539        _: &SelectToEndOfParagraph,
13540        window: &mut Window,
13541        cx: &mut Context<Self>,
13542    ) {
13543        if matches!(self.mode, EditorMode::SingleLine) {
13544            cx.propagate();
13545            return;
13546        }
13547        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13548        self.change_selections(Default::default(), window, cx, |s| {
13549            s.move_heads_with(|map, head, _| {
13550                (
13551                    movement::end_of_paragraph(map, head, 1),
13552                    SelectionGoal::None,
13553                )
13554            });
13555        })
13556    }
13557
13558    pub fn move_to_start_of_excerpt(
13559        &mut self,
13560        _: &MoveToStartOfExcerpt,
13561        window: &mut Window,
13562        cx: &mut Context<Self>,
13563    ) {
13564        if matches!(self.mode, EditorMode::SingleLine) {
13565            cx.propagate();
13566            return;
13567        }
13568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13569        self.change_selections(Default::default(), window, cx, |s| {
13570            s.move_with(|map, selection| {
13571                selection.collapse_to(
13572                    movement::start_of_excerpt(
13573                        map,
13574                        selection.head(),
13575                        workspace::searchable::Direction::Prev,
13576                    ),
13577                    SelectionGoal::None,
13578                )
13579            });
13580        })
13581    }
13582
13583    pub fn move_to_start_of_next_excerpt(
13584        &mut self,
13585        _: &MoveToStartOfNextExcerpt,
13586        window: &mut Window,
13587        cx: &mut Context<Self>,
13588    ) {
13589        if matches!(self.mode, EditorMode::SingleLine) {
13590            cx.propagate();
13591            return;
13592        }
13593
13594        self.change_selections(Default::default(), window, cx, |s| {
13595            s.move_with(|map, selection| {
13596                selection.collapse_to(
13597                    movement::start_of_excerpt(
13598                        map,
13599                        selection.head(),
13600                        workspace::searchable::Direction::Next,
13601                    ),
13602                    SelectionGoal::None,
13603                )
13604            });
13605        })
13606    }
13607
13608    pub fn move_to_end_of_excerpt(
13609        &mut self,
13610        _: &MoveToEndOfExcerpt,
13611        window: &mut Window,
13612        cx: &mut Context<Self>,
13613    ) {
13614        if matches!(self.mode, EditorMode::SingleLine) {
13615            cx.propagate();
13616            return;
13617        }
13618        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13619        self.change_selections(Default::default(), window, cx, |s| {
13620            s.move_with(|map, selection| {
13621                selection.collapse_to(
13622                    movement::end_of_excerpt(
13623                        map,
13624                        selection.head(),
13625                        workspace::searchable::Direction::Next,
13626                    ),
13627                    SelectionGoal::None,
13628                )
13629            });
13630        })
13631    }
13632
13633    pub fn move_to_end_of_previous_excerpt(
13634        &mut self,
13635        _: &MoveToEndOfPreviousExcerpt,
13636        window: &mut Window,
13637        cx: &mut Context<Self>,
13638    ) {
13639        if matches!(self.mode, EditorMode::SingleLine) {
13640            cx.propagate();
13641            return;
13642        }
13643        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13644        self.change_selections(Default::default(), window, cx, |s| {
13645            s.move_with(|map, selection| {
13646                selection.collapse_to(
13647                    movement::end_of_excerpt(
13648                        map,
13649                        selection.head(),
13650                        workspace::searchable::Direction::Prev,
13651                    ),
13652                    SelectionGoal::None,
13653                )
13654            });
13655        })
13656    }
13657
13658    pub fn select_to_start_of_excerpt(
13659        &mut self,
13660        _: &SelectToStartOfExcerpt,
13661        window: &mut Window,
13662        cx: &mut Context<Self>,
13663    ) {
13664        if matches!(self.mode, EditorMode::SingleLine) {
13665            cx.propagate();
13666            return;
13667        }
13668        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13669        self.change_selections(Default::default(), window, cx, |s| {
13670            s.move_heads_with(|map, head, _| {
13671                (
13672                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13673                    SelectionGoal::None,
13674                )
13675            });
13676        })
13677    }
13678
13679    pub fn select_to_start_of_next_excerpt(
13680        &mut self,
13681        _: &SelectToStartOfNextExcerpt,
13682        window: &mut Window,
13683        cx: &mut Context<Self>,
13684    ) {
13685        if matches!(self.mode, EditorMode::SingleLine) {
13686            cx.propagate();
13687            return;
13688        }
13689        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13690        self.change_selections(Default::default(), window, cx, |s| {
13691            s.move_heads_with(|map, head, _| {
13692                (
13693                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13694                    SelectionGoal::None,
13695                )
13696            });
13697        })
13698    }
13699
13700    pub fn select_to_end_of_excerpt(
13701        &mut self,
13702        _: &SelectToEndOfExcerpt,
13703        window: &mut Window,
13704        cx: &mut Context<Self>,
13705    ) {
13706        if matches!(self.mode, EditorMode::SingleLine) {
13707            cx.propagate();
13708            return;
13709        }
13710        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13711        self.change_selections(Default::default(), window, cx, |s| {
13712            s.move_heads_with(|map, head, _| {
13713                (
13714                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13715                    SelectionGoal::None,
13716                )
13717            });
13718        })
13719    }
13720
13721    pub fn select_to_end_of_previous_excerpt(
13722        &mut self,
13723        _: &SelectToEndOfPreviousExcerpt,
13724        window: &mut Window,
13725        cx: &mut Context<Self>,
13726    ) {
13727        if matches!(self.mode, EditorMode::SingleLine) {
13728            cx.propagate();
13729            return;
13730        }
13731        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13732        self.change_selections(Default::default(), window, cx, |s| {
13733            s.move_heads_with(|map, head, _| {
13734                (
13735                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13736                    SelectionGoal::None,
13737                )
13738            });
13739        })
13740    }
13741
13742    pub fn move_to_beginning(
13743        &mut self,
13744        _: &MoveToBeginning,
13745        window: &mut Window,
13746        cx: &mut Context<Self>,
13747    ) {
13748        if matches!(self.mode, EditorMode::SingleLine) {
13749            cx.propagate();
13750            return;
13751        }
13752        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13753        self.change_selections(Default::default(), window, cx, |s| {
13754            s.select_ranges(vec![0..0]);
13755        });
13756    }
13757
13758    pub fn select_to_beginning(
13759        &mut self,
13760        _: &SelectToBeginning,
13761        window: &mut Window,
13762        cx: &mut Context<Self>,
13763    ) {
13764        let mut selection = self.selections.last::<Point>(cx);
13765        selection.set_head(Point::zero(), SelectionGoal::None);
13766        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13767        self.change_selections(Default::default(), window, cx, |s| {
13768            s.select(vec![selection]);
13769        });
13770    }
13771
13772    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13773        if matches!(self.mode, EditorMode::SingleLine) {
13774            cx.propagate();
13775            return;
13776        }
13777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13778        let cursor = self.buffer.read(cx).read(cx).len();
13779        self.change_selections(Default::default(), window, cx, |s| {
13780            s.select_ranges(vec![cursor..cursor])
13781        });
13782    }
13783
13784    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13785        self.nav_history = nav_history;
13786    }
13787
13788    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13789        self.nav_history.as_ref()
13790    }
13791
13792    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13793        self.push_to_nav_history(
13794            self.selections.newest_anchor().head(),
13795            None,
13796            false,
13797            true,
13798            cx,
13799        );
13800    }
13801
13802    fn push_to_nav_history(
13803        &mut self,
13804        cursor_anchor: Anchor,
13805        new_position: Option<Point>,
13806        is_deactivate: bool,
13807        always: bool,
13808        cx: &mut Context<Self>,
13809    ) {
13810        if let Some(nav_history) = self.nav_history.as_mut() {
13811            let buffer = self.buffer.read(cx).read(cx);
13812            let cursor_position = cursor_anchor.to_point(&buffer);
13813            let scroll_state = self.scroll_manager.anchor();
13814            let scroll_top_row = scroll_state.top_row(&buffer);
13815            drop(buffer);
13816
13817            if let Some(new_position) = new_position {
13818                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13819                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13820                    return;
13821                }
13822            }
13823
13824            nav_history.push(
13825                Some(NavigationData {
13826                    cursor_anchor,
13827                    cursor_position,
13828                    scroll_anchor: scroll_state,
13829                    scroll_top_row,
13830                }),
13831                cx,
13832            );
13833            cx.emit(EditorEvent::PushedToNavHistory {
13834                anchor: cursor_anchor,
13835                is_deactivate,
13836            })
13837        }
13838    }
13839
13840    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13841        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13842        let buffer = self.buffer.read(cx).snapshot(cx);
13843        let mut selection = self.selections.first::<usize>(cx);
13844        selection.set_head(buffer.len(), SelectionGoal::None);
13845        self.change_selections(Default::default(), window, cx, |s| {
13846            s.select(vec![selection]);
13847        });
13848    }
13849
13850    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13851        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13852        let end = self.buffer.read(cx).read(cx).len();
13853        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13854            s.select_ranges(vec![0..end]);
13855        });
13856    }
13857
13858    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13859        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13860        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13861        let mut selections = self.selections.all::<Point>(cx);
13862        let max_point = display_map.buffer_snapshot.max_point();
13863        for selection in &mut selections {
13864            let rows = selection.spanned_rows(true, &display_map);
13865            selection.start = Point::new(rows.start.0, 0);
13866            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13867            selection.reversed = false;
13868        }
13869        self.change_selections(Default::default(), window, cx, |s| {
13870            s.select(selections);
13871        });
13872    }
13873
13874    pub fn split_selection_into_lines(
13875        &mut self,
13876        action: &SplitSelectionIntoLines,
13877        window: &mut Window,
13878        cx: &mut Context<Self>,
13879    ) {
13880        let selections = self
13881            .selections
13882            .all::<Point>(cx)
13883            .into_iter()
13884            .map(|selection| selection.start..selection.end)
13885            .collect::<Vec<_>>();
13886        self.unfold_ranges(&selections, true, true, cx);
13887
13888        let mut new_selection_ranges = Vec::new();
13889        {
13890            let buffer = self.buffer.read(cx).read(cx);
13891            for selection in selections {
13892                for row in selection.start.row..selection.end.row {
13893                    let line_start = Point::new(row, 0);
13894                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13895
13896                    if action.keep_selections {
13897                        // Keep the selection range for each line
13898                        let selection_start = if row == selection.start.row {
13899                            selection.start
13900                        } else {
13901                            line_start
13902                        };
13903                        new_selection_ranges.push(selection_start..line_end);
13904                    } else {
13905                        // Collapse to cursor at end of line
13906                        new_selection_ranges.push(line_end..line_end);
13907                    }
13908                }
13909
13910                let is_multiline_selection = selection.start.row != selection.end.row;
13911                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13912                // so this action feels more ergonomic when paired with other selection operations
13913                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13914                if !should_skip_last {
13915                    if action.keep_selections {
13916                        if is_multiline_selection {
13917                            let line_start = Point::new(selection.end.row, 0);
13918                            new_selection_ranges.push(line_start..selection.end);
13919                        } else {
13920                            new_selection_ranges.push(selection.start..selection.end);
13921                        }
13922                    } else {
13923                        new_selection_ranges.push(selection.end..selection.end);
13924                    }
13925                }
13926            }
13927        }
13928        self.change_selections(Default::default(), window, cx, |s| {
13929            s.select_ranges(new_selection_ranges);
13930        });
13931    }
13932
13933    pub fn add_selection_above(
13934        &mut self,
13935        _: &AddSelectionAbove,
13936        window: &mut Window,
13937        cx: &mut Context<Self>,
13938    ) {
13939        self.add_selection(true, window, cx);
13940    }
13941
13942    pub fn add_selection_below(
13943        &mut self,
13944        _: &AddSelectionBelow,
13945        window: &mut Window,
13946        cx: &mut Context<Self>,
13947    ) {
13948        self.add_selection(false, window, cx);
13949    }
13950
13951    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13952        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13953
13954        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13955        let all_selections = self.selections.all::<Point>(cx);
13956        let text_layout_details = self.text_layout_details(window);
13957
13958        let (mut columnar_selections, new_selections_to_columnarize) = {
13959            if let Some(state) = self.add_selections_state.as_ref() {
13960                let columnar_selection_ids: HashSet<_> = state
13961                    .groups
13962                    .iter()
13963                    .flat_map(|group| group.stack.iter())
13964                    .copied()
13965                    .collect();
13966
13967                all_selections
13968                    .into_iter()
13969                    .partition(|s| columnar_selection_ids.contains(&s.id))
13970            } else {
13971                (Vec::new(), all_selections)
13972            }
13973        };
13974
13975        let mut state = self
13976            .add_selections_state
13977            .take()
13978            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13979
13980        for selection in new_selections_to_columnarize {
13981            let range = selection.display_range(&display_map).sorted();
13982            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13983            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13984            let positions = start_x.min(end_x)..start_x.max(end_x);
13985            let mut stack = Vec::new();
13986            for row in range.start.row().0..=range.end.row().0 {
13987                if let Some(selection) = self.selections.build_columnar_selection(
13988                    &display_map,
13989                    DisplayRow(row),
13990                    &positions,
13991                    selection.reversed,
13992                    &text_layout_details,
13993                ) {
13994                    stack.push(selection.id);
13995                    columnar_selections.push(selection);
13996                }
13997            }
13998            if !stack.is_empty() {
13999                if above {
14000                    stack.reverse();
14001                }
14002                state.groups.push(AddSelectionsGroup { above, stack });
14003            }
14004        }
14005
14006        let mut final_selections = Vec::new();
14007        let end_row = if above {
14008            DisplayRow(0)
14009        } else {
14010            display_map.max_point().row()
14011        };
14012
14013        let mut last_added_item_per_group = HashMap::default();
14014        for group in state.groups.iter_mut() {
14015            if let Some(last_id) = group.stack.last() {
14016                last_added_item_per_group.insert(*last_id, group);
14017            }
14018        }
14019
14020        for selection in columnar_selections {
14021            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14022                if above == group.above {
14023                    let range = selection.display_range(&display_map).sorted();
14024                    debug_assert_eq!(range.start.row(), range.end.row());
14025                    let mut row = range.start.row();
14026                    let positions =
14027                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14028                            px(start)..px(end)
14029                        } else {
14030                            let start_x =
14031                                display_map.x_for_display_point(range.start, &text_layout_details);
14032                            let end_x =
14033                                display_map.x_for_display_point(range.end, &text_layout_details);
14034                            start_x.min(end_x)..start_x.max(end_x)
14035                        };
14036
14037                    let mut maybe_new_selection = None;
14038                    while row != end_row {
14039                        if above {
14040                            row.0 -= 1;
14041                        } else {
14042                            row.0 += 1;
14043                        }
14044                        if let Some(new_selection) = self.selections.build_columnar_selection(
14045                            &display_map,
14046                            row,
14047                            &positions,
14048                            selection.reversed,
14049                            &text_layout_details,
14050                        ) {
14051                            maybe_new_selection = Some(new_selection);
14052                            break;
14053                        }
14054                    }
14055
14056                    if let Some(new_selection) = maybe_new_selection {
14057                        group.stack.push(new_selection.id);
14058                        if above {
14059                            final_selections.push(new_selection);
14060                            final_selections.push(selection);
14061                        } else {
14062                            final_selections.push(selection);
14063                            final_selections.push(new_selection);
14064                        }
14065                    } else {
14066                        final_selections.push(selection);
14067                    }
14068                } else {
14069                    group.stack.pop();
14070                }
14071            } else {
14072                final_selections.push(selection);
14073            }
14074        }
14075
14076        self.change_selections(Default::default(), window, cx, |s| {
14077            s.select(final_selections);
14078        });
14079
14080        let final_selection_ids: HashSet<_> = self
14081            .selections
14082            .all::<Point>(cx)
14083            .iter()
14084            .map(|s| s.id)
14085            .collect();
14086        state.groups.retain_mut(|group| {
14087            // selections might get merged above so we remove invalid items from stacks
14088            group.stack.retain(|id| final_selection_ids.contains(id));
14089
14090            // single selection in stack can be treated as initial state
14091            group.stack.len() > 1
14092        });
14093
14094        if !state.groups.is_empty() {
14095            self.add_selections_state = Some(state);
14096        }
14097    }
14098
14099    fn select_match_ranges(
14100        &mut self,
14101        range: Range<usize>,
14102        reversed: bool,
14103        replace_newest: bool,
14104        auto_scroll: Option<Autoscroll>,
14105        window: &mut Window,
14106        cx: &mut Context<Editor>,
14107    ) {
14108        self.unfold_ranges(
14109            std::slice::from_ref(&range),
14110            false,
14111            auto_scroll.is_some(),
14112            cx,
14113        );
14114        let effects = if let Some(scroll) = auto_scroll {
14115            SelectionEffects::scroll(scroll)
14116        } else {
14117            SelectionEffects::no_scroll()
14118        };
14119        self.change_selections(effects, window, cx, |s| {
14120            if replace_newest {
14121                s.delete(s.newest_anchor().id);
14122            }
14123            if reversed {
14124                s.insert_range(range.end..range.start);
14125            } else {
14126                s.insert_range(range);
14127            }
14128        });
14129    }
14130
14131    pub fn select_next_match_internal(
14132        &mut self,
14133        display_map: &DisplaySnapshot,
14134        replace_newest: bool,
14135        autoscroll: Option<Autoscroll>,
14136        window: &mut Window,
14137        cx: &mut Context<Self>,
14138    ) -> Result<()> {
14139        let buffer = &display_map.buffer_snapshot;
14140        let mut selections = self.selections.all::<usize>(cx);
14141        if let Some(mut select_next_state) = self.select_next_state.take() {
14142            let query = &select_next_state.query;
14143            if !select_next_state.done {
14144                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14145                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14146                let mut next_selected_range = None;
14147
14148                let bytes_after_last_selection =
14149                    buffer.bytes_in_range(last_selection.end..buffer.len());
14150                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14151                let query_matches = query
14152                    .stream_find_iter(bytes_after_last_selection)
14153                    .map(|result| (last_selection.end, result))
14154                    .chain(
14155                        query
14156                            .stream_find_iter(bytes_before_first_selection)
14157                            .map(|result| (0, result)),
14158                    );
14159
14160                for (start_offset, query_match) in query_matches {
14161                    let query_match = query_match.unwrap(); // can only fail due to I/O
14162                    let offset_range =
14163                        start_offset + query_match.start()..start_offset + query_match.end();
14164
14165                    if !select_next_state.wordwise
14166                        || (!buffer.is_inside_word(offset_range.start, false)
14167                            && !buffer.is_inside_word(offset_range.end, false))
14168                    {
14169                        // TODO: This is n^2, because we might check all the selections
14170                        if !selections
14171                            .iter()
14172                            .any(|selection| selection.range().overlaps(&offset_range))
14173                        {
14174                            next_selected_range = Some(offset_range);
14175                            break;
14176                        }
14177                    }
14178                }
14179
14180                if let Some(next_selected_range) = next_selected_range {
14181                    self.select_match_ranges(
14182                        next_selected_range,
14183                        last_selection.reversed,
14184                        replace_newest,
14185                        autoscroll,
14186                        window,
14187                        cx,
14188                    );
14189                } else {
14190                    select_next_state.done = true;
14191                }
14192            }
14193
14194            self.select_next_state = Some(select_next_state);
14195        } else {
14196            let mut only_carets = true;
14197            let mut same_text_selected = true;
14198            let mut selected_text = None;
14199
14200            let mut selections_iter = selections.iter().peekable();
14201            while let Some(selection) = selections_iter.next() {
14202                if selection.start != selection.end {
14203                    only_carets = false;
14204                }
14205
14206                if same_text_selected {
14207                    if selected_text.is_none() {
14208                        selected_text =
14209                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14210                    }
14211
14212                    if let Some(next_selection) = selections_iter.peek() {
14213                        if next_selection.range().len() == selection.range().len() {
14214                            let next_selected_text = buffer
14215                                .text_for_range(next_selection.range())
14216                                .collect::<String>();
14217                            if Some(next_selected_text) != selected_text {
14218                                same_text_selected = false;
14219                                selected_text = None;
14220                            }
14221                        } else {
14222                            same_text_selected = false;
14223                            selected_text = None;
14224                        }
14225                    }
14226                }
14227            }
14228
14229            if only_carets {
14230                for selection in &mut selections {
14231                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14232                    selection.start = word_range.start;
14233                    selection.end = word_range.end;
14234                    selection.goal = SelectionGoal::None;
14235                    selection.reversed = false;
14236                    self.select_match_ranges(
14237                        selection.start..selection.end,
14238                        selection.reversed,
14239                        replace_newest,
14240                        autoscroll,
14241                        window,
14242                        cx,
14243                    );
14244                }
14245
14246                if selections.len() == 1 {
14247                    let selection = selections
14248                        .last()
14249                        .expect("ensured that there's only one selection");
14250                    let query = buffer
14251                        .text_for_range(selection.start..selection.end)
14252                        .collect::<String>();
14253                    let is_empty = query.is_empty();
14254                    let select_state = SelectNextState {
14255                        query: AhoCorasick::new(&[query])?,
14256                        wordwise: true,
14257                        done: is_empty,
14258                    };
14259                    self.select_next_state = Some(select_state);
14260                } else {
14261                    self.select_next_state = None;
14262                }
14263            } else if let Some(selected_text) = selected_text {
14264                self.select_next_state = Some(SelectNextState {
14265                    query: AhoCorasick::new(&[selected_text])?,
14266                    wordwise: false,
14267                    done: false,
14268                });
14269                self.select_next_match_internal(
14270                    display_map,
14271                    replace_newest,
14272                    autoscroll,
14273                    window,
14274                    cx,
14275                )?;
14276            }
14277        }
14278        Ok(())
14279    }
14280
14281    pub fn select_all_matches(
14282        &mut self,
14283        _action: &SelectAllMatches,
14284        window: &mut Window,
14285        cx: &mut Context<Self>,
14286    ) -> Result<()> {
14287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14288
14289        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14290
14291        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14292        let Some(select_next_state) = self.select_next_state.as_mut() else {
14293            return Ok(());
14294        };
14295        if select_next_state.done {
14296            return Ok(());
14297        }
14298
14299        let mut new_selections = Vec::new();
14300
14301        let reversed = self.selections.oldest::<usize>(cx).reversed;
14302        let buffer = &display_map.buffer_snapshot;
14303        let query_matches = select_next_state
14304            .query
14305            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14306
14307        for query_match in query_matches.into_iter() {
14308            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14309            let offset_range = if reversed {
14310                query_match.end()..query_match.start()
14311            } else {
14312                query_match.start()..query_match.end()
14313            };
14314
14315            if !select_next_state.wordwise
14316                || (!buffer.is_inside_word(offset_range.start, false)
14317                    && !buffer.is_inside_word(offset_range.end, false))
14318            {
14319                new_selections.push(offset_range.start..offset_range.end);
14320            }
14321        }
14322
14323        select_next_state.done = true;
14324
14325        if new_selections.is_empty() {
14326            log::error!("bug: new_selections is empty in select_all_matches");
14327            return Ok(());
14328        }
14329
14330        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14331        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14332            selections.select_ranges(new_selections)
14333        });
14334
14335        Ok(())
14336    }
14337
14338    pub fn select_next(
14339        &mut self,
14340        action: &SelectNext,
14341        window: &mut Window,
14342        cx: &mut Context<Self>,
14343    ) -> Result<()> {
14344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14345        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14346        self.select_next_match_internal(
14347            &display_map,
14348            action.replace_newest,
14349            Some(Autoscroll::newest()),
14350            window,
14351            cx,
14352        )?;
14353        Ok(())
14354    }
14355
14356    pub fn select_previous(
14357        &mut self,
14358        action: &SelectPrevious,
14359        window: &mut Window,
14360        cx: &mut Context<Self>,
14361    ) -> Result<()> {
14362        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14363        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14364        let buffer = &display_map.buffer_snapshot;
14365        let mut selections = self.selections.all::<usize>(cx);
14366        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14367            let query = &select_prev_state.query;
14368            if !select_prev_state.done {
14369                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14370                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14371                let mut next_selected_range = None;
14372                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14373                let bytes_before_last_selection =
14374                    buffer.reversed_bytes_in_range(0..last_selection.start);
14375                let bytes_after_first_selection =
14376                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14377                let query_matches = query
14378                    .stream_find_iter(bytes_before_last_selection)
14379                    .map(|result| (last_selection.start, result))
14380                    .chain(
14381                        query
14382                            .stream_find_iter(bytes_after_first_selection)
14383                            .map(|result| (buffer.len(), result)),
14384                    );
14385                for (end_offset, query_match) in query_matches {
14386                    let query_match = query_match.unwrap(); // can only fail due to I/O
14387                    let offset_range =
14388                        end_offset - query_match.end()..end_offset - query_match.start();
14389
14390                    if !select_prev_state.wordwise
14391                        || (!buffer.is_inside_word(offset_range.start, false)
14392                            && !buffer.is_inside_word(offset_range.end, false))
14393                    {
14394                        next_selected_range = Some(offset_range);
14395                        break;
14396                    }
14397                }
14398
14399                if let Some(next_selected_range) = next_selected_range {
14400                    self.select_match_ranges(
14401                        next_selected_range,
14402                        last_selection.reversed,
14403                        action.replace_newest,
14404                        Some(Autoscroll::newest()),
14405                        window,
14406                        cx,
14407                    );
14408                } else {
14409                    select_prev_state.done = true;
14410                }
14411            }
14412
14413            self.select_prev_state = Some(select_prev_state);
14414        } else {
14415            let mut only_carets = true;
14416            let mut same_text_selected = true;
14417            let mut selected_text = None;
14418
14419            let mut selections_iter = selections.iter().peekable();
14420            while let Some(selection) = selections_iter.next() {
14421                if selection.start != selection.end {
14422                    only_carets = false;
14423                }
14424
14425                if same_text_selected {
14426                    if selected_text.is_none() {
14427                        selected_text =
14428                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14429                    }
14430
14431                    if let Some(next_selection) = selections_iter.peek() {
14432                        if next_selection.range().len() == selection.range().len() {
14433                            let next_selected_text = buffer
14434                                .text_for_range(next_selection.range())
14435                                .collect::<String>();
14436                            if Some(next_selected_text) != selected_text {
14437                                same_text_selected = false;
14438                                selected_text = None;
14439                            }
14440                        } else {
14441                            same_text_selected = false;
14442                            selected_text = None;
14443                        }
14444                    }
14445                }
14446            }
14447
14448            if only_carets {
14449                for selection in &mut selections {
14450                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14451                    selection.start = word_range.start;
14452                    selection.end = word_range.end;
14453                    selection.goal = SelectionGoal::None;
14454                    selection.reversed = false;
14455                    self.select_match_ranges(
14456                        selection.start..selection.end,
14457                        selection.reversed,
14458                        action.replace_newest,
14459                        Some(Autoscroll::newest()),
14460                        window,
14461                        cx,
14462                    );
14463                }
14464                if selections.len() == 1 {
14465                    let selection = selections
14466                        .last()
14467                        .expect("ensured that there's only one selection");
14468                    let query = buffer
14469                        .text_for_range(selection.start..selection.end)
14470                        .collect::<String>();
14471                    let is_empty = query.is_empty();
14472                    let select_state = SelectNextState {
14473                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14474                        wordwise: true,
14475                        done: is_empty,
14476                    };
14477                    self.select_prev_state = Some(select_state);
14478                } else {
14479                    self.select_prev_state = None;
14480                }
14481            } else if let Some(selected_text) = selected_text {
14482                self.select_prev_state = Some(SelectNextState {
14483                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14484                    wordwise: false,
14485                    done: false,
14486                });
14487                self.select_previous(action, window, cx)?;
14488            }
14489        }
14490        Ok(())
14491    }
14492
14493    pub fn find_next_match(
14494        &mut self,
14495        _: &FindNextMatch,
14496        window: &mut Window,
14497        cx: &mut Context<Self>,
14498    ) -> Result<()> {
14499        let selections = self.selections.disjoint_anchors();
14500        match selections.first() {
14501            Some(first) if selections.len() >= 2 => {
14502                self.change_selections(Default::default(), window, cx, |s| {
14503                    s.select_ranges([first.range()]);
14504                });
14505            }
14506            _ => self.select_next(
14507                &SelectNext {
14508                    replace_newest: true,
14509                },
14510                window,
14511                cx,
14512            )?,
14513        }
14514        Ok(())
14515    }
14516
14517    pub fn find_previous_match(
14518        &mut self,
14519        _: &FindPreviousMatch,
14520        window: &mut Window,
14521        cx: &mut Context<Self>,
14522    ) -> Result<()> {
14523        let selections = self.selections.disjoint_anchors();
14524        match selections.last() {
14525            Some(last) if selections.len() >= 2 => {
14526                self.change_selections(Default::default(), window, cx, |s| {
14527                    s.select_ranges([last.range()]);
14528                });
14529            }
14530            _ => self.select_previous(
14531                &SelectPrevious {
14532                    replace_newest: true,
14533                },
14534                window,
14535                cx,
14536            )?,
14537        }
14538        Ok(())
14539    }
14540
14541    pub fn toggle_comments(
14542        &mut self,
14543        action: &ToggleComments,
14544        window: &mut Window,
14545        cx: &mut Context<Self>,
14546    ) {
14547        if self.read_only(cx) {
14548            return;
14549        }
14550        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14551        let text_layout_details = &self.text_layout_details(window);
14552        self.transact(window, cx, |this, window, cx| {
14553            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14554            let mut edits = Vec::new();
14555            let mut selection_edit_ranges = Vec::new();
14556            let mut last_toggled_row = None;
14557            let snapshot = this.buffer.read(cx).read(cx);
14558            let empty_str: Arc<str> = Arc::default();
14559            let mut suffixes_inserted = Vec::new();
14560            let ignore_indent = action.ignore_indent;
14561
14562            fn comment_prefix_range(
14563                snapshot: &MultiBufferSnapshot,
14564                row: MultiBufferRow,
14565                comment_prefix: &str,
14566                comment_prefix_whitespace: &str,
14567                ignore_indent: bool,
14568            ) -> Range<Point> {
14569                let indent_size = if ignore_indent {
14570                    0
14571                } else {
14572                    snapshot.indent_size_for_line(row).len
14573                };
14574
14575                let start = Point::new(row.0, indent_size);
14576
14577                let mut line_bytes = snapshot
14578                    .bytes_in_range(start..snapshot.max_point())
14579                    .flatten()
14580                    .copied();
14581
14582                // If this line currently begins with the line comment prefix, then record
14583                // the range containing the prefix.
14584                if line_bytes
14585                    .by_ref()
14586                    .take(comment_prefix.len())
14587                    .eq(comment_prefix.bytes())
14588                {
14589                    // Include any whitespace that matches the comment prefix.
14590                    let matching_whitespace_len = line_bytes
14591                        .zip(comment_prefix_whitespace.bytes())
14592                        .take_while(|(a, b)| a == b)
14593                        .count() as u32;
14594                    let end = Point::new(
14595                        start.row,
14596                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14597                    );
14598                    start..end
14599                } else {
14600                    start..start
14601                }
14602            }
14603
14604            fn comment_suffix_range(
14605                snapshot: &MultiBufferSnapshot,
14606                row: MultiBufferRow,
14607                comment_suffix: &str,
14608                comment_suffix_has_leading_space: bool,
14609            ) -> Range<Point> {
14610                let end = Point::new(row.0, snapshot.line_len(row));
14611                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14612
14613                let mut line_end_bytes = snapshot
14614                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14615                    .flatten()
14616                    .copied();
14617
14618                let leading_space_len = if suffix_start_column > 0
14619                    && line_end_bytes.next() == Some(b' ')
14620                    && comment_suffix_has_leading_space
14621                {
14622                    1
14623                } else {
14624                    0
14625                };
14626
14627                // If this line currently begins with the line comment prefix, then record
14628                // the range containing the prefix.
14629                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14630                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14631                    start..end
14632                } else {
14633                    end..end
14634                }
14635            }
14636
14637            // TODO: Handle selections that cross excerpts
14638            for selection in &mut selections {
14639                let start_column = snapshot
14640                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14641                    .len;
14642                let language = if let Some(language) =
14643                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14644                {
14645                    language
14646                } else {
14647                    continue;
14648                };
14649
14650                selection_edit_ranges.clear();
14651
14652                // If multiple selections contain a given row, avoid processing that
14653                // row more than once.
14654                let mut start_row = MultiBufferRow(selection.start.row);
14655                if last_toggled_row == Some(start_row) {
14656                    start_row = start_row.next_row();
14657                }
14658                let end_row =
14659                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14660                        MultiBufferRow(selection.end.row - 1)
14661                    } else {
14662                        MultiBufferRow(selection.end.row)
14663                    };
14664                last_toggled_row = Some(end_row);
14665
14666                if start_row > end_row {
14667                    continue;
14668                }
14669
14670                // If the language has line comments, toggle those.
14671                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14672
14673                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14674                if ignore_indent {
14675                    full_comment_prefixes = full_comment_prefixes
14676                        .into_iter()
14677                        .map(|s| Arc::from(s.trim_end()))
14678                        .collect();
14679                }
14680
14681                if !full_comment_prefixes.is_empty() {
14682                    let first_prefix = full_comment_prefixes
14683                        .first()
14684                        .expect("prefixes is non-empty");
14685                    let prefix_trimmed_lengths = full_comment_prefixes
14686                        .iter()
14687                        .map(|p| p.trim_end_matches(' ').len())
14688                        .collect::<SmallVec<[usize; 4]>>();
14689
14690                    let mut all_selection_lines_are_comments = true;
14691
14692                    for row in start_row.0..=end_row.0 {
14693                        let row = MultiBufferRow(row);
14694                        if start_row < end_row && snapshot.is_line_blank(row) {
14695                            continue;
14696                        }
14697
14698                        let prefix_range = full_comment_prefixes
14699                            .iter()
14700                            .zip(prefix_trimmed_lengths.iter().copied())
14701                            .map(|(prefix, trimmed_prefix_len)| {
14702                                comment_prefix_range(
14703                                    snapshot.deref(),
14704                                    row,
14705                                    &prefix[..trimmed_prefix_len],
14706                                    &prefix[trimmed_prefix_len..],
14707                                    ignore_indent,
14708                                )
14709                            })
14710                            .max_by_key(|range| range.end.column - range.start.column)
14711                            .expect("prefixes is non-empty");
14712
14713                        if prefix_range.is_empty() {
14714                            all_selection_lines_are_comments = false;
14715                        }
14716
14717                        selection_edit_ranges.push(prefix_range);
14718                    }
14719
14720                    if all_selection_lines_are_comments {
14721                        edits.extend(
14722                            selection_edit_ranges
14723                                .iter()
14724                                .cloned()
14725                                .map(|range| (range, empty_str.clone())),
14726                        );
14727                    } else {
14728                        let min_column = selection_edit_ranges
14729                            .iter()
14730                            .map(|range| range.start.column)
14731                            .min()
14732                            .unwrap_or(0);
14733                        edits.extend(selection_edit_ranges.iter().map(|range| {
14734                            let position = Point::new(range.start.row, min_column);
14735                            (position..position, first_prefix.clone())
14736                        }));
14737                    }
14738                } else if let Some(BlockCommentConfig {
14739                    start: full_comment_prefix,
14740                    end: comment_suffix,
14741                    ..
14742                }) = language.block_comment()
14743                {
14744                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14745                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14746                    let prefix_range = comment_prefix_range(
14747                        snapshot.deref(),
14748                        start_row,
14749                        comment_prefix,
14750                        comment_prefix_whitespace,
14751                        ignore_indent,
14752                    );
14753                    let suffix_range = comment_suffix_range(
14754                        snapshot.deref(),
14755                        end_row,
14756                        comment_suffix.trim_start_matches(' '),
14757                        comment_suffix.starts_with(' '),
14758                    );
14759
14760                    if prefix_range.is_empty() || suffix_range.is_empty() {
14761                        edits.push((
14762                            prefix_range.start..prefix_range.start,
14763                            full_comment_prefix.clone(),
14764                        ));
14765                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14766                        suffixes_inserted.push((end_row, comment_suffix.len()));
14767                    } else {
14768                        edits.push((prefix_range, empty_str.clone()));
14769                        edits.push((suffix_range, empty_str.clone()));
14770                    }
14771                } else {
14772                    continue;
14773                }
14774            }
14775
14776            drop(snapshot);
14777            this.buffer.update(cx, |buffer, cx| {
14778                buffer.edit(edits, None, cx);
14779            });
14780
14781            // Adjust selections so that they end before any comment suffixes that
14782            // were inserted.
14783            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14784            let mut selections = this.selections.all::<Point>(cx);
14785            let snapshot = this.buffer.read(cx).read(cx);
14786            for selection in &mut selections {
14787                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14788                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14789                        Ordering::Less => {
14790                            suffixes_inserted.next();
14791                            continue;
14792                        }
14793                        Ordering::Greater => break,
14794                        Ordering::Equal => {
14795                            if selection.end.column == snapshot.line_len(row) {
14796                                if selection.is_empty() {
14797                                    selection.start.column -= suffix_len as u32;
14798                                }
14799                                selection.end.column -= suffix_len as u32;
14800                            }
14801                            break;
14802                        }
14803                    }
14804                }
14805            }
14806
14807            drop(snapshot);
14808            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14809
14810            let selections = this.selections.all::<Point>(cx);
14811            let selections_on_single_row = selections.windows(2).all(|selections| {
14812                selections[0].start.row == selections[1].start.row
14813                    && selections[0].end.row == selections[1].end.row
14814                    && selections[0].start.row == selections[0].end.row
14815            });
14816            let selections_selecting = selections
14817                .iter()
14818                .any(|selection| selection.start != selection.end);
14819            let advance_downwards = action.advance_downwards
14820                && selections_on_single_row
14821                && !selections_selecting
14822                && !matches!(this.mode, EditorMode::SingleLine);
14823
14824            if advance_downwards {
14825                let snapshot = this.buffer.read(cx).snapshot(cx);
14826
14827                this.change_selections(Default::default(), window, cx, |s| {
14828                    s.move_cursors_with(|display_snapshot, display_point, _| {
14829                        let mut point = display_point.to_point(display_snapshot);
14830                        point.row += 1;
14831                        point = snapshot.clip_point(point, Bias::Left);
14832                        let display_point = point.to_display_point(display_snapshot);
14833                        let goal = SelectionGoal::HorizontalPosition(
14834                            display_snapshot
14835                                .x_for_display_point(display_point, text_layout_details)
14836                                .into(),
14837                        );
14838                        (display_point, goal)
14839                    })
14840                });
14841            }
14842        });
14843    }
14844
14845    pub fn select_enclosing_symbol(
14846        &mut self,
14847        _: &SelectEnclosingSymbol,
14848        window: &mut Window,
14849        cx: &mut Context<Self>,
14850    ) {
14851        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14852
14853        let buffer = self.buffer.read(cx).snapshot(cx);
14854        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14855
14856        fn update_selection(
14857            selection: &Selection<usize>,
14858            buffer_snap: &MultiBufferSnapshot,
14859        ) -> Option<Selection<usize>> {
14860            let cursor = selection.head();
14861            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14862            for symbol in symbols.iter().rev() {
14863                let start = symbol.range.start.to_offset(buffer_snap);
14864                let end = symbol.range.end.to_offset(buffer_snap);
14865                let new_range = start..end;
14866                if start < selection.start || end > selection.end {
14867                    return Some(Selection {
14868                        id: selection.id,
14869                        start: new_range.start,
14870                        end: new_range.end,
14871                        goal: SelectionGoal::None,
14872                        reversed: selection.reversed,
14873                    });
14874                }
14875            }
14876            None
14877        }
14878
14879        let mut selected_larger_symbol = false;
14880        let new_selections = old_selections
14881            .iter()
14882            .map(|selection| match update_selection(selection, &buffer) {
14883                Some(new_selection) => {
14884                    if new_selection.range() != selection.range() {
14885                        selected_larger_symbol = true;
14886                    }
14887                    new_selection
14888                }
14889                None => selection.clone(),
14890            })
14891            .collect::<Vec<_>>();
14892
14893        if selected_larger_symbol {
14894            self.change_selections(Default::default(), window, cx, |s| {
14895                s.select(new_selections);
14896            });
14897        }
14898    }
14899
14900    pub fn select_larger_syntax_node(
14901        &mut self,
14902        _: &SelectLargerSyntaxNode,
14903        window: &mut Window,
14904        cx: &mut Context<Self>,
14905    ) {
14906        let Some(visible_row_count) = self.visible_row_count() else {
14907            return;
14908        };
14909        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14910        if old_selections.is_empty() {
14911            return;
14912        }
14913
14914        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14915
14916        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14917        let buffer = self.buffer.read(cx).snapshot(cx);
14918
14919        let mut selected_larger_node = false;
14920        let mut new_selections = old_selections
14921            .iter()
14922            .map(|selection| {
14923                let old_range = selection.start..selection.end;
14924
14925                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14926                    // manually select word at selection
14927                    if ["string_content", "inline"].contains(&node.kind()) {
14928                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14929                        // ignore if word is already selected
14930                        if !word_range.is_empty() && old_range != word_range {
14931                            let (last_word_range, _) =
14932                                buffer.surrounding_word(old_range.end, false);
14933                            // only select word if start and end point belongs to same word
14934                            if word_range == last_word_range {
14935                                selected_larger_node = true;
14936                                return Selection {
14937                                    id: selection.id,
14938                                    start: word_range.start,
14939                                    end: word_range.end,
14940                                    goal: SelectionGoal::None,
14941                                    reversed: selection.reversed,
14942                                };
14943                            }
14944                        }
14945                    }
14946                }
14947
14948                let mut new_range = old_range.clone();
14949                while let Some((_node, containing_range)) =
14950                    buffer.syntax_ancestor(new_range.clone())
14951                {
14952                    new_range = match containing_range {
14953                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14954                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14955                    };
14956                    if !display_map.intersects_fold(new_range.start)
14957                        && !display_map.intersects_fold(new_range.end)
14958                    {
14959                        break;
14960                    }
14961                }
14962
14963                selected_larger_node |= new_range != old_range;
14964                Selection {
14965                    id: selection.id,
14966                    start: new_range.start,
14967                    end: new_range.end,
14968                    goal: SelectionGoal::None,
14969                    reversed: selection.reversed,
14970                }
14971            })
14972            .collect::<Vec<_>>();
14973
14974        if !selected_larger_node {
14975            return; // don't put this call in the history
14976        }
14977
14978        // scroll based on transformation done to the last selection created by the user
14979        let (last_old, last_new) = old_selections
14980            .last()
14981            .zip(new_selections.last().cloned())
14982            .expect("old_selections isn't empty");
14983
14984        // revert selection
14985        let is_selection_reversed = {
14986            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14987            new_selections.last_mut().expect("checked above").reversed =
14988                should_newest_selection_be_reversed;
14989            should_newest_selection_be_reversed
14990        };
14991
14992        if selected_larger_node {
14993            self.select_syntax_node_history.disable_clearing = true;
14994            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14995                s.select(new_selections.clone());
14996            });
14997            self.select_syntax_node_history.disable_clearing = false;
14998        }
14999
15000        let start_row = last_new.start.to_display_point(&display_map).row().0;
15001        let end_row = last_new.end.to_display_point(&display_map).row().0;
15002        let selection_height = end_row - start_row + 1;
15003        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15004
15005        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15006        let scroll_behavior = if fits_on_the_screen {
15007            self.request_autoscroll(Autoscroll::fit(), cx);
15008            SelectSyntaxNodeScrollBehavior::FitSelection
15009        } else if is_selection_reversed {
15010            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15011            SelectSyntaxNodeScrollBehavior::CursorTop
15012        } else {
15013            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15014            SelectSyntaxNodeScrollBehavior::CursorBottom
15015        };
15016
15017        self.select_syntax_node_history.push((
15018            old_selections,
15019            scroll_behavior,
15020            is_selection_reversed,
15021        ));
15022    }
15023
15024    pub fn select_smaller_syntax_node(
15025        &mut self,
15026        _: &SelectSmallerSyntaxNode,
15027        window: &mut Window,
15028        cx: &mut Context<Self>,
15029    ) {
15030        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15031
15032        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15033            self.select_syntax_node_history.pop()
15034        {
15035            if let Some(selection) = selections.last_mut() {
15036                selection.reversed = is_selection_reversed;
15037            }
15038
15039            self.select_syntax_node_history.disable_clearing = true;
15040            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15041                s.select(selections.to_vec());
15042            });
15043            self.select_syntax_node_history.disable_clearing = false;
15044
15045            match scroll_behavior {
15046                SelectSyntaxNodeScrollBehavior::CursorTop => {
15047                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15048                }
15049                SelectSyntaxNodeScrollBehavior::FitSelection => {
15050                    self.request_autoscroll(Autoscroll::fit(), cx);
15051                }
15052                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15053                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15054                }
15055            }
15056        }
15057    }
15058
15059    pub fn unwrap_syntax_node(
15060        &mut self,
15061        _: &UnwrapSyntaxNode,
15062        window: &mut Window,
15063        cx: &mut Context<Self>,
15064    ) {
15065        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15066
15067        let buffer = self.buffer.read(cx).snapshot(cx);
15068        let selections = self
15069            .selections
15070            .all::<usize>(cx)
15071            .into_iter()
15072            // subtracting the offset requires sorting
15073            .sorted_by_key(|i| i.start);
15074
15075        let full_edits = selections
15076            .into_iter()
15077            .filter_map(|selection| {
15078                // Only requires two branches once if-let-chains stabilize (#53667)
15079                let child = if !selection.is_empty() {
15080                    selection.range()
15081                } else if let Some((_, ancestor_range)) =
15082                    buffer.syntax_ancestor(selection.start..selection.end)
15083                {
15084                    match ancestor_range {
15085                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15086                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15087                    }
15088                } else {
15089                    selection.range()
15090                };
15091
15092                let mut parent = child.clone();
15093                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15094                    parent = match ancestor_range {
15095                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15096                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15097                    };
15098                    if parent.start < child.start || parent.end > child.end {
15099                        break;
15100                    }
15101                }
15102
15103                if parent == child {
15104                    return None;
15105                }
15106                let text = buffer.text_for_range(child).collect::<String>();
15107                Some((selection.id, parent, text))
15108            })
15109            .collect::<Vec<_>>();
15110
15111        self.transact(window, cx, |this, window, cx| {
15112            this.buffer.update(cx, |buffer, cx| {
15113                buffer.edit(
15114                    full_edits
15115                        .iter()
15116                        .map(|(_, p, t)| (p.clone(), t.clone()))
15117                        .collect::<Vec<_>>(),
15118                    None,
15119                    cx,
15120                );
15121            });
15122            this.change_selections(Default::default(), window, cx, |s| {
15123                let mut offset = 0;
15124                let mut selections = vec![];
15125                for (id, parent, text) in full_edits {
15126                    let start = parent.start - offset;
15127                    offset += parent.len() - text.len();
15128                    selections.push(Selection {
15129                        id,
15130                        start,
15131                        end: start + text.len(),
15132                        reversed: false,
15133                        goal: Default::default(),
15134                    });
15135                }
15136                s.select(selections);
15137            });
15138        });
15139    }
15140
15141    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15142        if !EditorSettings::get_global(cx).gutter.runnables {
15143            self.clear_tasks();
15144            return Task::ready(());
15145        }
15146        let project = self.project().map(Entity::downgrade);
15147        let task_sources = self.lsp_task_sources(cx);
15148        let multi_buffer = self.buffer.downgrade();
15149        cx.spawn_in(window, async move |editor, cx| {
15150            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15151            let Some(project) = project.and_then(|p| p.upgrade()) else {
15152                return;
15153            };
15154            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15155                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15156            }) else {
15157                return;
15158            };
15159
15160            let hide_runnables = project
15161                .update(cx, |project, _| project.is_via_collab())
15162                .unwrap_or(true);
15163            if hide_runnables {
15164                return;
15165            }
15166            let new_rows =
15167                cx.background_spawn({
15168                    let snapshot = display_snapshot.clone();
15169                    async move {
15170                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15171                    }
15172                })
15173                    .await;
15174            let Ok(lsp_tasks) =
15175                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15176            else {
15177                return;
15178            };
15179            let lsp_tasks = lsp_tasks.await;
15180
15181            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15182                lsp_tasks
15183                    .into_iter()
15184                    .flat_map(|(kind, tasks)| {
15185                        tasks.into_iter().filter_map(move |(location, task)| {
15186                            Some((kind.clone(), location?, task))
15187                        })
15188                    })
15189                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15190                        let buffer = location.target.buffer;
15191                        let buffer_snapshot = buffer.read(cx).snapshot();
15192                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15193                            |(excerpt_id, snapshot, _)| {
15194                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15195                                    display_snapshot
15196                                        .buffer_snapshot
15197                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15198                                } else {
15199                                    None
15200                                }
15201                            },
15202                        );
15203                        if let Some(offset) = offset {
15204                            let task_buffer_range =
15205                                location.target.range.to_point(&buffer_snapshot);
15206                            let context_buffer_range =
15207                                task_buffer_range.to_offset(&buffer_snapshot);
15208                            let context_range = BufferOffset(context_buffer_range.start)
15209                                ..BufferOffset(context_buffer_range.end);
15210
15211                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15212                                .or_insert_with(|| RunnableTasks {
15213                                    templates: Vec::new(),
15214                                    offset,
15215                                    column: task_buffer_range.start.column,
15216                                    extra_variables: HashMap::default(),
15217                                    context_range,
15218                                })
15219                                .templates
15220                                .push((kind, task.original_task().clone()));
15221                        }
15222
15223                        acc
15224                    })
15225            }) else {
15226                return;
15227            };
15228
15229            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15230                buffer.language_settings(cx).tasks.prefer_lsp
15231            }) else {
15232                return;
15233            };
15234
15235            let rows = Self::runnable_rows(
15236                project,
15237                display_snapshot,
15238                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15239                new_rows,
15240                cx.clone(),
15241            )
15242            .await;
15243            editor
15244                .update(cx, |editor, _| {
15245                    editor.clear_tasks();
15246                    for (key, mut value) in rows {
15247                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15248                            value.templates.extend(lsp_tasks.templates);
15249                        }
15250
15251                        editor.insert_tasks(key, value);
15252                    }
15253                    for (key, value) in lsp_tasks_by_rows {
15254                        editor.insert_tasks(key, value);
15255                    }
15256                })
15257                .ok();
15258        })
15259    }
15260    fn fetch_runnable_ranges(
15261        snapshot: &DisplaySnapshot,
15262        range: Range<Anchor>,
15263    ) -> Vec<language::RunnableRange> {
15264        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15265    }
15266
15267    fn runnable_rows(
15268        project: Entity<Project>,
15269        snapshot: DisplaySnapshot,
15270        prefer_lsp: bool,
15271        runnable_ranges: Vec<RunnableRange>,
15272        cx: AsyncWindowContext,
15273    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15274        cx.spawn(async move |cx| {
15275            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15276            for mut runnable in runnable_ranges {
15277                let Some(tasks) = cx
15278                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15279                    .ok()
15280                else {
15281                    continue;
15282                };
15283                let mut tasks = tasks.await;
15284
15285                if prefer_lsp {
15286                    tasks.retain(|(task_kind, _)| {
15287                        !matches!(task_kind, TaskSourceKind::Language { .. })
15288                    });
15289                }
15290                if tasks.is_empty() {
15291                    continue;
15292                }
15293
15294                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15295                let Some(row) = snapshot
15296                    .buffer_snapshot
15297                    .buffer_line_for_row(MultiBufferRow(point.row))
15298                    .map(|(_, range)| range.start.row)
15299                else {
15300                    continue;
15301                };
15302
15303                let context_range =
15304                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15305                runnable_rows.push((
15306                    (runnable.buffer_id, row),
15307                    RunnableTasks {
15308                        templates: tasks,
15309                        offset: snapshot
15310                            .buffer_snapshot
15311                            .anchor_before(runnable.run_range.start),
15312                        context_range,
15313                        column: point.column,
15314                        extra_variables: runnable.extra_captures,
15315                    },
15316                ));
15317            }
15318            runnable_rows
15319        })
15320    }
15321
15322    fn templates_with_tags(
15323        project: &Entity<Project>,
15324        runnable: &mut Runnable,
15325        cx: &mut App,
15326    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15327        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15328            let (worktree_id, file) = project
15329                .buffer_for_id(runnable.buffer, cx)
15330                .and_then(|buffer| buffer.read(cx).file())
15331                .map(|file| (file.worktree_id(cx), file.clone()))
15332                .unzip();
15333
15334            (
15335                project.task_store().read(cx).task_inventory().cloned(),
15336                worktree_id,
15337                file,
15338            )
15339        });
15340
15341        let tags = mem::take(&mut runnable.tags);
15342        let language = runnable.language.clone();
15343        cx.spawn(async move |cx| {
15344            let mut templates_with_tags = Vec::new();
15345            if let Some(inventory) = inventory {
15346                for RunnableTag(tag) in tags {
15347                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15348                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15349                    }) else {
15350                        return templates_with_tags;
15351                    };
15352                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15353                        move |(_, template)| {
15354                            template.tags.iter().any(|source_tag| source_tag == &tag)
15355                        },
15356                    ));
15357                }
15358            }
15359            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15360
15361            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15362                // Strongest source wins; if we have worktree tag binding, prefer that to
15363                // global and language bindings;
15364                // if we have a global binding, prefer that to language binding.
15365                let first_mismatch = templates_with_tags
15366                    .iter()
15367                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15368                if let Some(index) = first_mismatch {
15369                    templates_with_tags.truncate(index);
15370                }
15371            }
15372
15373            templates_with_tags
15374        })
15375    }
15376
15377    pub fn move_to_enclosing_bracket(
15378        &mut self,
15379        _: &MoveToEnclosingBracket,
15380        window: &mut Window,
15381        cx: &mut Context<Self>,
15382    ) {
15383        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15384        self.change_selections(Default::default(), window, cx, |s| {
15385            s.move_offsets_with(|snapshot, selection| {
15386                let Some(enclosing_bracket_ranges) =
15387                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15388                else {
15389                    return;
15390                };
15391
15392                let mut best_length = usize::MAX;
15393                let mut best_inside = false;
15394                let mut best_in_bracket_range = false;
15395                let mut best_destination = None;
15396                for (open, close) in enclosing_bracket_ranges {
15397                    let close = close.to_inclusive();
15398                    let length = close.end() - open.start;
15399                    let inside = selection.start >= open.end && selection.end <= *close.start();
15400                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15401                        || close.contains(&selection.head());
15402
15403                    // If best is next to a bracket and current isn't, skip
15404                    if !in_bracket_range && best_in_bracket_range {
15405                        continue;
15406                    }
15407
15408                    // Prefer smaller lengths unless best is inside and current isn't
15409                    if length > best_length && (best_inside || !inside) {
15410                        continue;
15411                    }
15412
15413                    best_length = length;
15414                    best_inside = inside;
15415                    best_in_bracket_range = in_bracket_range;
15416                    best_destination = Some(
15417                        if close.contains(&selection.start) && close.contains(&selection.end) {
15418                            if inside { open.end } else { open.start }
15419                        } else if inside {
15420                            *close.start()
15421                        } else {
15422                            *close.end()
15423                        },
15424                    );
15425                }
15426
15427                if let Some(destination) = best_destination {
15428                    selection.collapse_to(destination, SelectionGoal::None);
15429                }
15430            })
15431        });
15432    }
15433
15434    pub fn undo_selection(
15435        &mut self,
15436        _: &UndoSelection,
15437        window: &mut Window,
15438        cx: &mut Context<Self>,
15439    ) {
15440        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15441        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15442            self.selection_history.mode = SelectionHistoryMode::Undoing;
15443            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15444                this.end_selection(window, cx);
15445                this.change_selections(
15446                    SelectionEffects::scroll(Autoscroll::newest()),
15447                    window,
15448                    cx,
15449                    |s| s.select_anchors(entry.selections.to_vec()),
15450                );
15451            });
15452            self.selection_history.mode = SelectionHistoryMode::Normal;
15453
15454            self.select_next_state = entry.select_next_state;
15455            self.select_prev_state = entry.select_prev_state;
15456            self.add_selections_state = entry.add_selections_state;
15457        }
15458    }
15459
15460    pub fn redo_selection(
15461        &mut self,
15462        _: &RedoSelection,
15463        window: &mut Window,
15464        cx: &mut Context<Self>,
15465    ) {
15466        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15467        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15468            self.selection_history.mode = SelectionHistoryMode::Redoing;
15469            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15470                this.end_selection(window, cx);
15471                this.change_selections(
15472                    SelectionEffects::scroll(Autoscroll::newest()),
15473                    window,
15474                    cx,
15475                    |s| s.select_anchors(entry.selections.to_vec()),
15476                );
15477            });
15478            self.selection_history.mode = SelectionHistoryMode::Normal;
15479
15480            self.select_next_state = entry.select_next_state;
15481            self.select_prev_state = entry.select_prev_state;
15482            self.add_selections_state = entry.add_selections_state;
15483        }
15484    }
15485
15486    pub fn expand_excerpts(
15487        &mut self,
15488        action: &ExpandExcerpts,
15489        _: &mut Window,
15490        cx: &mut Context<Self>,
15491    ) {
15492        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15493    }
15494
15495    pub fn expand_excerpts_down(
15496        &mut self,
15497        action: &ExpandExcerptsDown,
15498        _: &mut Window,
15499        cx: &mut Context<Self>,
15500    ) {
15501        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15502    }
15503
15504    pub fn expand_excerpts_up(
15505        &mut self,
15506        action: &ExpandExcerptsUp,
15507        _: &mut Window,
15508        cx: &mut Context<Self>,
15509    ) {
15510        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15511    }
15512
15513    pub fn expand_excerpts_for_direction(
15514        &mut self,
15515        lines: u32,
15516        direction: ExpandExcerptDirection,
15517
15518        cx: &mut Context<Self>,
15519    ) {
15520        let selections = self.selections.disjoint_anchors();
15521
15522        let lines = if lines == 0 {
15523            EditorSettings::get_global(cx).expand_excerpt_lines
15524        } else {
15525            lines
15526        };
15527
15528        self.buffer.update(cx, |buffer, cx| {
15529            let snapshot = buffer.snapshot(cx);
15530            let mut excerpt_ids = selections
15531                .iter()
15532                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15533                .collect::<Vec<_>>();
15534            excerpt_ids.sort();
15535            excerpt_ids.dedup();
15536            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15537        })
15538    }
15539
15540    pub fn expand_excerpt(
15541        &mut self,
15542        excerpt: ExcerptId,
15543        direction: ExpandExcerptDirection,
15544        window: &mut Window,
15545        cx: &mut Context<Self>,
15546    ) {
15547        let current_scroll_position = self.scroll_position(cx);
15548        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15549        let mut should_scroll_up = false;
15550
15551        if direction == ExpandExcerptDirection::Down {
15552            let multi_buffer = self.buffer.read(cx);
15553            let snapshot = multi_buffer.snapshot(cx);
15554            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15555                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15556                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15557            {
15558                let buffer_snapshot = buffer.read(cx).snapshot();
15559                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15560                let last_row = buffer_snapshot.max_point().row;
15561                let lines_below = last_row.saturating_sub(excerpt_end_row);
15562                should_scroll_up = lines_below >= lines_to_expand;
15563            }
15564        }
15565
15566        self.buffer.update(cx, |buffer, cx| {
15567            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15568        });
15569
15570        if should_scroll_up {
15571            let new_scroll_position =
15572                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15573            self.set_scroll_position(new_scroll_position, window, cx);
15574        }
15575    }
15576
15577    pub fn go_to_singleton_buffer_point(
15578        &mut self,
15579        point: Point,
15580        window: &mut Window,
15581        cx: &mut Context<Self>,
15582    ) {
15583        self.go_to_singleton_buffer_range(point..point, window, cx);
15584    }
15585
15586    pub fn go_to_singleton_buffer_range(
15587        &mut self,
15588        range: Range<Point>,
15589        window: &mut Window,
15590        cx: &mut Context<Self>,
15591    ) {
15592        let multibuffer = self.buffer().read(cx);
15593        let Some(buffer) = multibuffer.as_singleton() else {
15594            return;
15595        };
15596        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15597            return;
15598        };
15599        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15600            return;
15601        };
15602        self.change_selections(
15603            SelectionEffects::default().nav_history(true),
15604            window,
15605            cx,
15606            |s| s.select_anchor_ranges([start..end]),
15607        );
15608    }
15609
15610    pub fn go_to_diagnostic(
15611        &mut self,
15612        action: &GoToDiagnostic,
15613        window: &mut Window,
15614        cx: &mut Context<Self>,
15615    ) {
15616        if !self.diagnostics_enabled() {
15617            return;
15618        }
15619        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15620        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15621    }
15622
15623    pub fn go_to_prev_diagnostic(
15624        &mut self,
15625        action: &GoToPreviousDiagnostic,
15626        window: &mut Window,
15627        cx: &mut Context<Self>,
15628    ) {
15629        if !self.diagnostics_enabled() {
15630            return;
15631        }
15632        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15633        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15634    }
15635
15636    pub fn go_to_diagnostic_impl(
15637        &mut self,
15638        direction: Direction,
15639        severity: GoToDiagnosticSeverityFilter,
15640        window: &mut Window,
15641        cx: &mut Context<Self>,
15642    ) {
15643        let buffer = self.buffer.read(cx).snapshot(cx);
15644        let selection = self.selections.newest::<usize>(cx);
15645
15646        let mut active_group_id = None;
15647        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15648            && active_group.active_range.start.to_offset(&buffer) == selection.start
15649        {
15650            active_group_id = Some(active_group.group_id);
15651        }
15652
15653        fn filtered(
15654            snapshot: EditorSnapshot,
15655            severity: GoToDiagnosticSeverityFilter,
15656            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15657        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15658            diagnostics
15659                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15660                .filter(|entry| entry.range.start != entry.range.end)
15661                .filter(|entry| !entry.diagnostic.is_unnecessary)
15662                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15663        }
15664
15665        let snapshot = self.snapshot(window, cx);
15666        let before = filtered(
15667            snapshot.clone(),
15668            severity,
15669            buffer
15670                .diagnostics_in_range(0..selection.start)
15671                .filter(|entry| entry.range.start <= selection.start),
15672        );
15673        let after = filtered(
15674            snapshot,
15675            severity,
15676            buffer
15677                .diagnostics_in_range(selection.start..buffer.len())
15678                .filter(|entry| entry.range.start >= selection.start),
15679        );
15680
15681        let mut found: Option<DiagnosticEntry<usize>> = None;
15682        if direction == Direction::Prev {
15683            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15684            {
15685                for diagnostic in prev_diagnostics.into_iter().rev() {
15686                    if diagnostic.range.start != selection.start
15687                        || active_group_id
15688                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15689                    {
15690                        found = Some(diagnostic);
15691                        break 'outer;
15692                    }
15693                }
15694            }
15695        } else {
15696            for diagnostic in after.chain(before) {
15697                if diagnostic.range.start != selection.start
15698                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15699                {
15700                    found = Some(diagnostic);
15701                    break;
15702                }
15703            }
15704        }
15705        let Some(next_diagnostic) = found else {
15706            return;
15707        };
15708
15709        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15710        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15711            return;
15712        };
15713        self.change_selections(Default::default(), window, cx, |s| {
15714            s.select_ranges(vec![
15715                next_diagnostic.range.start..next_diagnostic.range.start,
15716            ])
15717        });
15718        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15719        self.refresh_edit_prediction(false, true, window, cx);
15720    }
15721
15722    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15723        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15724        let snapshot = self.snapshot(window, cx);
15725        let selection = self.selections.newest::<Point>(cx);
15726        self.go_to_hunk_before_or_after_position(
15727            &snapshot,
15728            selection.head(),
15729            Direction::Next,
15730            window,
15731            cx,
15732        );
15733    }
15734
15735    pub fn go_to_hunk_before_or_after_position(
15736        &mut self,
15737        snapshot: &EditorSnapshot,
15738        position: Point,
15739        direction: Direction,
15740        window: &mut Window,
15741        cx: &mut Context<Editor>,
15742    ) {
15743        let row = if direction == Direction::Next {
15744            self.hunk_after_position(snapshot, position)
15745                .map(|hunk| hunk.row_range.start)
15746        } else {
15747            self.hunk_before_position(snapshot, position)
15748        };
15749
15750        if let Some(row) = row {
15751            let destination = Point::new(row.0, 0);
15752            let autoscroll = Autoscroll::center();
15753
15754            self.unfold_ranges(&[destination..destination], false, false, cx);
15755            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15756                s.select_ranges([destination..destination]);
15757            });
15758        }
15759    }
15760
15761    fn hunk_after_position(
15762        &mut self,
15763        snapshot: &EditorSnapshot,
15764        position: Point,
15765    ) -> Option<MultiBufferDiffHunk> {
15766        snapshot
15767            .buffer_snapshot
15768            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15769            .find(|hunk| hunk.row_range.start.0 > position.row)
15770            .or_else(|| {
15771                snapshot
15772                    .buffer_snapshot
15773                    .diff_hunks_in_range(Point::zero()..position)
15774                    .find(|hunk| hunk.row_range.end.0 < position.row)
15775            })
15776    }
15777
15778    fn go_to_prev_hunk(
15779        &mut self,
15780        _: &GoToPreviousHunk,
15781        window: &mut Window,
15782        cx: &mut Context<Self>,
15783    ) {
15784        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15785        let snapshot = self.snapshot(window, cx);
15786        let selection = self.selections.newest::<Point>(cx);
15787        self.go_to_hunk_before_or_after_position(
15788            &snapshot,
15789            selection.head(),
15790            Direction::Prev,
15791            window,
15792            cx,
15793        );
15794    }
15795
15796    fn hunk_before_position(
15797        &mut self,
15798        snapshot: &EditorSnapshot,
15799        position: Point,
15800    ) -> Option<MultiBufferRow> {
15801        snapshot
15802            .buffer_snapshot
15803            .diff_hunk_before(position)
15804            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15805    }
15806
15807    fn go_to_next_change(
15808        &mut self,
15809        _: &GoToNextChange,
15810        window: &mut Window,
15811        cx: &mut Context<Self>,
15812    ) {
15813        if let Some(selections) = self
15814            .change_list
15815            .next_change(1, Direction::Next)
15816            .map(|s| s.to_vec())
15817        {
15818            self.change_selections(Default::default(), window, cx, |s| {
15819                let map = s.display_map();
15820                s.select_display_ranges(selections.iter().map(|a| {
15821                    let point = a.to_display_point(&map);
15822                    point..point
15823                }))
15824            })
15825        }
15826    }
15827
15828    fn go_to_previous_change(
15829        &mut self,
15830        _: &GoToPreviousChange,
15831        window: &mut Window,
15832        cx: &mut Context<Self>,
15833    ) {
15834        if let Some(selections) = self
15835            .change_list
15836            .next_change(1, Direction::Prev)
15837            .map(|s| s.to_vec())
15838        {
15839            self.change_selections(Default::default(), window, cx, |s| {
15840                let map = s.display_map();
15841                s.select_display_ranges(selections.iter().map(|a| {
15842                    let point = a.to_display_point(&map);
15843                    point..point
15844                }))
15845            })
15846        }
15847    }
15848
15849    fn go_to_line<T: 'static>(
15850        &mut self,
15851        position: Anchor,
15852        highlight_color: Option<Hsla>,
15853        window: &mut Window,
15854        cx: &mut Context<Self>,
15855    ) {
15856        let snapshot = self.snapshot(window, cx).display_snapshot;
15857        let position = position.to_point(&snapshot.buffer_snapshot);
15858        let start = snapshot
15859            .buffer_snapshot
15860            .clip_point(Point::new(position.row, 0), Bias::Left);
15861        let end = start + Point::new(1, 0);
15862        let start = snapshot.buffer_snapshot.anchor_before(start);
15863        let end = snapshot.buffer_snapshot.anchor_before(end);
15864
15865        self.highlight_rows::<T>(
15866            start..end,
15867            highlight_color
15868                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15869            Default::default(),
15870            cx,
15871        );
15872
15873        if self.buffer.read(cx).is_singleton() {
15874            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15875        }
15876    }
15877
15878    pub fn go_to_definition(
15879        &mut self,
15880        _: &GoToDefinition,
15881        window: &mut Window,
15882        cx: &mut Context<Self>,
15883    ) -> Task<Result<Navigated>> {
15884        let definition =
15885            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15886        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15887        cx.spawn_in(window, async move |editor, cx| {
15888            if definition.await? == Navigated::Yes {
15889                return Ok(Navigated::Yes);
15890            }
15891            match fallback_strategy {
15892                GoToDefinitionFallback::None => Ok(Navigated::No),
15893                GoToDefinitionFallback::FindAllReferences => {
15894                    match editor.update_in(cx, |editor, window, cx| {
15895                        editor.find_all_references(&FindAllReferences, window, cx)
15896                    })? {
15897                        Some(references) => references.await,
15898                        None => Ok(Navigated::No),
15899                    }
15900                }
15901            }
15902        })
15903    }
15904
15905    pub fn go_to_declaration(
15906        &mut self,
15907        _: &GoToDeclaration,
15908        window: &mut Window,
15909        cx: &mut Context<Self>,
15910    ) -> Task<Result<Navigated>> {
15911        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15912    }
15913
15914    pub fn go_to_declaration_split(
15915        &mut self,
15916        _: &GoToDeclaration,
15917        window: &mut Window,
15918        cx: &mut Context<Self>,
15919    ) -> Task<Result<Navigated>> {
15920        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15921    }
15922
15923    pub fn go_to_implementation(
15924        &mut self,
15925        _: &GoToImplementation,
15926        window: &mut Window,
15927        cx: &mut Context<Self>,
15928    ) -> Task<Result<Navigated>> {
15929        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15930    }
15931
15932    pub fn go_to_implementation_split(
15933        &mut self,
15934        _: &GoToImplementationSplit,
15935        window: &mut Window,
15936        cx: &mut Context<Self>,
15937    ) -> Task<Result<Navigated>> {
15938        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15939    }
15940
15941    pub fn go_to_type_definition(
15942        &mut self,
15943        _: &GoToTypeDefinition,
15944        window: &mut Window,
15945        cx: &mut Context<Self>,
15946    ) -> Task<Result<Navigated>> {
15947        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15948    }
15949
15950    pub fn go_to_definition_split(
15951        &mut self,
15952        _: &GoToDefinitionSplit,
15953        window: &mut Window,
15954        cx: &mut Context<Self>,
15955    ) -> Task<Result<Navigated>> {
15956        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15957    }
15958
15959    pub fn go_to_type_definition_split(
15960        &mut self,
15961        _: &GoToTypeDefinitionSplit,
15962        window: &mut Window,
15963        cx: &mut Context<Self>,
15964    ) -> Task<Result<Navigated>> {
15965        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15966    }
15967
15968    fn go_to_definition_of_kind(
15969        &mut self,
15970        kind: GotoDefinitionKind,
15971        split: bool,
15972        window: &mut Window,
15973        cx: &mut Context<Self>,
15974    ) -> Task<Result<Navigated>> {
15975        let Some(provider) = self.semantics_provider.clone() else {
15976            return Task::ready(Ok(Navigated::No));
15977        };
15978        let head = self.selections.newest::<usize>(cx).head();
15979        let buffer = self.buffer.read(cx);
15980        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15981            return Task::ready(Ok(Navigated::No));
15982        };
15983        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15984            return Task::ready(Ok(Navigated::No));
15985        };
15986
15987        cx.spawn_in(window, async move |editor, cx| {
15988            let Some(definitions) = definitions.await? else {
15989                return Ok(Navigated::No);
15990            };
15991            let navigated = editor
15992                .update_in(cx, |editor, window, cx| {
15993                    editor.navigate_to_hover_links(
15994                        Some(kind),
15995                        definitions
15996                            .into_iter()
15997                            .filter(|location| {
15998                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15999                            })
16000                            .map(HoverLink::Text)
16001                            .collect::<Vec<_>>(),
16002                        split,
16003                        window,
16004                        cx,
16005                    )
16006                })?
16007                .await?;
16008            anyhow::Ok(navigated)
16009        })
16010    }
16011
16012    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16013        let selection = self.selections.newest_anchor();
16014        let head = selection.head();
16015        let tail = selection.tail();
16016
16017        let Some((buffer, start_position)) =
16018            self.buffer.read(cx).text_anchor_for_position(head, cx)
16019        else {
16020            return;
16021        };
16022
16023        let end_position = if head != tail {
16024            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16025                return;
16026            };
16027            Some(pos)
16028        } else {
16029            None
16030        };
16031
16032        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16033            let url = if let Some(end_pos) = end_position {
16034                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16035            } else {
16036                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16037            };
16038
16039            if let Some(url) = url {
16040                editor.update(cx, |_, cx| {
16041                    cx.open_url(&url);
16042                })
16043            } else {
16044                Ok(())
16045            }
16046        });
16047
16048        url_finder.detach();
16049    }
16050
16051    pub fn open_selected_filename(
16052        &mut self,
16053        _: &OpenSelectedFilename,
16054        window: &mut Window,
16055        cx: &mut Context<Self>,
16056    ) {
16057        let Some(workspace) = self.workspace() else {
16058            return;
16059        };
16060
16061        let position = self.selections.newest_anchor().head();
16062
16063        let Some((buffer, buffer_position)) =
16064            self.buffer.read(cx).text_anchor_for_position(position, cx)
16065        else {
16066            return;
16067        };
16068
16069        let project = self.project.clone();
16070
16071        cx.spawn_in(window, async move |_, cx| {
16072            let result = find_file(&buffer, project, buffer_position, cx).await;
16073
16074            if let Some((_, path)) = result {
16075                workspace
16076                    .update_in(cx, |workspace, window, cx| {
16077                        workspace.open_resolved_path(path, window, cx)
16078                    })?
16079                    .await?;
16080            }
16081            anyhow::Ok(())
16082        })
16083        .detach();
16084    }
16085
16086    pub(crate) fn navigate_to_hover_links(
16087        &mut self,
16088        kind: Option<GotoDefinitionKind>,
16089        definitions: Vec<HoverLink>,
16090        split: bool,
16091        window: &mut Window,
16092        cx: &mut Context<Editor>,
16093    ) -> Task<Result<Navigated>> {
16094        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16095        let mut first_url_or_file = None;
16096        let definitions: Vec<_> = definitions
16097            .into_iter()
16098            .filter_map(|def| match def {
16099                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16100                HoverLink::InlayHint(lsp_location, server_id) => {
16101                    let computation =
16102                        self.compute_target_location(lsp_location, server_id, window, cx);
16103                    Some(cx.background_spawn(computation))
16104                }
16105                HoverLink::Url(url) => {
16106                    first_url_or_file = Some(Either::Left(url));
16107                    None
16108                }
16109                HoverLink::File(path) => {
16110                    first_url_or_file = Some(Either::Right(path));
16111                    None
16112                }
16113            })
16114            .collect();
16115
16116        let workspace = self.workspace();
16117
16118        cx.spawn_in(window, async move |editor, acx| {
16119            let mut locations: Vec<Location> = future::join_all(definitions)
16120                .await
16121                .into_iter()
16122                .filter_map(|location| location.transpose())
16123                .collect::<Result<_>>()
16124                .context("location tasks")?;
16125
16126            if locations.len() > 1 {
16127                let Some(workspace) = workspace else {
16128                    return Ok(Navigated::No);
16129                };
16130
16131                let tab_kind = match kind {
16132                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16133                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16134                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16135                    Some(GotoDefinitionKind::Type) => "Types",
16136                };
16137                let title = editor
16138                    .update_in(acx, |_, _, cx| {
16139                        let target = locations
16140                            .iter()
16141                            .map(|location| {
16142                                location
16143                                    .buffer
16144                                    .read(cx)
16145                                    .text_for_range(location.range.clone())
16146                                    .collect::<String>()
16147                            })
16148                            .filter(|text| !text.contains('\n'))
16149                            .unique()
16150                            .take(3)
16151                            .join(", ");
16152                        if target.is_empty() {
16153                            tab_kind.to_owned()
16154                        } else {
16155                            format!("{tab_kind} for {target}")
16156                        }
16157                    })
16158                    .context("buffer title")?;
16159
16160                let opened = workspace
16161                    .update_in(acx, |workspace, window, cx| {
16162                        Self::open_locations_in_multibuffer(
16163                            workspace,
16164                            locations,
16165                            title,
16166                            split,
16167                            MultibufferSelectionMode::First,
16168                            window,
16169                            cx,
16170                        )
16171                    })
16172                    .is_ok();
16173
16174                anyhow::Ok(Navigated::from_bool(opened))
16175            } else if locations.is_empty() {
16176                // If there is one definition, just open it directly
16177                match first_url_or_file {
16178                    Some(Either::Left(url)) => {
16179                        acx.update(|_, cx| cx.open_url(&url))?;
16180                        Ok(Navigated::Yes)
16181                    }
16182                    Some(Either::Right(path)) => {
16183                        let Some(workspace) = workspace else {
16184                            return Ok(Navigated::No);
16185                        };
16186
16187                        workspace
16188                            .update_in(acx, |workspace, window, cx| {
16189                                workspace.open_resolved_path(path, window, cx)
16190                            })?
16191                            .await?;
16192                        Ok(Navigated::Yes)
16193                    }
16194                    None => Ok(Navigated::No),
16195                }
16196            } else {
16197                let Some(workspace) = workspace else {
16198                    return Ok(Navigated::No);
16199                };
16200
16201                let target = locations.pop().unwrap();
16202                editor.update_in(acx, |editor, window, cx| {
16203                    let pane = workspace.read(cx).active_pane().clone();
16204
16205                    let range = target.range.to_point(target.buffer.read(cx));
16206                    let range = editor.range_for_match(&range);
16207                    let range = collapse_multiline_range(range);
16208
16209                    if !split
16210                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16211                    {
16212                        editor.go_to_singleton_buffer_range(range, window, cx);
16213                    } else {
16214                        window.defer(cx, move |window, cx| {
16215                            let target_editor: Entity<Self> =
16216                                workspace.update(cx, |workspace, cx| {
16217                                    let pane = if split {
16218                                        workspace.adjacent_pane(window, cx)
16219                                    } else {
16220                                        workspace.active_pane().clone()
16221                                    };
16222
16223                                    workspace.open_project_item(
16224                                        pane,
16225                                        target.buffer.clone(),
16226                                        true,
16227                                        true,
16228                                        window,
16229                                        cx,
16230                                    )
16231                                });
16232                            target_editor.update(cx, |target_editor, cx| {
16233                                // When selecting a definition in a different buffer, disable the nav history
16234                                // to avoid creating a history entry at the previous cursor location.
16235                                pane.update(cx, |pane, _| pane.disable_history());
16236                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16237                                pane.update(cx, |pane, _| pane.enable_history());
16238                            });
16239                        });
16240                    }
16241                    Navigated::Yes
16242                })
16243            }
16244        })
16245    }
16246
16247    fn compute_target_location(
16248        &self,
16249        lsp_location: lsp::Location,
16250        server_id: LanguageServerId,
16251        window: &mut Window,
16252        cx: &mut Context<Self>,
16253    ) -> Task<anyhow::Result<Option<Location>>> {
16254        let Some(project) = self.project.clone() else {
16255            return Task::ready(Ok(None));
16256        };
16257
16258        cx.spawn_in(window, async move |editor, cx| {
16259            let location_task = editor.update(cx, |_, cx| {
16260                project.update(cx, |project, cx| {
16261                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16262                })
16263            })?;
16264            let location = Some({
16265                let target_buffer_handle = location_task.await.context("open local buffer")?;
16266                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16267                    let target_start = target_buffer
16268                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16269                    let target_end = target_buffer
16270                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16271                    target_buffer.anchor_after(target_start)
16272                        ..target_buffer.anchor_before(target_end)
16273                })?;
16274                Location {
16275                    buffer: target_buffer_handle,
16276                    range,
16277                }
16278            });
16279            Ok(location)
16280        })
16281    }
16282
16283    pub fn find_all_references(
16284        &mut self,
16285        _: &FindAllReferences,
16286        window: &mut Window,
16287        cx: &mut Context<Self>,
16288    ) -> Option<Task<Result<Navigated>>> {
16289        let selection = self.selections.newest::<usize>(cx);
16290        let multi_buffer = self.buffer.read(cx);
16291        let head = selection.head();
16292
16293        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16294        let head_anchor = multi_buffer_snapshot.anchor_at(
16295            head,
16296            if head < selection.tail() {
16297                Bias::Right
16298            } else {
16299                Bias::Left
16300            },
16301        );
16302
16303        match self
16304            .find_all_references_task_sources
16305            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16306        {
16307            Ok(_) => {
16308                log::info!(
16309                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16310                );
16311                return None;
16312            }
16313            Err(i) => {
16314                self.find_all_references_task_sources.insert(i, head_anchor);
16315            }
16316        }
16317
16318        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16319        let workspace = self.workspace()?;
16320        let project = workspace.read(cx).project().clone();
16321        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16322        Some(cx.spawn_in(window, async move |editor, cx| {
16323            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16324                if let Ok(i) = editor
16325                    .find_all_references_task_sources
16326                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16327                {
16328                    editor.find_all_references_task_sources.remove(i);
16329                }
16330            });
16331
16332            let Some(locations) = references.await? else {
16333                return anyhow::Ok(Navigated::No);
16334            };
16335            if locations.is_empty() {
16336                return anyhow::Ok(Navigated::No);
16337            }
16338
16339            workspace.update_in(cx, |workspace, window, cx| {
16340                let target = locations
16341                    .iter()
16342                    .map(|location| {
16343                        location
16344                            .buffer
16345                            .read(cx)
16346                            .text_for_range(location.range.clone())
16347                            .collect::<String>()
16348                    })
16349                    .filter(|text| !text.contains('\n'))
16350                    .unique()
16351                    .take(3)
16352                    .join(", ");
16353                let title = if target.is_empty() {
16354                    "References".to_owned()
16355                } else {
16356                    format!("References to {target}")
16357                };
16358                Self::open_locations_in_multibuffer(
16359                    workspace,
16360                    locations,
16361                    title,
16362                    false,
16363                    MultibufferSelectionMode::First,
16364                    window,
16365                    cx,
16366                );
16367                Navigated::Yes
16368            })
16369        }))
16370    }
16371
16372    /// Opens a multibuffer with the given project locations in it
16373    pub fn open_locations_in_multibuffer(
16374        workspace: &mut Workspace,
16375        mut locations: Vec<Location>,
16376        title: String,
16377        split: bool,
16378        multibuffer_selection_mode: MultibufferSelectionMode,
16379        window: &mut Window,
16380        cx: &mut Context<Workspace>,
16381    ) {
16382        if locations.is_empty() {
16383            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16384            return;
16385        }
16386
16387        // If there are multiple definitions, open them in a multibuffer
16388        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16389        let mut locations = locations.into_iter().peekable();
16390        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16391        let capability = workspace.project().read(cx).capability();
16392
16393        let excerpt_buffer = cx.new(|cx| {
16394            let mut multibuffer = MultiBuffer::new(capability);
16395            while let Some(location) = locations.next() {
16396                let buffer = location.buffer.read(cx);
16397                let mut ranges_for_buffer = Vec::new();
16398                let range = location.range.to_point(buffer);
16399                ranges_for_buffer.push(range.clone());
16400
16401                while let Some(next_location) = locations.peek() {
16402                    if next_location.buffer == location.buffer {
16403                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16404                        locations.next();
16405                    } else {
16406                        break;
16407                    }
16408                }
16409
16410                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16411                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16412                    PathKey::for_buffer(&location.buffer, cx),
16413                    location.buffer.clone(),
16414                    ranges_for_buffer,
16415                    multibuffer_context_lines(cx),
16416                    cx,
16417                );
16418                ranges.extend(new_ranges)
16419            }
16420
16421            multibuffer.with_title(title)
16422        });
16423
16424        let editor = cx.new(|cx| {
16425            Editor::for_multibuffer(
16426                excerpt_buffer,
16427                Some(workspace.project().clone()),
16428                window,
16429                cx,
16430            )
16431        });
16432        editor.update(cx, |editor, cx| {
16433            match multibuffer_selection_mode {
16434                MultibufferSelectionMode::First => {
16435                    if let Some(first_range) = ranges.first() {
16436                        editor.change_selections(
16437                            SelectionEffects::no_scroll(),
16438                            window,
16439                            cx,
16440                            |selections| {
16441                                selections.clear_disjoint();
16442                                selections
16443                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16444                            },
16445                        );
16446                    }
16447                    editor.highlight_background::<Self>(
16448                        &ranges,
16449                        |theme| theme.colors().editor_highlighted_line_background,
16450                        cx,
16451                    );
16452                }
16453                MultibufferSelectionMode::All => {
16454                    editor.change_selections(
16455                        SelectionEffects::no_scroll(),
16456                        window,
16457                        cx,
16458                        |selections| {
16459                            selections.clear_disjoint();
16460                            selections.select_anchor_ranges(ranges);
16461                        },
16462                    );
16463                }
16464            }
16465            editor.register_buffers_with_language_servers(cx);
16466        });
16467
16468        let item = Box::new(editor);
16469        let item_id = item.item_id();
16470
16471        if split {
16472            workspace.split_item(SplitDirection::Right, item, window, cx);
16473        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16474            let (preview_item_id, preview_item_idx) =
16475                workspace.active_pane().read_with(cx, |pane, _| {
16476                    (pane.preview_item_id(), pane.preview_item_idx())
16477                });
16478
16479            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16480
16481            if let Some(preview_item_id) = preview_item_id {
16482                workspace.active_pane().update(cx, |pane, cx| {
16483                    pane.remove_item(preview_item_id, false, false, window, cx);
16484                });
16485            }
16486        } else {
16487            workspace.add_item_to_active_pane(item, None, true, window, cx);
16488        }
16489        workspace.active_pane().update(cx, |pane, cx| {
16490            pane.set_preview_item_id(Some(item_id), cx);
16491        });
16492    }
16493
16494    pub fn rename(
16495        &mut self,
16496        _: &Rename,
16497        window: &mut Window,
16498        cx: &mut Context<Self>,
16499    ) -> Option<Task<Result<()>>> {
16500        use language::ToOffset as _;
16501
16502        let provider = self.semantics_provider.clone()?;
16503        let selection = self.selections.newest_anchor().clone();
16504        let (cursor_buffer, cursor_buffer_position) = self
16505            .buffer
16506            .read(cx)
16507            .text_anchor_for_position(selection.head(), cx)?;
16508        let (tail_buffer, cursor_buffer_position_end) = self
16509            .buffer
16510            .read(cx)
16511            .text_anchor_for_position(selection.tail(), cx)?;
16512        if tail_buffer != cursor_buffer {
16513            return None;
16514        }
16515
16516        let snapshot = cursor_buffer.read(cx).snapshot();
16517        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16518        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16519        let prepare_rename = provider
16520            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16521            .unwrap_or_else(|| Task::ready(Ok(None)));
16522        drop(snapshot);
16523
16524        Some(cx.spawn_in(window, async move |this, cx| {
16525            let rename_range = if let Some(range) = prepare_rename.await? {
16526                Some(range)
16527            } else {
16528                this.update(cx, |this, cx| {
16529                    let buffer = this.buffer.read(cx).snapshot(cx);
16530                    let mut buffer_highlights = this
16531                        .document_highlights_for_position(selection.head(), &buffer)
16532                        .filter(|highlight| {
16533                            highlight.start.excerpt_id == selection.head().excerpt_id
16534                                && highlight.end.excerpt_id == selection.head().excerpt_id
16535                        });
16536                    buffer_highlights
16537                        .next()
16538                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16539                })?
16540            };
16541            if let Some(rename_range) = rename_range {
16542                this.update_in(cx, |this, window, cx| {
16543                    let snapshot = cursor_buffer.read(cx).snapshot();
16544                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16545                    let cursor_offset_in_rename_range =
16546                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16547                    let cursor_offset_in_rename_range_end =
16548                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16549
16550                    this.take_rename(false, window, cx);
16551                    let buffer = this.buffer.read(cx).read(cx);
16552                    let cursor_offset = selection.head().to_offset(&buffer);
16553                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16554                    let rename_end = rename_start + rename_buffer_range.len();
16555                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16556                    let mut old_highlight_id = None;
16557                    let old_name: Arc<str> = buffer
16558                        .chunks(rename_start..rename_end, true)
16559                        .map(|chunk| {
16560                            if old_highlight_id.is_none() {
16561                                old_highlight_id = chunk.syntax_highlight_id;
16562                            }
16563                            chunk.text
16564                        })
16565                        .collect::<String>()
16566                        .into();
16567
16568                    drop(buffer);
16569
16570                    // Position the selection in the rename editor so that it matches the current selection.
16571                    this.show_local_selections = false;
16572                    let rename_editor = cx.new(|cx| {
16573                        let mut editor = Editor::single_line(window, cx);
16574                        editor.buffer.update(cx, |buffer, cx| {
16575                            buffer.edit([(0..0, old_name.clone())], None, cx)
16576                        });
16577                        let rename_selection_range = match cursor_offset_in_rename_range
16578                            .cmp(&cursor_offset_in_rename_range_end)
16579                        {
16580                            Ordering::Equal => {
16581                                editor.select_all(&SelectAll, window, cx);
16582                                return editor;
16583                            }
16584                            Ordering::Less => {
16585                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16586                            }
16587                            Ordering::Greater => {
16588                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16589                            }
16590                        };
16591                        if rename_selection_range.end > old_name.len() {
16592                            editor.select_all(&SelectAll, window, cx);
16593                        } else {
16594                            editor.change_selections(Default::default(), window, cx, |s| {
16595                                s.select_ranges([rename_selection_range]);
16596                            });
16597                        }
16598                        editor
16599                    });
16600                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16601                        if e == &EditorEvent::Focused {
16602                            cx.emit(EditorEvent::FocusedIn)
16603                        }
16604                    })
16605                    .detach();
16606
16607                    let write_highlights =
16608                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16609                    let read_highlights =
16610                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16611                    let ranges = write_highlights
16612                        .iter()
16613                        .flat_map(|(_, ranges)| ranges.iter())
16614                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16615                        .cloned()
16616                        .collect();
16617
16618                    this.highlight_text::<Rename>(
16619                        ranges,
16620                        HighlightStyle {
16621                            fade_out: Some(0.6),
16622                            ..Default::default()
16623                        },
16624                        cx,
16625                    );
16626                    let rename_focus_handle = rename_editor.focus_handle(cx);
16627                    window.focus(&rename_focus_handle);
16628                    let block_id = this.insert_blocks(
16629                        [BlockProperties {
16630                            style: BlockStyle::Flex,
16631                            placement: BlockPlacement::Below(range.start),
16632                            height: Some(1),
16633                            render: Arc::new({
16634                                let rename_editor = rename_editor.clone();
16635                                move |cx: &mut BlockContext| {
16636                                    let mut text_style = cx.editor_style.text.clone();
16637                                    if let Some(highlight_style) = old_highlight_id
16638                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16639                                    {
16640                                        text_style = text_style.highlight(highlight_style);
16641                                    }
16642                                    div()
16643                                        .block_mouse_except_scroll()
16644                                        .pl(cx.anchor_x)
16645                                        .child(EditorElement::new(
16646                                            &rename_editor,
16647                                            EditorStyle {
16648                                                background: cx.theme().system().transparent,
16649                                                local_player: cx.editor_style.local_player,
16650                                                text: text_style,
16651                                                scrollbar_width: cx.editor_style.scrollbar_width,
16652                                                syntax: cx.editor_style.syntax.clone(),
16653                                                status: cx.editor_style.status.clone(),
16654                                                inlay_hints_style: HighlightStyle {
16655                                                    font_weight: Some(FontWeight::BOLD),
16656                                                    ..make_inlay_hints_style(cx.app)
16657                                                },
16658                                                edit_prediction_styles: make_suggestion_styles(
16659                                                    cx.app,
16660                                                ),
16661                                                ..EditorStyle::default()
16662                                            },
16663                                        ))
16664                                        .into_any_element()
16665                                }
16666                            }),
16667                            priority: 0,
16668                        }],
16669                        Some(Autoscroll::fit()),
16670                        cx,
16671                    )[0];
16672                    this.pending_rename = Some(RenameState {
16673                        range,
16674                        old_name,
16675                        editor: rename_editor,
16676                        block_id,
16677                    });
16678                })?;
16679            }
16680
16681            Ok(())
16682        }))
16683    }
16684
16685    pub fn confirm_rename(
16686        &mut self,
16687        _: &ConfirmRename,
16688        window: &mut Window,
16689        cx: &mut Context<Self>,
16690    ) -> Option<Task<Result<()>>> {
16691        let rename = self.take_rename(false, window, cx)?;
16692        let workspace = self.workspace()?.downgrade();
16693        let (buffer, start) = self
16694            .buffer
16695            .read(cx)
16696            .text_anchor_for_position(rename.range.start, cx)?;
16697        let (end_buffer, _) = self
16698            .buffer
16699            .read(cx)
16700            .text_anchor_for_position(rename.range.end, cx)?;
16701        if buffer != end_buffer {
16702            return None;
16703        }
16704
16705        let old_name = rename.old_name;
16706        let new_name = rename.editor.read(cx).text(cx);
16707
16708        let rename = self.semantics_provider.as_ref()?.perform_rename(
16709            &buffer,
16710            start,
16711            new_name.clone(),
16712            cx,
16713        )?;
16714
16715        Some(cx.spawn_in(window, async move |editor, cx| {
16716            let project_transaction = rename.await?;
16717            Self::open_project_transaction(
16718                &editor,
16719                workspace,
16720                project_transaction,
16721                format!("Rename: {}{}", old_name, new_name),
16722                cx,
16723            )
16724            .await?;
16725
16726            editor.update(cx, |editor, cx| {
16727                editor.refresh_document_highlights(cx);
16728            })?;
16729            Ok(())
16730        }))
16731    }
16732
16733    fn take_rename(
16734        &mut self,
16735        moving_cursor: bool,
16736        window: &mut Window,
16737        cx: &mut Context<Self>,
16738    ) -> Option<RenameState> {
16739        let rename = self.pending_rename.take()?;
16740        if rename.editor.focus_handle(cx).is_focused(window) {
16741            window.focus(&self.focus_handle);
16742        }
16743
16744        self.remove_blocks(
16745            [rename.block_id].into_iter().collect(),
16746            Some(Autoscroll::fit()),
16747            cx,
16748        );
16749        self.clear_highlights::<Rename>(cx);
16750        self.show_local_selections = true;
16751
16752        if moving_cursor {
16753            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16754                editor.selections.newest::<usize>(cx).head()
16755            });
16756
16757            // Update the selection to match the position of the selection inside
16758            // the rename editor.
16759            let snapshot = self.buffer.read(cx).read(cx);
16760            let rename_range = rename.range.to_offset(&snapshot);
16761            let cursor_in_editor = snapshot
16762                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16763                .min(rename_range.end);
16764            drop(snapshot);
16765
16766            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16767                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16768            });
16769        } else {
16770            self.refresh_document_highlights(cx);
16771        }
16772
16773        Some(rename)
16774    }
16775
16776    pub fn pending_rename(&self) -> Option<&RenameState> {
16777        self.pending_rename.as_ref()
16778    }
16779
16780    fn format(
16781        &mut self,
16782        _: &Format,
16783        window: &mut Window,
16784        cx: &mut Context<Self>,
16785    ) -> Option<Task<Result<()>>> {
16786        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16787
16788        let project = match &self.project {
16789            Some(project) => project.clone(),
16790            None => return None,
16791        };
16792
16793        Some(self.perform_format(
16794            project,
16795            FormatTrigger::Manual,
16796            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16797            window,
16798            cx,
16799        ))
16800    }
16801
16802    fn format_selections(
16803        &mut self,
16804        _: &FormatSelections,
16805        window: &mut Window,
16806        cx: &mut Context<Self>,
16807    ) -> Option<Task<Result<()>>> {
16808        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16809
16810        let project = match &self.project {
16811            Some(project) => project.clone(),
16812            None => return None,
16813        };
16814
16815        let ranges = self
16816            .selections
16817            .all_adjusted(cx)
16818            .into_iter()
16819            .map(|selection| selection.range())
16820            .collect_vec();
16821
16822        Some(self.perform_format(
16823            project,
16824            FormatTrigger::Manual,
16825            FormatTarget::Ranges(ranges),
16826            window,
16827            cx,
16828        ))
16829    }
16830
16831    fn perform_format(
16832        &mut self,
16833        project: Entity<Project>,
16834        trigger: FormatTrigger,
16835        target: FormatTarget,
16836        window: &mut Window,
16837        cx: &mut Context<Self>,
16838    ) -> Task<Result<()>> {
16839        let buffer = self.buffer.clone();
16840        let (buffers, target) = match target {
16841            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16842            FormatTarget::Ranges(selection_ranges) => {
16843                let multi_buffer = buffer.read(cx);
16844                let snapshot = multi_buffer.read(cx);
16845                let mut buffers = HashSet::default();
16846                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16847                    BTreeMap::new();
16848                for selection_range in selection_ranges {
16849                    for (buffer, buffer_range, _) in
16850                        snapshot.range_to_buffer_ranges(selection_range)
16851                    {
16852                        let buffer_id = buffer.remote_id();
16853                        let start = buffer.anchor_before(buffer_range.start);
16854                        let end = buffer.anchor_after(buffer_range.end);
16855                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16856                        buffer_id_to_ranges
16857                            .entry(buffer_id)
16858                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16859                            .or_insert_with(|| vec![start..end]);
16860                    }
16861                }
16862                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16863            }
16864        };
16865
16866        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16867        let selections_prev = transaction_id_prev
16868            .and_then(|transaction_id_prev| {
16869                // default to selections as they were after the last edit, if we have them,
16870                // instead of how they are now.
16871                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16872                // will take you back to where you made the last edit, instead of staying where you scrolled
16873                self.selection_history
16874                    .transaction(transaction_id_prev)
16875                    .map(|t| t.0.clone())
16876            })
16877            .unwrap_or_else(|| self.selections.disjoint_anchors());
16878
16879        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16880        let format = project.update(cx, |project, cx| {
16881            project.format(buffers, target, true, trigger, cx)
16882        });
16883
16884        cx.spawn_in(window, async move |editor, cx| {
16885            let transaction = futures::select_biased! {
16886                transaction = format.log_err().fuse() => transaction,
16887                () = timeout => {
16888                    log::warn!("timed out waiting for formatting");
16889                    None
16890                }
16891            };
16892
16893            buffer
16894                .update(cx, |buffer, cx| {
16895                    if let Some(transaction) = transaction
16896                        && !buffer.is_singleton()
16897                    {
16898                        buffer.push_transaction(&transaction.0, cx);
16899                    }
16900                    cx.notify();
16901                })
16902                .ok();
16903
16904            if let Some(transaction_id_now) =
16905                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16906            {
16907                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16908                if has_new_transaction {
16909                    _ = editor.update(cx, |editor, _| {
16910                        editor
16911                            .selection_history
16912                            .insert_transaction(transaction_id_now, selections_prev);
16913                    });
16914                }
16915            }
16916
16917            Ok(())
16918        })
16919    }
16920
16921    fn organize_imports(
16922        &mut self,
16923        _: &OrganizeImports,
16924        window: &mut Window,
16925        cx: &mut Context<Self>,
16926    ) -> Option<Task<Result<()>>> {
16927        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16928        let project = match &self.project {
16929            Some(project) => project.clone(),
16930            None => return None,
16931        };
16932        Some(self.perform_code_action_kind(
16933            project,
16934            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16935            window,
16936            cx,
16937        ))
16938    }
16939
16940    fn perform_code_action_kind(
16941        &mut self,
16942        project: Entity<Project>,
16943        kind: CodeActionKind,
16944        window: &mut Window,
16945        cx: &mut Context<Self>,
16946    ) -> Task<Result<()>> {
16947        let buffer = self.buffer.clone();
16948        let buffers = buffer.read(cx).all_buffers();
16949        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16950        let apply_action = project.update(cx, |project, cx| {
16951            project.apply_code_action_kind(buffers, kind, true, cx)
16952        });
16953        cx.spawn_in(window, async move |_, cx| {
16954            let transaction = futures::select_biased! {
16955                () = timeout => {
16956                    log::warn!("timed out waiting for executing code action");
16957                    None
16958                }
16959                transaction = apply_action.log_err().fuse() => transaction,
16960            };
16961            buffer
16962                .update(cx, |buffer, cx| {
16963                    // check if we need this
16964                    if let Some(transaction) = transaction
16965                        && !buffer.is_singleton()
16966                    {
16967                        buffer.push_transaction(&transaction.0, cx);
16968                    }
16969                    cx.notify();
16970                })
16971                .ok();
16972            Ok(())
16973        })
16974    }
16975
16976    pub fn restart_language_server(
16977        &mut self,
16978        _: &RestartLanguageServer,
16979        _: &mut Window,
16980        cx: &mut Context<Self>,
16981    ) {
16982        if let Some(project) = self.project.clone() {
16983            self.buffer.update(cx, |multi_buffer, cx| {
16984                project.update(cx, |project, cx| {
16985                    project.restart_language_servers_for_buffers(
16986                        multi_buffer.all_buffers().into_iter().collect(),
16987                        HashSet::default(),
16988                        cx,
16989                    );
16990                });
16991            })
16992        }
16993    }
16994
16995    pub fn stop_language_server(
16996        &mut self,
16997        _: &StopLanguageServer,
16998        _: &mut Window,
16999        cx: &mut Context<Self>,
17000    ) {
17001        if let Some(project) = self.project.clone() {
17002            self.buffer.update(cx, |multi_buffer, cx| {
17003                project.update(cx, |project, cx| {
17004                    project.stop_language_servers_for_buffers(
17005                        multi_buffer.all_buffers().into_iter().collect(),
17006                        HashSet::default(),
17007                        cx,
17008                    );
17009                    cx.emit(project::Event::RefreshInlayHints);
17010                });
17011            });
17012        }
17013    }
17014
17015    fn cancel_language_server_work(
17016        workspace: &mut Workspace,
17017        _: &actions::CancelLanguageServerWork,
17018        _: &mut Window,
17019        cx: &mut Context<Workspace>,
17020    ) {
17021        let project = workspace.project();
17022        let buffers = workspace
17023            .active_item(cx)
17024            .and_then(|item| item.act_as::<Editor>(cx))
17025            .map_or(HashSet::default(), |editor| {
17026                editor.read(cx).buffer.read(cx).all_buffers()
17027            });
17028        project.update(cx, |project, cx| {
17029            project.cancel_language_server_work_for_buffers(buffers, cx);
17030        });
17031    }
17032
17033    fn show_character_palette(
17034        &mut self,
17035        _: &ShowCharacterPalette,
17036        window: &mut Window,
17037        _: &mut Context<Self>,
17038    ) {
17039        window.show_character_palette();
17040    }
17041
17042    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17043        if !self.diagnostics_enabled() {
17044            return;
17045        }
17046
17047        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17048            let buffer = self.buffer.read(cx).snapshot(cx);
17049            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17050            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17051            let is_valid = buffer
17052                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17053                .any(|entry| {
17054                    entry.diagnostic.is_primary
17055                        && !entry.range.is_empty()
17056                        && entry.range.start == primary_range_start
17057                        && entry.diagnostic.message == active_diagnostics.active_message
17058                });
17059
17060            if !is_valid {
17061                self.dismiss_diagnostics(cx);
17062            }
17063        }
17064    }
17065
17066    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17067        match &self.active_diagnostics {
17068            ActiveDiagnostic::Group(group) => Some(group),
17069            _ => None,
17070        }
17071    }
17072
17073    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17074        if !self.diagnostics_enabled() {
17075            return;
17076        }
17077        self.dismiss_diagnostics(cx);
17078        self.active_diagnostics = ActiveDiagnostic::All;
17079    }
17080
17081    fn activate_diagnostics(
17082        &mut self,
17083        buffer_id: BufferId,
17084        diagnostic: DiagnosticEntry<usize>,
17085        window: &mut Window,
17086        cx: &mut Context<Self>,
17087    ) {
17088        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17089            return;
17090        }
17091        self.dismiss_diagnostics(cx);
17092        let snapshot = self.snapshot(window, cx);
17093        let buffer = self.buffer.read(cx).snapshot(cx);
17094        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17095            return;
17096        };
17097
17098        let diagnostic_group = buffer
17099            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17100            .collect::<Vec<_>>();
17101
17102        let blocks =
17103            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17104
17105        let blocks = self.display_map.update(cx, |display_map, cx| {
17106            display_map.insert_blocks(blocks, cx).into_iter().collect()
17107        });
17108        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17109            active_range: buffer.anchor_before(diagnostic.range.start)
17110                ..buffer.anchor_after(diagnostic.range.end),
17111            active_message: diagnostic.diagnostic.message.clone(),
17112            group_id: diagnostic.diagnostic.group_id,
17113            blocks,
17114        });
17115        cx.notify();
17116    }
17117
17118    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17119        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17120            return;
17121        };
17122
17123        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17124        if let ActiveDiagnostic::Group(group) = prev {
17125            self.display_map.update(cx, |display_map, cx| {
17126                display_map.remove_blocks(group.blocks, cx);
17127            });
17128            cx.notify();
17129        }
17130    }
17131
17132    /// Disable inline diagnostics rendering for this editor.
17133    pub fn disable_inline_diagnostics(&mut self) {
17134        self.inline_diagnostics_enabled = false;
17135        self.inline_diagnostics_update = Task::ready(());
17136        self.inline_diagnostics.clear();
17137    }
17138
17139    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17140        self.diagnostics_enabled = false;
17141        self.dismiss_diagnostics(cx);
17142        self.inline_diagnostics_update = Task::ready(());
17143        self.inline_diagnostics.clear();
17144    }
17145
17146    pub fn disable_word_completions(&mut self) {
17147        self.word_completions_enabled = false;
17148    }
17149
17150    pub fn diagnostics_enabled(&self) -> bool {
17151        self.diagnostics_enabled && self.mode.is_full()
17152    }
17153
17154    pub fn inline_diagnostics_enabled(&self) -> bool {
17155        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17156    }
17157
17158    pub fn show_inline_diagnostics(&self) -> bool {
17159        self.show_inline_diagnostics
17160    }
17161
17162    pub fn toggle_inline_diagnostics(
17163        &mut self,
17164        _: &ToggleInlineDiagnostics,
17165        window: &mut Window,
17166        cx: &mut Context<Editor>,
17167    ) {
17168        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17169        self.refresh_inline_diagnostics(false, window, cx);
17170    }
17171
17172    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17173        self.diagnostics_max_severity = severity;
17174        self.display_map.update(cx, |display_map, _| {
17175            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17176        });
17177    }
17178
17179    pub fn toggle_diagnostics(
17180        &mut self,
17181        _: &ToggleDiagnostics,
17182        window: &mut Window,
17183        cx: &mut Context<Editor>,
17184    ) {
17185        if !self.diagnostics_enabled() {
17186            return;
17187        }
17188
17189        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17190            EditorSettings::get_global(cx)
17191                .diagnostics_max_severity
17192                .filter(|severity| severity != &DiagnosticSeverity::Off)
17193                .unwrap_or(DiagnosticSeverity::Hint)
17194        } else {
17195            DiagnosticSeverity::Off
17196        };
17197        self.set_max_diagnostics_severity(new_severity, cx);
17198        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17199            self.active_diagnostics = ActiveDiagnostic::None;
17200            self.inline_diagnostics_update = Task::ready(());
17201            self.inline_diagnostics.clear();
17202        } else {
17203            self.refresh_inline_diagnostics(false, window, cx);
17204        }
17205
17206        cx.notify();
17207    }
17208
17209    pub fn toggle_minimap(
17210        &mut self,
17211        _: &ToggleMinimap,
17212        window: &mut Window,
17213        cx: &mut Context<Editor>,
17214    ) {
17215        if self.supports_minimap(cx) {
17216            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17217        }
17218    }
17219
17220    fn refresh_inline_diagnostics(
17221        &mut self,
17222        debounce: bool,
17223        window: &mut Window,
17224        cx: &mut Context<Self>,
17225    ) {
17226        let max_severity = ProjectSettings::get_global(cx)
17227            .diagnostics
17228            .inline
17229            .max_severity
17230            .unwrap_or(self.diagnostics_max_severity);
17231
17232        if !self.inline_diagnostics_enabled()
17233            || !self.show_inline_diagnostics
17234            || max_severity == DiagnosticSeverity::Off
17235        {
17236            self.inline_diagnostics_update = Task::ready(());
17237            self.inline_diagnostics.clear();
17238            return;
17239        }
17240
17241        let debounce_ms = ProjectSettings::get_global(cx)
17242            .diagnostics
17243            .inline
17244            .update_debounce_ms;
17245        let debounce = if debounce && debounce_ms > 0 {
17246            Some(Duration::from_millis(debounce_ms))
17247        } else {
17248            None
17249        };
17250        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17251            if let Some(debounce) = debounce {
17252                cx.background_executor().timer(debounce).await;
17253            }
17254            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17255                editor
17256                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17257                    .ok()
17258            }) else {
17259                return;
17260            };
17261
17262            let new_inline_diagnostics = cx
17263                .background_spawn(async move {
17264                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17265                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17266                        let message = diagnostic_entry
17267                            .diagnostic
17268                            .message
17269                            .split_once('\n')
17270                            .map(|(line, _)| line)
17271                            .map(SharedString::new)
17272                            .unwrap_or_else(|| {
17273                                SharedString::from(diagnostic_entry.diagnostic.message)
17274                            });
17275                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17276                        let (Ok(i) | Err(i)) = inline_diagnostics
17277                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17278                        inline_diagnostics.insert(
17279                            i,
17280                            (
17281                                start_anchor,
17282                                InlineDiagnostic {
17283                                    message,
17284                                    group_id: diagnostic_entry.diagnostic.group_id,
17285                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17286                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17287                                    severity: diagnostic_entry.diagnostic.severity,
17288                                },
17289                            ),
17290                        );
17291                    }
17292                    inline_diagnostics
17293                })
17294                .await;
17295
17296            editor
17297                .update(cx, |editor, cx| {
17298                    editor.inline_diagnostics = new_inline_diagnostics;
17299                    cx.notify();
17300                })
17301                .ok();
17302        });
17303    }
17304
17305    fn pull_diagnostics(
17306        &mut self,
17307        buffer_id: Option<BufferId>,
17308        window: &Window,
17309        cx: &mut Context<Self>,
17310    ) -> Option<()> {
17311        if !self.mode().is_full() {
17312            return None;
17313        }
17314        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17315            .diagnostics
17316            .lsp_pull_diagnostics;
17317        if !pull_diagnostics_settings.enabled {
17318            return None;
17319        }
17320        let project = self.project()?.downgrade();
17321        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17322        let mut buffers = self.buffer.read(cx).all_buffers();
17323        if let Some(buffer_id) = buffer_id {
17324            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17325        }
17326
17327        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17328            cx.background_executor().timer(debounce).await;
17329
17330            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17331                buffers
17332                    .into_iter()
17333                    .filter_map(|buffer| {
17334                        project
17335                            .update(cx, |project, cx| {
17336                                project.lsp_store().update(cx, |lsp_store, cx| {
17337                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17338                                })
17339                            })
17340                            .ok()
17341                    })
17342                    .collect::<FuturesUnordered<_>>()
17343            }) else {
17344                return;
17345            };
17346
17347            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17348                match pull_task {
17349                    Ok(()) => {
17350                        if editor
17351                            .update_in(cx, |editor, window, cx| {
17352                                editor.update_diagnostics_state(window, cx);
17353                            })
17354                            .is_err()
17355                        {
17356                            return;
17357                        }
17358                    }
17359                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17360                }
17361            }
17362        });
17363
17364        Some(())
17365    }
17366
17367    pub fn set_selections_from_remote(
17368        &mut self,
17369        selections: Vec<Selection<Anchor>>,
17370        pending_selection: Option<Selection<Anchor>>,
17371        window: &mut Window,
17372        cx: &mut Context<Self>,
17373    ) {
17374        let old_cursor_position = self.selections.newest_anchor().head();
17375        self.selections.change_with(cx, |s| {
17376            s.select_anchors(selections);
17377            if let Some(pending_selection) = pending_selection {
17378                s.set_pending(pending_selection, SelectMode::Character);
17379            } else {
17380                s.clear_pending();
17381            }
17382        });
17383        self.selections_did_change(
17384            false,
17385            &old_cursor_position,
17386            SelectionEffects::default(),
17387            window,
17388            cx,
17389        );
17390    }
17391
17392    pub fn transact(
17393        &mut self,
17394        window: &mut Window,
17395        cx: &mut Context<Self>,
17396        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17397    ) -> Option<TransactionId> {
17398        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17399            this.start_transaction_at(Instant::now(), window, cx);
17400            update(this, window, cx);
17401            this.end_transaction_at(Instant::now(), cx)
17402        })
17403    }
17404
17405    pub fn start_transaction_at(
17406        &mut self,
17407        now: Instant,
17408        window: &mut Window,
17409        cx: &mut Context<Self>,
17410    ) -> Option<TransactionId> {
17411        self.end_selection(window, cx);
17412        if let Some(tx_id) = self
17413            .buffer
17414            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17415        {
17416            self.selection_history
17417                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17418            cx.emit(EditorEvent::TransactionBegun {
17419                transaction_id: tx_id,
17420            });
17421            Some(tx_id)
17422        } else {
17423            None
17424        }
17425    }
17426
17427    pub fn end_transaction_at(
17428        &mut self,
17429        now: Instant,
17430        cx: &mut Context<Self>,
17431    ) -> Option<TransactionId> {
17432        if let Some(transaction_id) = self
17433            .buffer
17434            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17435        {
17436            if let Some((_, end_selections)) =
17437                self.selection_history.transaction_mut(transaction_id)
17438            {
17439                *end_selections = Some(self.selections.disjoint_anchors());
17440            } else {
17441                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17442            }
17443
17444            cx.emit(EditorEvent::Edited { transaction_id });
17445            Some(transaction_id)
17446        } else {
17447            None
17448        }
17449    }
17450
17451    pub fn modify_transaction_selection_history(
17452        &mut self,
17453        transaction_id: TransactionId,
17454        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17455    ) -> bool {
17456        self.selection_history
17457            .transaction_mut(transaction_id)
17458            .map(modify)
17459            .is_some()
17460    }
17461
17462    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17463        if self.selection_mark_mode {
17464            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17465                s.move_with(|_, sel| {
17466                    sel.collapse_to(sel.head(), SelectionGoal::None);
17467                });
17468            })
17469        }
17470        self.selection_mark_mode = true;
17471        cx.notify();
17472    }
17473
17474    pub fn swap_selection_ends(
17475        &mut self,
17476        _: &actions::SwapSelectionEnds,
17477        window: &mut Window,
17478        cx: &mut Context<Self>,
17479    ) {
17480        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17481            s.move_with(|_, sel| {
17482                if sel.start != sel.end {
17483                    sel.reversed = !sel.reversed
17484                }
17485            });
17486        });
17487        self.request_autoscroll(Autoscroll::newest(), cx);
17488        cx.notify();
17489    }
17490
17491    pub fn toggle_focus(
17492        workspace: &mut Workspace,
17493        _: &actions::ToggleFocus,
17494        window: &mut Window,
17495        cx: &mut Context<Workspace>,
17496    ) {
17497        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17498            return;
17499        };
17500        workspace.activate_item(&item, true, true, window, cx);
17501    }
17502
17503    pub fn toggle_fold(
17504        &mut self,
17505        _: &actions::ToggleFold,
17506        window: &mut Window,
17507        cx: &mut Context<Self>,
17508    ) {
17509        if self.is_singleton(cx) {
17510            let selection = self.selections.newest::<Point>(cx);
17511
17512            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17513            let range = if selection.is_empty() {
17514                let point = selection.head().to_display_point(&display_map);
17515                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17516                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17517                    .to_point(&display_map);
17518                start..end
17519            } else {
17520                selection.range()
17521            };
17522            if display_map.folds_in_range(range).next().is_some() {
17523                self.unfold_lines(&Default::default(), window, cx)
17524            } else {
17525                self.fold(&Default::default(), window, cx)
17526            }
17527        } else {
17528            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17529            let buffer_ids: HashSet<_> = self
17530                .selections
17531                .disjoint_anchor_ranges()
17532                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17533                .collect();
17534
17535            let should_unfold = buffer_ids
17536                .iter()
17537                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17538
17539            for buffer_id in buffer_ids {
17540                if should_unfold {
17541                    self.unfold_buffer(buffer_id, cx);
17542                } else {
17543                    self.fold_buffer(buffer_id, cx);
17544                }
17545            }
17546        }
17547    }
17548
17549    pub fn toggle_fold_recursive(
17550        &mut self,
17551        _: &actions::ToggleFoldRecursive,
17552        window: &mut Window,
17553        cx: &mut Context<Self>,
17554    ) {
17555        let selection = self.selections.newest::<Point>(cx);
17556
17557        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17558        let range = if selection.is_empty() {
17559            let point = selection.head().to_display_point(&display_map);
17560            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17561            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17562                .to_point(&display_map);
17563            start..end
17564        } else {
17565            selection.range()
17566        };
17567        if display_map.folds_in_range(range).next().is_some() {
17568            self.unfold_recursive(&Default::default(), window, cx)
17569        } else {
17570            self.fold_recursive(&Default::default(), window, cx)
17571        }
17572    }
17573
17574    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17575        if self.is_singleton(cx) {
17576            let mut to_fold = Vec::new();
17577            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17578            let selections = self.selections.all_adjusted(cx);
17579
17580            for selection in selections {
17581                let range = selection.range().sorted();
17582                let buffer_start_row = range.start.row;
17583
17584                if range.start.row != range.end.row {
17585                    let mut found = false;
17586                    let mut row = range.start.row;
17587                    while row <= range.end.row {
17588                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17589                        {
17590                            found = true;
17591                            row = crease.range().end.row + 1;
17592                            to_fold.push(crease);
17593                        } else {
17594                            row += 1
17595                        }
17596                    }
17597                    if found {
17598                        continue;
17599                    }
17600                }
17601
17602                for row in (0..=range.start.row).rev() {
17603                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17604                        && crease.range().end.row >= buffer_start_row
17605                    {
17606                        to_fold.push(crease);
17607                        if row <= range.start.row {
17608                            break;
17609                        }
17610                    }
17611                }
17612            }
17613
17614            self.fold_creases(to_fold, true, window, cx);
17615        } else {
17616            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17617            let buffer_ids = self
17618                .selections
17619                .disjoint_anchor_ranges()
17620                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17621                .collect::<HashSet<_>>();
17622            for buffer_id in buffer_ids {
17623                self.fold_buffer(buffer_id, cx);
17624            }
17625        }
17626    }
17627
17628    pub fn toggle_fold_all(
17629        &mut self,
17630        _: &actions::ToggleFoldAll,
17631        window: &mut Window,
17632        cx: &mut Context<Self>,
17633    ) {
17634        if self.buffer.read(cx).is_singleton() {
17635            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17636            let has_folds = display_map
17637                .folds_in_range(0..display_map.buffer_snapshot.len())
17638                .next()
17639                .is_some();
17640
17641            if has_folds {
17642                self.unfold_all(&actions::UnfoldAll, window, cx);
17643            } else {
17644                self.fold_all(&actions::FoldAll, window, cx);
17645            }
17646        } else {
17647            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17648            let should_unfold = buffer_ids
17649                .iter()
17650                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17651
17652            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17653                editor
17654                    .update_in(cx, |editor, _, cx| {
17655                        for buffer_id in buffer_ids {
17656                            if should_unfold {
17657                                editor.unfold_buffer(buffer_id, cx);
17658                            } else {
17659                                editor.fold_buffer(buffer_id, cx);
17660                            }
17661                        }
17662                    })
17663                    .ok();
17664            });
17665        }
17666    }
17667
17668    fn fold_at_level(
17669        &mut self,
17670        fold_at: &FoldAtLevel,
17671        window: &mut Window,
17672        cx: &mut Context<Self>,
17673    ) {
17674        if !self.buffer.read(cx).is_singleton() {
17675            return;
17676        }
17677
17678        let fold_at_level = fold_at.0;
17679        let snapshot = self.buffer.read(cx).snapshot(cx);
17680        let mut to_fold = Vec::new();
17681        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17682
17683        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17684            while start_row < end_row {
17685                match self
17686                    .snapshot(window, cx)
17687                    .crease_for_buffer_row(MultiBufferRow(start_row))
17688                {
17689                    Some(crease) => {
17690                        let nested_start_row = crease.range().start.row + 1;
17691                        let nested_end_row = crease.range().end.row;
17692
17693                        if current_level < fold_at_level {
17694                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17695                        } else if current_level == fold_at_level {
17696                            to_fold.push(crease);
17697                        }
17698
17699                        start_row = nested_end_row + 1;
17700                    }
17701                    None => start_row += 1,
17702                }
17703            }
17704        }
17705
17706        self.fold_creases(to_fold, true, window, cx);
17707    }
17708
17709    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17710        if self.buffer.read(cx).is_singleton() {
17711            let mut fold_ranges = Vec::new();
17712            let snapshot = self.buffer.read(cx).snapshot(cx);
17713
17714            for row in 0..snapshot.max_row().0 {
17715                if let Some(foldable_range) = self
17716                    .snapshot(window, cx)
17717                    .crease_for_buffer_row(MultiBufferRow(row))
17718                {
17719                    fold_ranges.push(foldable_range);
17720                }
17721            }
17722
17723            self.fold_creases(fold_ranges, true, window, cx);
17724        } else {
17725            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17726                editor
17727                    .update_in(cx, |editor, _, cx| {
17728                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17729                            editor.fold_buffer(buffer_id, cx);
17730                        }
17731                    })
17732                    .ok();
17733            });
17734        }
17735    }
17736
17737    pub fn fold_function_bodies(
17738        &mut self,
17739        _: &actions::FoldFunctionBodies,
17740        window: &mut Window,
17741        cx: &mut Context<Self>,
17742    ) {
17743        let snapshot = self.buffer.read(cx).snapshot(cx);
17744
17745        let ranges = snapshot
17746            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17747            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17748            .collect::<Vec<_>>();
17749
17750        let creases = ranges
17751            .into_iter()
17752            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17753            .collect();
17754
17755        self.fold_creases(creases, true, window, cx);
17756    }
17757
17758    pub fn fold_recursive(
17759        &mut self,
17760        _: &actions::FoldRecursive,
17761        window: &mut Window,
17762        cx: &mut Context<Self>,
17763    ) {
17764        let mut to_fold = Vec::new();
17765        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17766        let selections = self.selections.all_adjusted(cx);
17767
17768        for selection in selections {
17769            let range = selection.range().sorted();
17770            let buffer_start_row = range.start.row;
17771
17772            if range.start.row != range.end.row {
17773                let mut found = false;
17774                for row in range.start.row..=range.end.row {
17775                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17776                        found = true;
17777                        to_fold.push(crease);
17778                    }
17779                }
17780                if found {
17781                    continue;
17782                }
17783            }
17784
17785            for row in (0..=range.start.row).rev() {
17786                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17787                    if crease.range().end.row >= buffer_start_row {
17788                        to_fold.push(crease);
17789                    } else {
17790                        break;
17791                    }
17792                }
17793            }
17794        }
17795
17796        self.fold_creases(to_fold, true, window, cx);
17797    }
17798
17799    pub fn fold_at(
17800        &mut self,
17801        buffer_row: MultiBufferRow,
17802        window: &mut Window,
17803        cx: &mut Context<Self>,
17804    ) {
17805        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17806
17807        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17808            let autoscroll = self
17809                .selections
17810                .all::<Point>(cx)
17811                .iter()
17812                .any(|selection| crease.range().overlaps(&selection.range()));
17813
17814            self.fold_creases(vec![crease], autoscroll, window, cx);
17815        }
17816    }
17817
17818    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17819        if self.is_singleton(cx) {
17820            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17821            let buffer = &display_map.buffer_snapshot;
17822            let selections = self.selections.all::<Point>(cx);
17823            let ranges = selections
17824                .iter()
17825                .map(|s| {
17826                    let range = s.display_range(&display_map).sorted();
17827                    let mut start = range.start.to_point(&display_map);
17828                    let mut end = range.end.to_point(&display_map);
17829                    start.column = 0;
17830                    end.column = buffer.line_len(MultiBufferRow(end.row));
17831                    start..end
17832                })
17833                .collect::<Vec<_>>();
17834
17835            self.unfold_ranges(&ranges, true, true, cx);
17836        } else {
17837            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17838            let buffer_ids = self
17839                .selections
17840                .disjoint_anchor_ranges()
17841                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17842                .collect::<HashSet<_>>();
17843            for buffer_id in buffer_ids {
17844                self.unfold_buffer(buffer_id, cx);
17845            }
17846        }
17847    }
17848
17849    pub fn unfold_recursive(
17850        &mut self,
17851        _: &UnfoldRecursive,
17852        _window: &mut Window,
17853        cx: &mut Context<Self>,
17854    ) {
17855        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17856        let selections = self.selections.all::<Point>(cx);
17857        let ranges = selections
17858            .iter()
17859            .map(|s| {
17860                let mut range = s.display_range(&display_map).sorted();
17861                *range.start.column_mut() = 0;
17862                *range.end.column_mut() = display_map.line_len(range.end.row());
17863                let start = range.start.to_point(&display_map);
17864                let end = range.end.to_point(&display_map);
17865                start..end
17866            })
17867            .collect::<Vec<_>>();
17868
17869        self.unfold_ranges(&ranges, true, true, cx);
17870    }
17871
17872    pub fn unfold_at(
17873        &mut self,
17874        buffer_row: MultiBufferRow,
17875        _window: &mut Window,
17876        cx: &mut Context<Self>,
17877    ) {
17878        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17879
17880        let intersection_range = Point::new(buffer_row.0, 0)
17881            ..Point::new(
17882                buffer_row.0,
17883                display_map.buffer_snapshot.line_len(buffer_row),
17884            );
17885
17886        let autoscroll = self
17887            .selections
17888            .all::<Point>(cx)
17889            .iter()
17890            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17891
17892        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17893    }
17894
17895    pub fn unfold_all(
17896        &mut self,
17897        _: &actions::UnfoldAll,
17898        _window: &mut Window,
17899        cx: &mut Context<Self>,
17900    ) {
17901        if self.buffer.read(cx).is_singleton() {
17902            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17903            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17904        } else {
17905            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17906                editor
17907                    .update(cx, |editor, cx| {
17908                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17909                            editor.unfold_buffer(buffer_id, cx);
17910                        }
17911                    })
17912                    .ok();
17913            });
17914        }
17915    }
17916
17917    pub fn fold_selected_ranges(
17918        &mut self,
17919        _: &FoldSelectedRanges,
17920        window: &mut Window,
17921        cx: &mut Context<Self>,
17922    ) {
17923        let selections = self.selections.all_adjusted(cx);
17924        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17925        let ranges = selections
17926            .into_iter()
17927            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17928            .collect::<Vec<_>>();
17929        self.fold_creases(ranges, true, window, cx);
17930    }
17931
17932    pub fn fold_ranges<T: ToOffset + Clone>(
17933        &mut self,
17934        ranges: Vec<Range<T>>,
17935        auto_scroll: bool,
17936        window: &mut Window,
17937        cx: &mut Context<Self>,
17938    ) {
17939        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17940        let ranges = ranges
17941            .into_iter()
17942            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17943            .collect::<Vec<_>>();
17944        self.fold_creases(ranges, auto_scroll, window, cx);
17945    }
17946
17947    pub fn fold_creases<T: ToOffset + Clone>(
17948        &mut self,
17949        creases: Vec<Crease<T>>,
17950        auto_scroll: bool,
17951        _window: &mut Window,
17952        cx: &mut Context<Self>,
17953    ) {
17954        if creases.is_empty() {
17955            return;
17956        }
17957
17958        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17959
17960        if auto_scroll {
17961            self.request_autoscroll(Autoscroll::fit(), cx);
17962        }
17963
17964        cx.notify();
17965
17966        self.scrollbar_marker_state.dirty = true;
17967        self.folds_did_change(cx);
17968    }
17969
17970    /// Removes any folds whose ranges intersect any of the given ranges.
17971    pub fn unfold_ranges<T: ToOffset + Clone>(
17972        &mut self,
17973        ranges: &[Range<T>],
17974        inclusive: bool,
17975        auto_scroll: bool,
17976        cx: &mut Context<Self>,
17977    ) {
17978        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17979            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17980        });
17981        self.folds_did_change(cx);
17982    }
17983
17984    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17985        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17986            return;
17987        }
17988        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17989        self.display_map.update(cx, |display_map, cx| {
17990            display_map.fold_buffers([buffer_id], cx)
17991        });
17992        cx.emit(EditorEvent::BufferFoldToggled {
17993            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17994            folded: true,
17995        });
17996        cx.notify();
17997    }
17998
17999    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18000        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18001            return;
18002        }
18003        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18004        self.display_map.update(cx, |display_map, cx| {
18005            display_map.unfold_buffers([buffer_id], cx);
18006        });
18007        cx.emit(EditorEvent::BufferFoldToggled {
18008            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18009            folded: false,
18010        });
18011        cx.notify();
18012    }
18013
18014    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18015        self.display_map.read(cx).is_buffer_folded(buffer)
18016    }
18017
18018    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18019        self.display_map.read(cx).folded_buffers()
18020    }
18021
18022    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18023        self.display_map.update(cx, |display_map, cx| {
18024            display_map.disable_header_for_buffer(buffer_id, cx);
18025        });
18026        cx.notify();
18027    }
18028
18029    /// Removes any folds with the given ranges.
18030    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18031        &mut self,
18032        ranges: &[Range<T>],
18033        type_id: TypeId,
18034        auto_scroll: bool,
18035        cx: &mut Context<Self>,
18036    ) {
18037        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18038            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18039        });
18040        self.folds_did_change(cx);
18041    }
18042
18043    fn remove_folds_with<T: ToOffset + Clone>(
18044        &mut self,
18045        ranges: &[Range<T>],
18046        auto_scroll: bool,
18047        cx: &mut Context<Self>,
18048        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18049    ) {
18050        if ranges.is_empty() {
18051            return;
18052        }
18053
18054        let mut buffers_affected = HashSet::default();
18055        let multi_buffer = self.buffer().read(cx);
18056        for range in ranges {
18057            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18058                buffers_affected.insert(buffer.read(cx).remote_id());
18059            };
18060        }
18061
18062        self.display_map.update(cx, update);
18063
18064        if auto_scroll {
18065            self.request_autoscroll(Autoscroll::fit(), cx);
18066        }
18067
18068        cx.notify();
18069        self.scrollbar_marker_state.dirty = true;
18070        self.active_indent_guides_state.dirty = true;
18071    }
18072
18073    pub fn update_renderer_widths(
18074        &mut self,
18075        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18076        cx: &mut Context<Self>,
18077    ) -> bool {
18078        self.display_map
18079            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18080    }
18081
18082    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18083        self.display_map.read(cx).fold_placeholder.clone()
18084    }
18085
18086    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18087        self.buffer.update(cx, |buffer, cx| {
18088            buffer.set_all_diff_hunks_expanded(cx);
18089        });
18090    }
18091
18092    pub fn expand_all_diff_hunks(
18093        &mut self,
18094        _: &ExpandAllDiffHunks,
18095        _window: &mut Window,
18096        cx: &mut Context<Self>,
18097    ) {
18098        self.buffer.update(cx, |buffer, cx| {
18099            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18100        });
18101    }
18102
18103    pub fn toggle_selected_diff_hunks(
18104        &mut self,
18105        _: &ToggleSelectedDiffHunks,
18106        _window: &mut Window,
18107        cx: &mut Context<Self>,
18108    ) {
18109        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18110        self.toggle_diff_hunks_in_ranges(ranges, cx);
18111    }
18112
18113    pub fn diff_hunks_in_ranges<'a>(
18114        &'a self,
18115        ranges: &'a [Range<Anchor>],
18116        buffer: &'a MultiBufferSnapshot,
18117    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18118        ranges.iter().flat_map(move |range| {
18119            let end_excerpt_id = range.end.excerpt_id;
18120            let range = range.to_point(buffer);
18121            let mut peek_end = range.end;
18122            if range.end.row < buffer.max_row().0 {
18123                peek_end = Point::new(range.end.row + 1, 0);
18124            }
18125            buffer
18126                .diff_hunks_in_range(range.start..peek_end)
18127                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18128        })
18129    }
18130
18131    pub fn has_stageable_diff_hunks_in_ranges(
18132        &self,
18133        ranges: &[Range<Anchor>],
18134        snapshot: &MultiBufferSnapshot,
18135    ) -> bool {
18136        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18137        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18138    }
18139
18140    pub fn toggle_staged_selected_diff_hunks(
18141        &mut self,
18142        _: &::git::ToggleStaged,
18143        _: &mut Window,
18144        cx: &mut Context<Self>,
18145    ) {
18146        let snapshot = self.buffer.read(cx).snapshot(cx);
18147        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18148        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18149        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18150    }
18151
18152    pub fn set_render_diff_hunk_controls(
18153        &mut self,
18154        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18155        cx: &mut Context<Self>,
18156    ) {
18157        self.render_diff_hunk_controls = render_diff_hunk_controls;
18158        cx.notify();
18159    }
18160
18161    pub fn stage_and_next(
18162        &mut self,
18163        _: &::git::StageAndNext,
18164        window: &mut Window,
18165        cx: &mut Context<Self>,
18166    ) {
18167        self.do_stage_or_unstage_and_next(true, window, cx);
18168    }
18169
18170    pub fn unstage_and_next(
18171        &mut self,
18172        _: &::git::UnstageAndNext,
18173        window: &mut Window,
18174        cx: &mut Context<Self>,
18175    ) {
18176        self.do_stage_or_unstage_and_next(false, window, cx);
18177    }
18178
18179    pub fn stage_or_unstage_diff_hunks(
18180        &mut self,
18181        stage: bool,
18182        ranges: Vec<Range<Anchor>>,
18183        cx: &mut Context<Self>,
18184    ) {
18185        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18186        cx.spawn(async move |this, cx| {
18187            task.await?;
18188            this.update(cx, |this, cx| {
18189                let snapshot = this.buffer.read(cx).snapshot(cx);
18190                let chunk_by = this
18191                    .diff_hunks_in_ranges(&ranges, &snapshot)
18192                    .chunk_by(|hunk| hunk.buffer_id);
18193                for (buffer_id, hunks) in &chunk_by {
18194                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18195                }
18196            })
18197        })
18198        .detach_and_log_err(cx);
18199    }
18200
18201    fn save_buffers_for_ranges_if_needed(
18202        &mut self,
18203        ranges: &[Range<Anchor>],
18204        cx: &mut Context<Editor>,
18205    ) -> Task<Result<()>> {
18206        let multibuffer = self.buffer.read(cx);
18207        let snapshot = multibuffer.read(cx);
18208        let buffer_ids: HashSet<_> = ranges
18209            .iter()
18210            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18211            .collect();
18212        drop(snapshot);
18213
18214        let mut buffers = HashSet::default();
18215        for buffer_id in buffer_ids {
18216            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18217                let buffer = buffer_entity.read(cx);
18218                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18219                {
18220                    buffers.insert(buffer_entity);
18221                }
18222            }
18223        }
18224
18225        if let Some(project) = &self.project {
18226            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18227        } else {
18228            Task::ready(Ok(()))
18229        }
18230    }
18231
18232    fn do_stage_or_unstage_and_next(
18233        &mut self,
18234        stage: bool,
18235        window: &mut Window,
18236        cx: &mut Context<Self>,
18237    ) {
18238        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18239
18240        if ranges.iter().any(|range| range.start != range.end) {
18241            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18242            return;
18243        }
18244
18245        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18246        let snapshot = self.snapshot(window, cx);
18247        let position = self.selections.newest::<Point>(cx).head();
18248        let mut row = snapshot
18249            .buffer_snapshot
18250            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18251            .find(|hunk| hunk.row_range.start.0 > position.row)
18252            .map(|hunk| hunk.row_range.start);
18253
18254        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18255        // Outside of the project diff editor, wrap around to the beginning.
18256        if !all_diff_hunks_expanded {
18257            row = row.or_else(|| {
18258                snapshot
18259                    .buffer_snapshot
18260                    .diff_hunks_in_range(Point::zero()..position)
18261                    .find(|hunk| hunk.row_range.end.0 < position.row)
18262                    .map(|hunk| hunk.row_range.start)
18263            });
18264        }
18265
18266        if let Some(row) = row {
18267            let destination = Point::new(row.0, 0);
18268            let autoscroll = Autoscroll::center();
18269
18270            self.unfold_ranges(&[destination..destination], false, false, cx);
18271            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18272                s.select_ranges([destination..destination]);
18273            });
18274        }
18275    }
18276
18277    fn do_stage_or_unstage(
18278        &self,
18279        stage: bool,
18280        buffer_id: BufferId,
18281        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18282        cx: &mut App,
18283    ) -> Option<()> {
18284        let project = self.project()?;
18285        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18286        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18287        let buffer_snapshot = buffer.read(cx).snapshot();
18288        let file_exists = buffer_snapshot
18289            .file()
18290            .is_some_and(|file| file.disk_state().exists());
18291        diff.update(cx, |diff, cx| {
18292            diff.stage_or_unstage_hunks(
18293                stage,
18294                &hunks
18295                    .map(|hunk| buffer_diff::DiffHunk {
18296                        buffer_range: hunk.buffer_range,
18297                        diff_base_byte_range: hunk.diff_base_byte_range,
18298                        secondary_status: hunk.secondary_status,
18299                        range: Point::zero()..Point::zero(), // unused
18300                    })
18301                    .collect::<Vec<_>>(),
18302                &buffer_snapshot,
18303                file_exists,
18304                cx,
18305            )
18306        });
18307        None
18308    }
18309
18310    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18311        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18312        self.buffer
18313            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18314    }
18315
18316    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18317        self.buffer.update(cx, |buffer, cx| {
18318            let ranges = vec![Anchor::min()..Anchor::max()];
18319            if !buffer.all_diff_hunks_expanded()
18320                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18321            {
18322                buffer.collapse_diff_hunks(ranges, cx);
18323                true
18324            } else {
18325                false
18326            }
18327        })
18328    }
18329
18330    fn toggle_diff_hunks_in_ranges(
18331        &mut self,
18332        ranges: Vec<Range<Anchor>>,
18333        cx: &mut Context<Editor>,
18334    ) {
18335        self.buffer.update(cx, |buffer, cx| {
18336            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18337            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18338        })
18339    }
18340
18341    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18342        self.buffer.update(cx, |buffer, cx| {
18343            let snapshot = buffer.snapshot(cx);
18344            let excerpt_id = range.end.excerpt_id;
18345            let point_range = range.to_point(&snapshot);
18346            let expand = !buffer.single_hunk_is_expanded(range, cx);
18347            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18348        })
18349    }
18350
18351    pub(crate) fn apply_all_diff_hunks(
18352        &mut self,
18353        _: &ApplyAllDiffHunks,
18354        window: &mut Window,
18355        cx: &mut Context<Self>,
18356    ) {
18357        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18358
18359        let buffers = self.buffer.read(cx).all_buffers();
18360        for branch_buffer in buffers {
18361            branch_buffer.update(cx, |branch_buffer, cx| {
18362                branch_buffer.merge_into_base(Vec::new(), cx);
18363            });
18364        }
18365
18366        if let Some(project) = self.project.clone() {
18367            self.save(
18368                SaveOptions {
18369                    format: true,
18370                    autosave: false,
18371                },
18372                project,
18373                window,
18374                cx,
18375            )
18376            .detach_and_log_err(cx);
18377        }
18378    }
18379
18380    pub(crate) fn apply_selected_diff_hunks(
18381        &mut self,
18382        _: &ApplyDiffHunk,
18383        window: &mut Window,
18384        cx: &mut Context<Self>,
18385    ) {
18386        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18387        let snapshot = self.snapshot(window, cx);
18388        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18389        let mut ranges_by_buffer = HashMap::default();
18390        self.transact(window, cx, |editor, _window, cx| {
18391            for hunk in hunks {
18392                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18393                    ranges_by_buffer
18394                        .entry(buffer.clone())
18395                        .or_insert_with(Vec::new)
18396                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18397                }
18398            }
18399
18400            for (buffer, ranges) in ranges_by_buffer {
18401                buffer.update(cx, |buffer, cx| {
18402                    buffer.merge_into_base(ranges, cx);
18403                });
18404            }
18405        });
18406
18407        if let Some(project) = self.project.clone() {
18408            self.save(
18409                SaveOptions {
18410                    format: true,
18411                    autosave: false,
18412                },
18413                project,
18414                window,
18415                cx,
18416            )
18417            .detach_and_log_err(cx);
18418        }
18419    }
18420
18421    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18422        if hovered != self.gutter_hovered {
18423            self.gutter_hovered = hovered;
18424            cx.notify();
18425        }
18426    }
18427
18428    pub fn insert_blocks(
18429        &mut self,
18430        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18431        autoscroll: Option<Autoscroll>,
18432        cx: &mut Context<Self>,
18433    ) -> Vec<CustomBlockId> {
18434        let blocks = self
18435            .display_map
18436            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18437        if let Some(autoscroll) = autoscroll {
18438            self.request_autoscroll(autoscroll, cx);
18439        }
18440        cx.notify();
18441        blocks
18442    }
18443
18444    pub fn resize_blocks(
18445        &mut self,
18446        heights: HashMap<CustomBlockId, u32>,
18447        autoscroll: Option<Autoscroll>,
18448        cx: &mut Context<Self>,
18449    ) {
18450        self.display_map
18451            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18452        if let Some(autoscroll) = autoscroll {
18453            self.request_autoscroll(autoscroll, cx);
18454        }
18455        cx.notify();
18456    }
18457
18458    pub fn replace_blocks(
18459        &mut self,
18460        renderers: HashMap<CustomBlockId, RenderBlock>,
18461        autoscroll: Option<Autoscroll>,
18462        cx: &mut Context<Self>,
18463    ) {
18464        self.display_map
18465            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18466        if let Some(autoscroll) = autoscroll {
18467            self.request_autoscroll(autoscroll, cx);
18468        }
18469        cx.notify();
18470    }
18471
18472    pub fn remove_blocks(
18473        &mut self,
18474        block_ids: HashSet<CustomBlockId>,
18475        autoscroll: Option<Autoscroll>,
18476        cx: &mut Context<Self>,
18477    ) {
18478        self.display_map.update(cx, |display_map, cx| {
18479            display_map.remove_blocks(block_ids, cx)
18480        });
18481        if let Some(autoscroll) = autoscroll {
18482            self.request_autoscroll(autoscroll, cx);
18483        }
18484        cx.notify();
18485    }
18486
18487    pub fn row_for_block(
18488        &self,
18489        block_id: CustomBlockId,
18490        cx: &mut Context<Self>,
18491    ) -> Option<DisplayRow> {
18492        self.display_map
18493            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18494    }
18495
18496    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18497        self.focused_block = Some(focused_block);
18498    }
18499
18500    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18501        self.focused_block.take()
18502    }
18503
18504    pub fn insert_creases(
18505        &mut self,
18506        creases: impl IntoIterator<Item = Crease<Anchor>>,
18507        cx: &mut Context<Self>,
18508    ) -> Vec<CreaseId> {
18509        self.display_map
18510            .update(cx, |map, cx| map.insert_creases(creases, cx))
18511    }
18512
18513    pub fn remove_creases(
18514        &mut self,
18515        ids: impl IntoIterator<Item = CreaseId>,
18516        cx: &mut Context<Self>,
18517    ) -> Vec<(CreaseId, Range<Anchor>)> {
18518        self.display_map
18519            .update(cx, |map, cx| map.remove_creases(ids, cx))
18520    }
18521
18522    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18523        self.display_map
18524            .update(cx, |map, cx| map.snapshot(cx))
18525            .longest_row()
18526    }
18527
18528    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18529        self.display_map
18530            .update(cx, |map, cx| map.snapshot(cx))
18531            .max_point()
18532    }
18533
18534    pub fn text(&self, cx: &App) -> String {
18535        self.buffer.read(cx).read(cx).text()
18536    }
18537
18538    pub fn is_empty(&self, cx: &App) -> bool {
18539        self.buffer.read(cx).read(cx).is_empty()
18540    }
18541
18542    pub fn text_option(&self, cx: &App) -> Option<String> {
18543        let text = self.text(cx);
18544        let text = text.trim();
18545
18546        if text.is_empty() {
18547            return None;
18548        }
18549
18550        Some(text.to_string())
18551    }
18552
18553    pub fn set_text(
18554        &mut self,
18555        text: impl Into<Arc<str>>,
18556        window: &mut Window,
18557        cx: &mut Context<Self>,
18558    ) {
18559        self.transact(window, cx, |this, _, cx| {
18560            this.buffer
18561                .read(cx)
18562                .as_singleton()
18563                .expect("you can only call set_text on editors for singleton buffers")
18564                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18565        });
18566    }
18567
18568    pub fn display_text(&self, cx: &mut App) -> String {
18569        self.display_map
18570            .update(cx, |map, cx| map.snapshot(cx))
18571            .text()
18572    }
18573
18574    fn create_minimap(
18575        &self,
18576        minimap_settings: MinimapSettings,
18577        window: &mut Window,
18578        cx: &mut Context<Self>,
18579    ) -> Option<Entity<Self>> {
18580        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18581            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18582    }
18583
18584    fn initialize_new_minimap(
18585        &self,
18586        minimap_settings: MinimapSettings,
18587        window: &mut Window,
18588        cx: &mut Context<Self>,
18589    ) -> Entity<Self> {
18590        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18591
18592        let mut minimap = Editor::new_internal(
18593            EditorMode::Minimap {
18594                parent: cx.weak_entity(),
18595            },
18596            self.buffer.clone(),
18597            None,
18598            Some(self.display_map.clone()),
18599            window,
18600            cx,
18601        );
18602        minimap.scroll_manager.clone_state(&self.scroll_manager);
18603        minimap.set_text_style_refinement(TextStyleRefinement {
18604            font_size: Some(MINIMAP_FONT_SIZE),
18605            font_weight: Some(MINIMAP_FONT_WEIGHT),
18606            ..Default::default()
18607        });
18608        minimap.update_minimap_configuration(minimap_settings, cx);
18609        cx.new(|_| minimap)
18610    }
18611
18612    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18613        let current_line_highlight = minimap_settings
18614            .current_line_highlight
18615            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18616        self.set_current_line_highlight(Some(current_line_highlight));
18617    }
18618
18619    pub fn minimap(&self) -> Option<&Entity<Self>> {
18620        self.minimap
18621            .as_ref()
18622            .filter(|_| self.minimap_visibility.visible())
18623    }
18624
18625    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18626        let mut wrap_guides = smallvec![];
18627
18628        if self.show_wrap_guides == Some(false) {
18629            return wrap_guides;
18630        }
18631
18632        let settings = self.buffer.read(cx).language_settings(cx);
18633        if settings.show_wrap_guides {
18634            match self.soft_wrap_mode(cx) {
18635                SoftWrap::Column(soft_wrap) => {
18636                    wrap_guides.push((soft_wrap as usize, true));
18637                }
18638                SoftWrap::Bounded(soft_wrap) => {
18639                    wrap_guides.push((soft_wrap as usize, true));
18640                }
18641                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18642            }
18643            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18644        }
18645
18646        wrap_guides
18647    }
18648
18649    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18650        let settings = self.buffer.read(cx).language_settings(cx);
18651        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18652        match mode {
18653            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18654                SoftWrap::None
18655            }
18656            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18657            language_settings::SoftWrap::PreferredLineLength => {
18658                SoftWrap::Column(settings.preferred_line_length)
18659            }
18660            language_settings::SoftWrap::Bounded => {
18661                SoftWrap::Bounded(settings.preferred_line_length)
18662            }
18663        }
18664    }
18665
18666    pub fn set_soft_wrap_mode(
18667        &mut self,
18668        mode: language_settings::SoftWrap,
18669
18670        cx: &mut Context<Self>,
18671    ) {
18672        self.soft_wrap_mode_override = Some(mode);
18673        cx.notify();
18674    }
18675
18676    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18677        self.hard_wrap = hard_wrap;
18678        cx.notify();
18679    }
18680
18681    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18682        self.text_style_refinement = Some(style);
18683    }
18684
18685    /// called by the Element so we know what style we were most recently rendered with.
18686    pub(crate) fn set_style(
18687        &mut self,
18688        style: EditorStyle,
18689        window: &mut Window,
18690        cx: &mut Context<Self>,
18691    ) {
18692        // We intentionally do not inform the display map about the minimap style
18693        // so that wrapping is not recalculated and stays consistent for the editor
18694        // and its linked minimap.
18695        if !self.mode.is_minimap() {
18696            let rem_size = window.rem_size();
18697            self.display_map.update(cx, |map, cx| {
18698                map.set_font(
18699                    style.text.font(),
18700                    style.text.font_size.to_pixels(rem_size),
18701                    cx,
18702                )
18703            });
18704        }
18705        self.style = Some(style);
18706    }
18707
18708    pub fn style(&self) -> Option<&EditorStyle> {
18709        self.style.as_ref()
18710    }
18711
18712    // Called by the element. This method is not designed to be called outside of the editor
18713    // element's layout code because it does not notify when rewrapping is computed synchronously.
18714    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18715        self.display_map
18716            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18717    }
18718
18719    pub fn set_soft_wrap(&mut self) {
18720        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18721    }
18722
18723    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18724        if self.soft_wrap_mode_override.is_some() {
18725            self.soft_wrap_mode_override.take();
18726        } else {
18727            let soft_wrap = match self.soft_wrap_mode(cx) {
18728                SoftWrap::GitDiff => return,
18729                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18730                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18731                    language_settings::SoftWrap::None
18732                }
18733            };
18734            self.soft_wrap_mode_override = Some(soft_wrap);
18735        }
18736        cx.notify();
18737    }
18738
18739    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18740        let Some(workspace) = self.workspace() else {
18741            return;
18742        };
18743        let fs = workspace.read(cx).app_state().fs.clone();
18744        let current_show = TabBarSettings::get_global(cx).show;
18745        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18746            setting.show = Some(!current_show);
18747        });
18748    }
18749
18750    pub fn toggle_indent_guides(
18751        &mut self,
18752        _: &ToggleIndentGuides,
18753        _: &mut Window,
18754        cx: &mut Context<Self>,
18755    ) {
18756        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18757            self.buffer
18758                .read(cx)
18759                .language_settings(cx)
18760                .indent_guides
18761                .enabled
18762        });
18763        self.show_indent_guides = Some(!currently_enabled);
18764        cx.notify();
18765    }
18766
18767    fn should_show_indent_guides(&self) -> Option<bool> {
18768        self.show_indent_guides
18769    }
18770
18771    pub fn toggle_line_numbers(
18772        &mut self,
18773        _: &ToggleLineNumbers,
18774        _: &mut Window,
18775        cx: &mut Context<Self>,
18776    ) {
18777        let mut editor_settings = EditorSettings::get_global(cx).clone();
18778        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18779        EditorSettings::override_global(editor_settings, cx);
18780    }
18781
18782    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18783        if let Some(show_line_numbers) = self.show_line_numbers {
18784            return show_line_numbers;
18785        }
18786        EditorSettings::get_global(cx).gutter.line_numbers
18787    }
18788
18789    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18790        self.use_relative_line_numbers
18791            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18792    }
18793
18794    pub fn toggle_relative_line_numbers(
18795        &mut self,
18796        _: &ToggleRelativeLineNumbers,
18797        _: &mut Window,
18798        cx: &mut Context<Self>,
18799    ) {
18800        let is_relative = self.should_use_relative_line_numbers(cx);
18801        self.set_relative_line_number(Some(!is_relative), cx)
18802    }
18803
18804    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18805        self.use_relative_line_numbers = is_relative;
18806        cx.notify();
18807    }
18808
18809    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18810        self.show_gutter = show_gutter;
18811        cx.notify();
18812    }
18813
18814    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18815        self.show_scrollbars = ScrollbarAxes {
18816            horizontal: show,
18817            vertical: show,
18818        };
18819        cx.notify();
18820    }
18821
18822    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18823        self.show_scrollbars.vertical = show;
18824        cx.notify();
18825    }
18826
18827    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18828        self.show_scrollbars.horizontal = show;
18829        cx.notify();
18830    }
18831
18832    pub fn set_minimap_visibility(
18833        &mut self,
18834        minimap_visibility: MinimapVisibility,
18835        window: &mut Window,
18836        cx: &mut Context<Self>,
18837    ) {
18838        if self.minimap_visibility != minimap_visibility {
18839            if minimap_visibility.visible() && self.minimap.is_none() {
18840                let minimap_settings = EditorSettings::get_global(cx).minimap;
18841                self.minimap =
18842                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18843            }
18844            self.minimap_visibility = minimap_visibility;
18845            cx.notify();
18846        }
18847    }
18848
18849    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18850        self.set_show_scrollbars(false, cx);
18851        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18852    }
18853
18854    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18855        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18856    }
18857
18858    /// Normally the text in full mode and auto height editors is padded on the
18859    /// left side by roughly half a character width for improved hit testing.
18860    ///
18861    /// Use this method to disable this for cases where this is not wanted (e.g.
18862    /// if you want to align the editor text with some other text above or below)
18863    /// or if you want to add this padding to single-line editors.
18864    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18865        self.offset_content = offset_content;
18866        cx.notify();
18867    }
18868
18869    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18870        self.show_line_numbers = Some(show_line_numbers);
18871        cx.notify();
18872    }
18873
18874    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18875        self.disable_expand_excerpt_buttons = true;
18876        cx.notify();
18877    }
18878
18879    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18880        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18881        cx.notify();
18882    }
18883
18884    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18885        self.show_code_actions = Some(show_code_actions);
18886        cx.notify();
18887    }
18888
18889    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18890        self.show_runnables = Some(show_runnables);
18891        cx.notify();
18892    }
18893
18894    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18895        self.show_breakpoints = Some(show_breakpoints);
18896        cx.notify();
18897    }
18898
18899    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18900        if self.display_map.read(cx).masked != masked {
18901            self.display_map.update(cx, |map, _| map.masked = masked);
18902        }
18903        cx.notify()
18904    }
18905
18906    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18907        self.show_wrap_guides = Some(show_wrap_guides);
18908        cx.notify();
18909    }
18910
18911    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18912        self.show_indent_guides = Some(show_indent_guides);
18913        cx.notify();
18914    }
18915
18916    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18917        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18918            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18919                && let Some(dir) = file.abs_path(cx).parent()
18920            {
18921                return Some(dir.to_owned());
18922            }
18923
18924            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18925                return Some(project_path.path.to_path_buf());
18926            }
18927        }
18928
18929        None
18930    }
18931
18932    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18933        self.active_excerpt(cx)?
18934            .1
18935            .read(cx)
18936            .file()
18937            .and_then(|f| f.as_local())
18938    }
18939
18940    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18941        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18942            let buffer = buffer.read(cx);
18943            if let Some(project_path) = buffer.project_path(cx) {
18944                let project = self.project()?.read(cx);
18945                project.absolute_path(&project_path, cx)
18946            } else {
18947                buffer
18948                    .file()
18949                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18950            }
18951        })
18952    }
18953
18954    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18955        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18956            let project_path = buffer.read(cx).project_path(cx)?;
18957            let project = self.project()?.read(cx);
18958            let entry = project.entry_for_path(&project_path, cx)?;
18959            let path = entry.path.to_path_buf();
18960            Some(path)
18961        })
18962    }
18963
18964    pub fn reveal_in_finder(
18965        &mut self,
18966        _: &RevealInFileManager,
18967        _window: &mut Window,
18968        cx: &mut Context<Self>,
18969    ) {
18970        if let Some(target) = self.target_file(cx) {
18971            cx.reveal_path(&target.abs_path(cx));
18972        }
18973    }
18974
18975    pub fn copy_path(
18976        &mut self,
18977        _: &zed_actions::workspace::CopyPath,
18978        _window: &mut Window,
18979        cx: &mut Context<Self>,
18980    ) {
18981        if let Some(path) = self.target_file_abs_path(cx)
18982            && let Some(path) = path.to_str()
18983        {
18984            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18985        }
18986    }
18987
18988    pub fn copy_relative_path(
18989        &mut self,
18990        _: &zed_actions::workspace::CopyRelativePath,
18991        _window: &mut Window,
18992        cx: &mut Context<Self>,
18993    ) {
18994        if let Some(path) = self.target_file_path(cx)
18995            && let Some(path) = path.to_str()
18996        {
18997            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18998        }
18999    }
19000
19001    /// Returns the project path for the editor's buffer, if any buffer is
19002    /// opened in the editor.
19003    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19004        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19005            buffer.read(cx).project_path(cx)
19006        } else {
19007            None
19008        }
19009    }
19010
19011    // Returns true if the editor handled a go-to-line request
19012    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19013        maybe!({
19014            let breakpoint_store = self.breakpoint_store.as_ref()?;
19015
19016            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19017            else {
19018                self.clear_row_highlights::<ActiveDebugLine>();
19019                return None;
19020            };
19021
19022            let position = active_stack_frame.position;
19023            let buffer_id = position.buffer_id?;
19024            let snapshot = self
19025                .project
19026                .as_ref()?
19027                .read(cx)
19028                .buffer_for_id(buffer_id, cx)?
19029                .read(cx)
19030                .snapshot();
19031
19032            let mut handled = false;
19033            for (id, ExcerptRange { context, .. }) in
19034                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19035            {
19036                if context.start.cmp(&position, &snapshot).is_ge()
19037                    || context.end.cmp(&position, &snapshot).is_lt()
19038                {
19039                    continue;
19040                }
19041                let snapshot = self.buffer.read(cx).snapshot(cx);
19042                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19043
19044                handled = true;
19045                self.clear_row_highlights::<ActiveDebugLine>();
19046
19047                self.go_to_line::<ActiveDebugLine>(
19048                    multibuffer_anchor,
19049                    Some(cx.theme().colors().editor_debugger_active_line_background),
19050                    window,
19051                    cx,
19052                );
19053
19054                cx.notify();
19055            }
19056
19057            handled.then_some(())
19058        })
19059        .is_some()
19060    }
19061
19062    pub fn copy_file_name_without_extension(
19063        &mut self,
19064        _: &CopyFileNameWithoutExtension,
19065        _: &mut Window,
19066        cx: &mut Context<Self>,
19067    ) {
19068        if let Some(file) = self.target_file(cx)
19069            && let Some(file_stem) = file.path().file_stem()
19070            && let Some(name) = file_stem.to_str()
19071        {
19072            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19073        }
19074    }
19075
19076    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19077        if let Some(file) = self.target_file(cx)
19078            && let Some(file_name) = file.path().file_name()
19079            && let Some(name) = file_name.to_str()
19080        {
19081            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19082        }
19083    }
19084
19085    pub fn toggle_git_blame(
19086        &mut self,
19087        _: &::git::Blame,
19088        window: &mut Window,
19089        cx: &mut Context<Self>,
19090    ) {
19091        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19092
19093        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19094            self.start_git_blame(true, window, cx);
19095        }
19096
19097        cx.notify();
19098    }
19099
19100    pub fn toggle_git_blame_inline(
19101        &mut self,
19102        _: &ToggleGitBlameInline,
19103        window: &mut Window,
19104        cx: &mut Context<Self>,
19105    ) {
19106        self.toggle_git_blame_inline_internal(true, window, cx);
19107        cx.notify();
19108    }
19109
19110    pub fn open_git_blame_commit(
19111        &mut self,
19112        _: &OpenGitBlameCommit,
19113        window: &mut Window,
19114        cx: &mut Context<Self>,
19115    ) {
19116        self.open_git_blame_commit_internal(window, cx);
19117    }
19118
19119    fn open_git_blame_commit_internal(
19120        &mut self,
19121        window: &mut Window,
19122        cx: &mut Context<Self>,
19123    ) -> Option<()> {
19124        let blame = self.blame.as_ref()?;
19125        let snapshot = self.snapshot(window, cx);
19126        let cursor = self.selections.newest::<Point>(cx).head();
19127        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19128        let (_, blame_entry) = blame
19129            .update(cx, |blame, cx| {
19130                blame
19131                    .blame_for_rows(
19132                        &[RowInfo {
19133                            buffer_id: Some(buffer.remote_id()),
19134                            buffer_row: Some(point.row),
19135                            ..Default::default()
19136                        }],
19137                        cx,
19138                    )
19139                    .next()
19140            })
19141            .flatten()?;
19142        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19143        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19144        let workspace = self.workspace()?.downgrade();
19145        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19146        None
19147    }
19148
19149    pub fn git_blame_inline_enabled(&self) -> bool {
19150        self.git_blame_inline_enabled
19151    }
19152
19153    pub fn toggle_selection_menu(
19154        &mut self,
19155        _: &ToggleSelectionMenu,
19156        _: &mut Window,
19157        cx: &mut Context<Self>,
19158    ) {
19159        self.show_selection_menu = self
19160            .show_selection_menu
19161            .map(|show_selections_menu| !show_selections_menu)
19162            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19163
19164        cx.notify();
19165    }
19166
19167    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19168        self.show_selection_menu
19169            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19170    }
19171
19172    fn start_git_blame(
19173        &mut self,
19174        user_triggered: bool,
19175        window: &mut Window,
19176        cx: &mut Context<Self>,
19177    ) {
19178        if let Some(project) = self.project() {
19179            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19180                && buffer.read(cx).file().is_none()
19181            {
19182                return;
19183            }
19184
19185            let focused = self.focus_handle(cx).contains_focused(window, cx);
19186
19187            let project = project.clone();
19188            let blame = cx
19189                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19190            self.blame_subscription =
19191                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19192            self.blame = Some(blame);
19193        }
19194    }
19195
19196    fn toggle_git_blame_inline_internal(
19197        &mut self,
19198        user_triggered: bool,
19199        window: &mut Window,
19200        cx: &mut Context<Self>,
19201    ) {
19202        if self.git_blame_inline_enabled {
19203            self.git_blame_inline_enabled = false;
19204            self.show_git_blame_inline = false;
19205            self.show_git_blame_inline_delay_task.take();
19206        } else {
19207            self.git_blame_inline_enabled = true;
19208            self.start_git_blame_inline(user_triggered, window, cx);
19209        }
19210
19211        cx.notify();
19212    }
19213
19214    fn start_git_blame_inline(
19215        &mut self,
19216        user_triggered: bool,
19217        window: &mut Window,
19218        cx: &mut Context<Self>,
19219    ) {
19220        self.start_git_blame(user_triggered, window, cx);
19221
19222        if ProjectSettings::get_global(cx)
19223            .git
19224            .inline_blame_delay()
19225            .is_some()
19226        {
19227            self.start_inline_blame_timer(window, cx);
19228        } else {
19229            self.show_git_blame_inline = true
19230        }
19231    }
19232
19233    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19234        self.blame.as_ref()
19235    }
19236
19237    pub fn show_git_blame_gutter(&self) -> bool {
19238        self.show_git_blame_gutter
19239    }
19240
19241    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19242        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19243    }
19244
19245    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19246        self.show_git_blame_inline
19247            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19248            && !self.newest_selection_head_on_empty_line(cx)
19249            && self.has_blame_entries(cx)
19250    }
19251
19252    fn has_blame_entries(&self, cx: &App) -> bool {
19253        self.blame()
19254            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19255    }
19256
19257    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19258        let cursor_anchor = self.selections.newest_anchor().head();
19259
19260        let snapshot = self.buffer.read(cx).snapshot(cx);
19261        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19262
19263        snapshot.line_len(buffer_row) == 0
19264    }
19265
19266    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19267        let buffer_and_selection = maybe!({
19268            let selection = self.selections.newest::<Point>(cx);
19269            let selection_range = selection.range();
19270
19271            let multi_buffer = self.buffer().read(cx);
19272            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19273            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19274
19275            let (buffer, range, _) = if selection.reversed {
19276                buffer_ranges.first()
19277            } else {
19278                buffer_ranges.last()
19279            }?;
19280
19281            let selection = text::ToPoint::to_point(&range.start, buffer).row
19282                ..text::ToPoint::to_point(&range.end, buffer).row;
19283            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19284        });
19285
19286        let Some((buffer, selection)) = buffer_and_selection else {
19287            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19288        };
19289
19290        let Some(project) = self.project() else {
19291            return Task::ready(Err(anyhow!("editor does not have project")));
19292        };
19293
19294        project.update(cx, |project, cx| {
19295            project.get_permalink_to_line(&buffer, selection, cx)
19296        })
19297    }
19298
19299    pub fn copy_permalink_to_line(
19300        &mut self,
19301        _: &CopyPermalinkToLine,
19302        window: &mut Window,
19303        cx: &mut Context<Self>,
19304    ) {
19305        let permalink_task = self.get_permalink_to_line(cx);
19306        let workspace = self.workspace();
19307
19308        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19309            Ok(permalink) => {
19310                cx.update(|_, cx| {
19311                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19312                })
19313                .ok();
19314            }
19315            Err(err) => {
19316                let message = format!("Failed to copy permalink: {err}");
19317
19318                anyhow::Result::<()>::Err(err).log_err();
19319
19320                if let Some(workspace) = workspace {
19321                    workspace
19322                        .update_in(cx, |workspace, _, cx| {
19323                            struct CopyPermalinkToLine;
19324
19325                            workspace.show_toast(
19326                                Toast::new(
19327                                    NotificationId::unique::<CopyPermalinkToLine>(),
19328                                    message,
19329                                ),
19330                                cx,
19331                            )
19332                        })
19333                        .ok();
19334                }
19335            }
19336        })
19337        .detach();
19338    }
19339
19340    pub fn copy_file_location(
19341        &mut self,
19342        _: &CopyFileLocation,
19343        _: &mut Window,
19344        cx: &mut Context<Self>,
19345    ) {
19346        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19347        if let Some(file) = self.target_file(cx)
19348            && let Some(path) = file.path().to_str()
19349        {
19350            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19351        }
19352    }
19353
19354    pub fn open_permalink_to_line(
19355        &mut self,
19356        _: &OpenPermalinkToLine,
19357        window: &mut Window,
19358        cx: &mut Context<Self>,
19359    ) {
19360        let permalink_task = self.get_permalink_to_line(cx);
19361        let workspace = self.workspace();
19362
19363        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19364            Ok(permalink) => {
19365                cx.update(|_, cx| {
19366                    cx.open_url(permalink.as_ref());
19367                })
19368                .ok();
19369            }
19370            Err(err) => {
19371                let message = format!("Failed to open permalink: {err}");
19372
19373                anyhow::Result::<()>::Err(err).log_err();
19374
19375                if let Some(workspace) = workspace {
19376                    workspace
19377                        .update(cx, |workspace, cx| {
19378                            struct OpenPermalinkToLine;
19379
19380                            workspace.show_toast(
19381                                Toast::new(
19382                                    NotificationId::unique::<OpenPermalinkToLine>(),
19383                                    message,
19384                                ),
19385                                cx,
19386                            )
19387                        })
19388                        .ok();
19389                }
19390            }
19391        })
19392        .detach();
19393    }
19394
19395    pub fn insert_uuid_v4(
19396        &mut self,
19397        _: &InsertUuidV4,
19398        window: &mut Window,
19399        cx: &mut Context<Self>,
19400    ) {
19401        self.insert_uuid(UuidVersion::V4, window, cx);
19402    }
19403
19404    pub fn insert_uuid_v7(
19405        &mut self,
19406        _: &InsertUuidV7,
19407        window: &mut Window,
19408        cx: &mut Context<Self>,
19409    ) {
19410        self.insert_uuid(UuidVersion::V7, window, cx);
19411    }
19412
19413    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19414        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19415        self.transact(window, cx, |this, window, cx| {
19416            let edits = this
19417                .selections
19418                .all::<Point>(cx)
19419                .into_iter()
19420                .map(|selection| {
19421                    let uuid = match version {
19422                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19423                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19424                    };
19425
19426                    (selection.range(), uuid.to_string())
19427                });
19428            this.edit(edits, cx);
19429            this.refresh_edit_prediction(true, false, window, cx);
19430        });
19431    }
19432
19433    pub fn open_selections_in_multibuffer(
19434        &mut self,
19435        _: &OpenSelectionsInMultibuffer,
19436        window: &mut Window,
19437        cx: &mut Context<Self>,
19438    ) {
19439        let multibuffer = self.buffer.read(cx);
19440
19441        let Some(buffer) = multibuffer.as_singleton() else {
19442            return;
19443        };
19444
19445        let Some(workspace) = self.workspace() else {
19446            return;
19447        };
19448
19449        let title = multibuffer.title(cx).to_string();
19450
19451        let locations = self
19452            .selections
19453            .all_anchors(cx)
19454            .iter()
19455            .map(|selection| Location {
19456                buffer: buffer.clone(),
19457                range: selection.start.text_anchor..selection.end.text_anchor,
19458            })
19459            .collect::<Vec<_>>();
19460
19461        cx.spawn_in(window, async move |_, cx| {
19462            workspace.update_in(cx, |workspace, window, cx| {
19463                Self::open_locations_in_multibuffer(
19464                    workspace,
19465                    locations,
19466                    format!("Selections for '{title}'"),
19467                    false,
19468                    MultibufferSelectionMode::All,
19469                    window,
19470                    cx,
19471                );
19472            })
19473        })
19474        .detach();
19475    }
19476
19477    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19478    /// last highlight added will be used.
19479    ///
19480    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19481    pub fn highlight_rows<T: 'static>(
19482        &mut self,
19483        range: Range<Anchor>,
19484        color: Hsla,
19485        options: RowHighlightOptions,
19486        cx: &mut Context<Self>,
19487    ) {
19488        let snapshot = self.buffer().read(cx).snapshot(cx);
19489        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19490        let ix = row_highlights.binary_search_by(|highlight| {
19491            Ordering::Equal
19492                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19493                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19494        });
19495
19496        if let Err(mut ix) = ix {
19497            let index = post_inc(&mut self.highlight_order);
19498
19499            // If this range intersects with the preceding highlight, then merge it with
19500            // the preceding highlight. Otherwise insert a new highlight.
19501            let mut merged = false;
19502            if ix > 0 {
19503                let prev_highlight = &mut row_highlights[ix - 1];
19504                if prev_highlight
19505                    .range
19506                    .end
19507                    .cmp(&range.start, &snapshot)
19508                    .is_ge()
19509                {
19510                    ix -= 1;
19511                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19512                        prev_highlight.range.end = range.end;
19513                    }
19514                    merged = true;
19515                    prev_highlight.index = index;
19516                    prev_highlight.color = color;
19517                    prev_highlight.options = options;
19518                }
19519            }
19520
19521            if !merged {
19522                row_highlights.insert(
19523                    ix,
19524                    RowHighlight {
19525                        range,
19526                        index,
19527                        color,
19528                        options,
19529                        type_id: TypeId::of::<T>(),
19530                    },
19531                );
19532            }
19533
19534            // If any of the following highlights intersect with this one, merge them.
19535            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19536                let highlight = &row_highlights[ix];
19537                if next_highlight
19538                    .range
19539                    .start
19540                    .cmp(&highlight.range.end, &snapshot)
19541                    .is_le()
19542                {
19543                    if next_highlight
19544                        .range
19545                        .end
19546                        .cmp(&highlight.range.end, &snapshot)
19547                        .is_gt()
19548                    {
19549                        row_highlights[ix].range.end = next_highlight.range.end;
19550                    }
19551                    row_highlights.remove(ix + 1);
19552                } else {
19553                    break;
19554                }
19555            }
19556        }
19557    }
19558
19559    /// Remove any highlighted row ranges of the given type that intersect the
19560    /// given ranges.
19561    pub fn remove_highlighted_rows<T: 'static>(
19562        &mut self,
19563        ranges_to_remove: Vec<Range<Anchor>>,
19564        cx: &mut Context<Self>,
19565    ) {
19566        let snapshot = self.buffer().read(cx).snapshot(cx);
19567        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19568        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19569        row_highlights.retain(|highlight| {
19570            while let Some(range_to_remove) = ranges_to_remove.peek() {
19571                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19572                    Ordering::Less | Ordering::Equal => {
19573                        ranges_to_remove.next();
19574                    }
19575                    Ordering::Greater => {
19576                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19577                            Ordering::Less | Ordering::Equal => {
19578                                return false;
19579                            }
19580                            Ordering::Greater => break,
19581                        }
19582                    }
19583                }
19584            }
19585
19586            true
19587        })
19588    }
19589
19590    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19591    pub fn clear_row_highlights<T: 'static>(&mut self) {
19592        self.highlighted_rows.remove(&TypeId::of::<T>());
19593    }
19594
19595    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19596    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19597        self.highlighted_rows
19598            .get(&TypeId::of::<T>())
19599            .map_or(&[] as &[_], |vec| vec.as_slice())
19600            .iter()
19601            .map(|highlight| (highlight.range.clone(), highlight.color))
19602    }
19603
19604    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19605    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19606    /// Allows to ignore certain kinds of highlights.
19607    pub fn highlighted_display_rows(
19608        &self,
19609        window: &mut Window,
19610        cx: &mut App,
19611    ) -> BTreeMap<DisplayRow, LineHighlight> {
19612        let snapshot = self.snapshot(window, cx);
19613        let mut used_highlight_orders = HashMap::default();
19614        self.highlighted_rows
19615            .iter()
19616            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19617            .fold(
19618                BTreeMap::<DisplayRow, LineHighlight>::new(),
19619                |mut unique_rows, highlight| {
19620                    let start = highlight.range.start.to_display_point(&snapshot);
19621                    let end = highlight.range.end.to_display_point(&snapshot);
19622                    let start_row = start.row().0;
19623                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19624                        && end.column() == 0
19625                    {
19626                        end.row().0.saturating_sub(1)
19627                    } else {
19628                        end.row().0
19629                    };
19630                    for row in start_row..=end_row {
19631                        let used_index =
19632                            used_highlight_orders.entry(row).or_insert(highlight.index);
19633                        if highlight.index >= *used_index {
19634                            *used_index = highlight.index;
19635                            unique_rows.insert(
19636                                DisplayRow(row),
19637                                LineHighlight {
19638                                    include_gutter: highlight.options.include_gutter,
19639                                    border: None,
19640                                    background: highlight.color.into(),
19641                                    type_id: Some(highlight.type_id),
19642                                },
19643                            );
19644                        }
19645                    }
19646                    unique_rows
19647                },
19648            )
19649    }
19650
19651    pub fn highlighted_display_row_for_autoscroll(
19652        &self,
19653        snapshot: &DisplaySnapshot,
19654    ) -> Option<DisplayRow> {
19655        self.highlighted_rows
19656            .values()
19657            .flat_map(|highlighted_rows| highlighted_rows.iter())
19658            .filter_map(|highlight| {
19659                if highlight.options.autoscroll {
19660                    Some(highlight.range.start.to_display_point(snapshot).row())
19661                } else {
19662                    None
19663                }
19664            })
19665            .min()
19666    }
19667
19668    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19669        self.highlight_background::<SearchWithinRange>(
19670            ranges,
19671            |colors| colors.colors().editor_document_highlight_read_background,
19672            cx,
19673        )
19674    }
19675
19676    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19677        self.breadcrumb_header = Some(new_header);
19678    }
19679
19680    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19681        self.clear_background_highlights::<SearchWithinRange>(cx);
19682    }
19683
19684    pub fn highlight_background<T: 'static>(
19685        &mut self,
19686        ranges: &[Range<Anchor>],
19687        color_fetcher: fn(&Theme) -> Hsla,
19688        cx: &mut Context<Self>,
19689    ) {
19690        self.background_highlights.insert(
19691            HighlightKey::Type(TypeId::of::<T>()),
19692            (color_fetcher, Arc::from(ranges)),
19693        );
19694        self.scrollbar_marker_state.dirty = true;
19695        cx.notify();
19696    }
19697
19698    pub fn highlight_background_key<T: 'static>(
19699        &mut self,
19700        key: usize,
19701        ranges: &[Range<Anchor>],
19702        color_fetcher: fn(&Theme) -> Hsla,
19703        cx: &mut Context<Self>,
19704    ) {
19705        self.background_highlights.insert(
19706            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19707            (color_fetcher, Arc::from(ranges)),
19708        );
19709        self.scrollbar_marker_state.dirty = true;
19710        cx.notify();
19711    }
19712
19713    pub fn clear_background_highlights<T: 'static>(
19714        &mut self,
19715        cx: &mut Context<Self>,
19716    ) -> Option<BackgroundHighlight> {
19717        let text_highlights = self
19718            .background_highlights
19719            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19720        if !text_highlights.1.is_empty() {
19721            self.scrollbar_marker_state.dirty = true;
19722            cx.notify();
19723        }
19724        Some(text_highlights)
19725    }
19726
19727    pub fn highlight_gutter<T: 'static>(
19728        &mut self,
19729        ranges: impl Into<Vec<Range<Anchor>>>,
19730        color_fetcher: fn(&App) -> Hsla,
19731        cx: &mut Context<Self>,
19732    ) {
19733        self.gutter_highlights
19734            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19735        cx.notify();
19736    }
19737
19738    pub fn clear_gutter_highlights<T: 'static>(
19739        &mut self,
19740        cx: &mut Context<Self>,
19741    ) -> Option<GutterHighlight> {
19742        cx.notify();
19743        self.gutter_highlights.remove(&TypeId::of::<T>())
19744    }
19745
19746    pub fn insert_gutter_highlight<T: 'static>(
19747        &mut self,
19748        range: Range<Anchor>,
19749        color_fetcher: fn(&App) -> Hsla,
19750        cx: &mut Context<Self>,
19751    ) {
19752        let snapshot = self.buffer().read(cx).snapshot(cx);
19753        let mut highlights = self
19754            .gutter_highlights
19755            .remove(&TypeId::of::<T>())
19756            .map(|(_, highlights)| highlights)
19757            .unwrap_or_default();
19758        let ix = highlights.binary_search_by(|highlight| {
19759            Ordering::Equal
19760                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19761                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19762        });
19763        if let Err(ix) = ix {
19764            highlights.insert(ix, range);
19765        }
19766        self.gutter_highlights
19767            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19768    }
19769
19770    pub fn remove_gutter_highlights<T: 'static>(
19771        &mut self,
19772        ranges_to_remove: Vec<Range<Anchor>>,
19773        cx: &mut Context<Self>,
19774    ) {
19775        let snapshot = self.buffer().read(cx).snapshot(cx);
19776        let Some((color_fetcher, mut gutter_highlights)) =
19777            self.gutter_highlights.remove(&TypeId::of::<T>())
19778        else {
19779            return;
19780        };
19781        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19782        gutter_highlights.retain(|highlight| {
19783            while let Some(range_to_remove) = ranges_to_remove.peek() {
19784                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19785                    Ordering::Less | Ordering::Equal => {
19786                        ranges_to_remove.next();
19787                    }
19788                    Ordering::Greater => {
19789                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19790                            Ordering::Less | Ordering::Equal => {
19791                                return false;
19792                            }
19793                            Ordering::Greater => break,
19794                        }
19795                    }
19796                }
19797            }
19798
19799            true
19800        });
19801        self.gutter_highlights
19802            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19803    }
19804
19805    #[cfg(feature = "test-support")]
19806    pub fn all_text_highlights(
19807        &self,
19808        window: &mut Window,
19809        cx: &mut Context<Self>,
19810    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19811        let snapshot = self.snapshot(window, cx);
19812        self.display_map.update(cx, |display_map, _| {
19813            display_map
19814                .all_text_highlights()
19815                .map(|highlight| {
19816                    let (style, ranges) = highlight.as_ref();
19817                    (
19818                        *style,
19819                        ranges
19820                            .iter()
19821                            .map(|range| range.clone().to_display_points(&snapshot))
19822                            .collect(),
19823                    )
19824                })
19825                .collect()
19826        })
19827    }
19828
19829    #[cfg(feature = "test-support")]
19830    pub fn all_text_background_highlights(
19831        &self,
19832        window: &mut Window,
19833        cx: &mut Context<Self>,
19834    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19835        let snapshot = self.snapshot(window, cx);
19836        let buffer = &snapshot.buffer_snapshot;
19837        let start = buffer.anchor_before(0);
19838        let end = buffer.anchor_after(buffer.len());
19839        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
19840    }
19841
19842    #[cfg(any(test, feature = "test-support"))]
19843    pub fn sorted_background_highlights_in_range(
19844        &self,
19845        search_range: Range<Anchor>,
19846        display_snapshot: &DisplaySnapshot,
19847        theme: &Theme,
19848    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19849        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
19850        res.sort_by(|a, b| {
19851            a.0.start
19852                .cmp(&b.0.start)
19853                .then_with(|| a.0.end.cmp(&b.0.end))
19854                .then_with(|| a.1.cmp(&b.1))
19855        });
19856        res
19857    }
19858
19859    #[cfg(feature = "test-support")]
19860    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19861        let snapshot = self.buffer().read(cx).snapshot(cx);
19862
19863        let highlights = self
19864            .background_highlights
19865            .get(&HighlightKey::Type(TypeId::of::<
19866                items::BufferSearchHighlights,
19867            >()));
19868
19869        if let Some((_color, ranges)) = highlights {
19870            ranges
19871                .iter()
19872                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19873                .collect_vec()
19874        } else {
19875            vec![]
19876        }
19877    }
19878
19879    fn document_highlights_for_position<'a>(
19880        &'a self,
19881        position: Anchor,
19882        buffer: &'a MultiBufferSnapshot,
19883    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19884        let read_highlights = self
19885            .background_highlights
19886            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19887            .map(|h| &h.1);
19888        let write_highlights = self
19889            .background_highlights
19890            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19891            .map(|h| &h.1);
19892        let left_position = position.bias_left(buffer);
19893        let right_position = position.bias_right(buffer);
19894        read_highlights
19895            .into_iter()
19896            .chain(write_highlights)
19897            .flat_map(move |ranges| {
19898                let start_ix = match ranges.binary_search_by(|probe| {
19899                    let cmp = probe.end.cmp(&left_position, buffer);
19900                    if cmp.is_ge() {
19901                        Ordering::Greater
19902                    } else {
19903                        Ordering::Less
19904                    }
19905                }) {
19906                    Ok(i) | Err(i) => i,
19907                };
19908
19909                ranges[start_ix..]
19910                    .iter()
19911                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19912            })
19913    }
19914
19915    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19916        self.background_highlights
19917            .get(&HighlightKey::Type(TypeId::of::<T>()))
19918            .is_some_and(|(_, highlights)| !highlights.is_empty())
19919    }
19920
19921    /// Returns all background highlights for a given range.
19922    ///
19923    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
19924    pub fn background_highlights_in_range(
19925        &self,
19926        search_range: Range<Anchor>,
19927        display_snapshot: &DisplaySnapshot,
19928        theme: &Theme,
19929    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19930        let mut results = Vec::new();
19931        for (color_fetcher, ranges) in self.background_highlights.values() {
19932            let color = color_fetcher(theme);
19933            let start_ix = match ranges.binary_search_by(|probe| {
19934                let cmp = probe
19935                    .end
19936                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19937                if cmp.is_gt() {
19938                    Ordering::Greater
19939                } else {
19940                    Ordering::Less
19941                }
19942            }) {
19943                Ok(i) | Err(i) => i,
19944            };
19945            for range in &ranges[start_ix..] {
19946                if range
19947                    .start
19948                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19949                    .is_ge()
19950                {
19951                    break;
19952                }
19953
19954                let start = range.start.to_display_point(display_snapshot);
19955                let end = range.end.to_display_point(display_snapshot);
19956                results.push((start..end, color))
19957            }
19958        }
19959        results
19960    }
19961
19962    pub fn gutter_highlights_in_range(
19963        &self,
19964        search_range: Range<Anchor>,
19965        display_snapshot: &DisplaySnapshot,
19966        cx: &App,
19967    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19968        let mut results = Vec::new();
19969        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19970            let color = color_fetcher(cx);
19971            let start_ix = match ranges.binary_search_by(|probe| {
19972                let cmp = probe
19973                    .end
19974                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19975                if cmp.is_gt() {
19976                    Ordering::Greater
19977                } else {
19978                    Ordering::Less
19979                }
19980            }) {
19981                Ok(i) | Err(i) => i,
19982            };
19983            for range in &ranges[start_ix..] {
19984                if range
19985                    .start
19986                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19987                    .is_ge()
19988                {
19989                    break;
19990                }
19991
19992                let start = range.start.to_display_point(display_snapshot);
19993                let end = range.end.to_display_point(display_snapshot);
19994                results.push((start..end, color))
19995            }
19996        }
19997        results
19998    }
19999
20000    /// Get the text ranges corresponding to the redaction query
20001    pub fn redacted_ranges(
20002        &self,
20003        search_range: Range<Anchor>,
20004        display_snapshot: &DisplaySnapshot,
20005        cx: &App,
20006    ) -> Vec<Range<DisplayPoint>> {
20007        display_snapshot
20008            .buffer_snapshot
20009            .redacted_ranges(search_range, |file| {
20010                if let Some(file) = file {
20011                    file.is_private()
20012                        && EditorSettings::get(
20013                            Some(SettingsLocation {
20014                                worktree_id: file.worktree_id(cx),
20015                                path: file.path().as_ref(),
20016                            }),
20017                            cx,
20018                        )
20019                        .redact_private_values
20020                } else {
20021                    false
20022                }
20023            })
20024            .map(|range| {
20025                range.start.to_display_point(display_snapshot)
20026                    ..range.end.to_display_point(display_snapshot)
20027            })
20028            .collect()
20029    }
20030
20031    pub fn highlight_text_key<T: 'static>(
20032        &mut self,
20033        key: usize,
20034        ranges: Vec<Range<Anchor>>,
20035        style: HighlightStyle,
20036        cx: &mut Context<Self>,
20037    ) {
20038        self.display_map.update(cx, |map, _| {
20039            map.highlight_text(
20040                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20041                ranges,
20042                style,
20043            );
20044        });
20045        cx.notify();
20046    }
20047
20048    pub fn highlight_text<T: 'static>(
20049        &mut self,
20050        ranges: Vec<Range<Anchor>>,
20051        style: HighlightStyle,
20052        cx: &mut Context<Self>,
20053    ) {
20054        self.display_map.update(cx, |map, _| {
20055            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20056        });
20057        cx.notify();
20058    }
20059
20060    pub(crate) fn highlight_inlays<T: 'static>(
20061        &mut self,
20062        highlights: Vec<InlayHighlight>,
20063        style: HighlightStyle,
20064        cx: &mut Context<Self>,
20065    ) {
20066        self.display_map.update(cx, |map, _| {
20067            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20068        });
20069        cx.notify();
20070    }
20071
20072    pub fn text_highlights<'a, T: 'static>(
20073        &'a self,
20074        cx: &'a App,
20075    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20076        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20077    }
20078
20079    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20080        let cleared = self
20081            .display_map
20082            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20083        if cleared {
20084            cx.notify();
20085        }
20086    }
20087
20088    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20089        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20090            && self.focus_handle.is_focused(window)
20091    }
20092
20093    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20094        self.show_cursor_when_unfocused = is_enabled;
20095        cx.notify();
20096    }
20097
20098    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20099        cx.notify();
20100    }
20101
20102    fn on_debug_session_event(
20103        &mut self,
20104        _session: Entity<Session>,
20105        event: &SessionEvent,
20106        cx: &mut Context<Self>,
20107    ) {
20108        if let SessionEvent::InvalidateInlineValue = event {
20109            self.refresh_inline_values(cx);
20110        }
20111    }
20112
20113    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20114        let Some(project) = self.project.clone() else {
20115            return;
20116        };
20117
20118        if !self.inline_value_cache.enabled {
20119            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20120            self.splice_inlays(&inlays, Vec::new(), cx);
20121            return;
20122        }
20123
20124        let current_execution_position = self
20125            .highlighted_rows
20126            .get(&TypeId::of::<ActiveDebugLine>())
20127            .and_then(|lines| lines.last().map(|line| line.range.end));
20128
20129        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20130            let inline_values = editor
20131                .update(cx, |editor, cx| {
20132                    let Some(current_execution_position) = current_execution_position else {
20133                        return Some(Task::ready(Ok(Vec::new())));
20134                    };
20135
20136                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20137                        let snapshot = buffer.snapshot(cx);
20138
20139                        let excerpt = snapshot.excerpt_containing(
20140                            current_execution_position..current_execution_position,
20141                        )?;
20142
20143                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20144                    })?;
20145
20146                    let range =
20147                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20148
20149                    project.inline_values(buffer, range, cx)
20150                })
20151                .ok()
20152                .flatten()?
20153                .await
20154                .context("refreshing debugger inlays")
20155                .log_err()?;
20156
20157            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20158
20159            for (buffer_id, inline_value) in inline_values
20160                .into_iter()
20161                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20162            {
20163                buffer_inline_values
20164                    .entry(buffer_id)
20165                    .or_default()
20166                    .push(inline_value);
20167            }
20168
20169            editor
20170                .update(cx, |editor, cx| {
20171                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20172                    let mut new_inlays = Vec::default();
20173
20174                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20175                        let buffer_id = buffer_snapshot.remote_id();
20176                        buffer_inline_values
20177                            .get(&buffer_id)
20178                            .into_iter()
20179                            .flatten()
20180                            .for_each(|hint| {
20181                                let inlay = Inlay::debugger(
20182                                    post_inc(&mut editor.next_inlay_id),
20183                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20184                                    hint.text(),
20185                                );
20186                                if !inlay.text.chars().contains(&'\n') {
20187                                    new_inlays.push(inlay);
20188                                }
20189                            });
20190                    }
20191
20192                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20193                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20194
20195                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20196                })
20197                .ok()?;
20198            Some(())
20199        });
20200    }
20201
20202    fn on_buffer_event(
20203        &mut self,
20204        multibuffer: &Entity<MultiBuffer>,
20205        event: &multi_buffer::Event,
20206        window: &mut Window,
20207        cx: &mut Context<Self>,
20208    ) {
20209        match event {
20210            multi_buffer::Event::Edited {
20211                singleton_buffer_edited,
20212                edited_buffer,
20213            } => {
20214                self.scrollbar_marker_state.dirty = true;
20215                self.active_indent_guides_state.dirty = true;
20216                self.refresh_active_diagnostics(cx);
20217                self.refresh_code_actions(window, cx);
20218                self.refresh_selected_text_highlights(true, window, cx);
20219                self.refresh_single_line_folds(window, cx);
20220                refresh_matching_bracket_highlights(self, window, cx);
20221                if self.has_active_edit_prediction() {
20222                    self.update_visible_edit_prediction(window, cx);
20223                }
20224                if let Some(project) = self.project.as_ref()
20225                    && let Some(edited_buffer) = edited_buffer
20226                {
20227                    project.update(cx, |project, cx| {
20228                        self.registered_buffers
20229                            .entry(edited_buffer.read(cx).remote_id())
20230                            .or_insert_with(|| {
20231                                project.register_buffer_with_language_servers(edited_buffer, cx)
20232                            });
20233                    });
20234                }
20235                cx.emit(EditorEvent::BufferEdited);
20236                cx.emit(SearchEvent::MatchesInvalidated);
20237
20238                if let Some(buffer) = edited_buffer {
20239                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20240                }
20241
20242                if *singleton_buffer_edited {
20243                    if let Some(buffer) = edited_buffer
20244                        && buffer.read(cx).file().is_none()
20245                    {
20246                        cx.emit(EditorEvent::TitleChanged);
20247                    }
20248                    if let Some(project) = &self.project {
20249                        #[allow(clippy::mutable_key_type)]
20250                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20251                            multibuffer
20252                                .all_buffers()
20253                                .into_iter()
20254                                .filter_map(|buffer| {
20255                                    buffer.update(cx, |buffer, cx| {
20256                                        let language = buffer.language()?;
20257                                        let should_discard = project.update(cx, |project, cx| {
20258                                            project.is_local()
20259                                                && !project.has_language_servers_for(buffer, cx)
20260                                        });
20261                                        should_discard.not().then_some(language.clone())
20262                                    })
20263                                })
20264                                .collect::<HashSet<_>>()
20265                        });
20266                        if !languages_affected.is_empty() {
20267                            self.refresh_inlay_hints(
20268                                InlayHintRefreshReason::BufferEdited(languages_affected),
20269                                cx,
20270                            );
20271                        }
20272                    }
20273                }
20274
20275                let Some(project) = &self.project else { return };
20276                let (telemetry, is_via_ssh) = {
20277                    let project = project.read(cx);
20278                    let telemetry = project.client().telemetry().clone();
20279                    let is_via_ssh = project.is_via_remote_server();
20280                    (telemetry, is_via_ssh)
20281                };
20282                refresh_linked_ranges(self, window, cx);
20283                telemetry.log_edit_event("editor", is_via_ssh);
20284            }
20285            multi_buffer::Event::ExcerptsAdded {
20286                buffer,
20287                predecessor,
20288                excerpts,
20289            } => {
20290                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20291                let buffer_id = buffer.read(cx).remote_id();
20292                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20293                    && let Some(project) = &self.project
20294                {
20295                    update_uncommitted_diff_for_buffer(
20296                        cx.entity(),
20297                        project,
20298                        [buffer.clone()],
20299                        self.buffer.clone(),
20300                        cx,
20301                    )
20302                    .detach();
20303                }
20304                self.update_lsp_data(false, Some(buffer_id), window, cx);
20305                cx.emit(EditorEvent::ExcerptsAdded {
20306                    buffer: buffer.clone(),
20307                    predecessor: *predecessor,
20308                    excerpts: excerpts.clone(),
20309                });
20310                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20311            }
20312            multi_buffer::Event::ExcerptsRemoved {
20313                ids,
20314                removed_buffer_ids,
20315            } => {
20316                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20317                let buffer = self.buffer.read(cx);
20318                self.registered_buffers
20319                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20320                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20321                cx.emit(EditorEvent::ExcerptsRemoved {
20322                    ids: ids.clone(),
20323                    removed_buffer_ids: removed_buffer_ids.clone(),
20324                });
20325            }
20326            multi_buffer::Event::ExcerptsEdited {
20327                excerpt_ids,
20328                buffer_ids,
20329            } => {
20330                self.display_map.update(cx, |map, cx| {
20331                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20332                });
20333                cx.emit(EditorEvent::ExcerptsEdited {
20334                    ids: excerpt_ids.clone(),
20335                });
20336            }
20337            multi_buffer::Event::ExcerptsExpanded { ids } => {
20338                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20339                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20340            }
20341            multi_buffer::Event::Reparsed(buffer_id) => {
20342                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20343                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20344
20345                cx.emit(EditorEvent::Reparsed(*buffer_id));
20346            }
20347            multi_buffer::Event::DiffHunksToggled => {
20348                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20349            }
20350            multi_buffer::Event::LanguageChanged(buffer_id) => {
20351                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20352                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20353                cx.emit(EditorEvent::Reparsed(*buffer_id));
20354                cx.notify();
20355            }
20356            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20357            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20358            multi_buffer::Event::FileHandleChanged
20359            | multi_buffer::Event::Reloaded
20360            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20361            multi_buffer::Event::DiagnosticsUpdated => {
20362                self.update_diagnostics_state(window, cx);
20363            }
20364            _ => {}
20365        };
20366    }
20367
20368    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20369        if !self.diagnostics_enabled() {
20370            return;
20371        }
20372        self.refresh_active_diagnostics(cx);
20373        self.refresh_inline_diagnostics(true, window, cx);
20374        self.scrollbar_marker_state.dirty = true;
20375        cx.notify();
20376    }
20377
20378    pub fn start_temporary_diff_override(&mut self) {
20379        self.load_diff_task.take();
20380        self.temporary_diff_override = true;
20381    }
20382
20383    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20384        self.temporary_diff_override = false;
20385        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20386        self.buffer.update(cx, |buffer, cx| {
20387            buffer.set_all_diff_hunks_collapsed(cx);
20388        });
20389
20390        if let Some(project) = self.project.clone() {
20391            self.load_diff_task = Some(
20392                update_uncommitted_diff_for_buffer(
20393                    cx.entity(),
20394                    &project,
20395                    self.buffer.read(cx).all_buffers(),
20396                    self.buffer.clone(),
20397                    cx,
20398                )
20399                .shared(),
20400            );
20401        }
20402    }
20403
20404    fn on_display_map_changed(
20405        &mut self,
20406        _: Entity<DisplayMap>,
20407        _: &mut Window,
20408        cx: &mut Context<Self>,
20409    ) {
20410        cx.notify();
20411    }
20412
20413    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20414        if self.diagnostics_enabled() {
20415            let new_severity = EditorSettings::get_global(cx)
20416                .diagnostics_max_severity
20417                .unwrap_or(DiagnosticSeverity::Hint);
20418            self.set_max_diagnostics_severity(new_severity, cx);
20419        }
20420        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20421        self.update_edit_prediction_settings(cx);
20422        self.refresh_edit_prediction(true, false, window, cx);
20423        self.refresh_inline_values(cx);
20424        self.refresh_inlay_hints(
20425            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20426                self.selections.newest_anchor().head(),
20427                &self.buffer.read(cx).snapshot(cx),
20428                cx,
20429            )),
20430            cx,
20431        );
20432
20433        let old_cursor_shape = self.cursor_shape;
20434        let old_show_breadcrumbs = self.show_breadcrumbs;
20435
20436        {
20437            let editor_settings = EditorSettings::get_global(cx);
20438            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20439            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20440            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20441            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20442        }
20443
20444        if old_cursor_shape != self.cursor_shape {
20445            cx.emit(EditorEvent::CursorShapeChanged);
20446        }
20447
20448        if old_show_breadcrumbs != self.show_breadcrumbs {
20449            cx.emit(EditorEvent::BreadcrumbsChanged);
20450        }
20451
20452        let project_settings = ProjectSettings::get_global(cx);
20453        self.serialize_dirty_buffers =
20454            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20455
20456        if self.mode.is_full() {
20457            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20458            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20459            if self.show_inline_diagnostics != show_inline_diagnostics {
20460                self.show_inline_diagnostics = show_inline_diagnostics;
20461                self.refresh_inline_diagnostics(false, window, cx);
20462            }
20463
20464            if self.git_blame_inline_enabled != inline_blame_enabled {
20465                self.toggle_git_blame_inline_internal(false, window, cx);
20466            }
20467
20468            let minimap_settings = EditorSettings::get_global(cx).minimap;
20469            if self.minimap_visibility != MinimapVisibility::Disabled {
20470                if self.minimap_visibility.settings_visibility()
20471                    != minimap_settings.minimap_enabled()
20472                {
20473                    self.set_minimap_visibility(
20474                        MinimapVisibility::for_mode(self.mode(), cx),
20475                        window,
20476                        cx,
20477                    );
20478                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20479                    minimap_entity.update(cx, |minimap_editor, cx| {
20480                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20481                    })
20482                }
20483            }
20484        }
20485
20486        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20487            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20488        }) {
20489            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20490                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20491            }
20492            self.refresh_colors(false, None, window, cx);
20493        }
20494
20495        cx.notify();
20496    }
20497
20498    pub fn set_searchable(&mut self, searchable: bool) {
20499        self.searchable = searchable;
20500    }
20501
20502    pub fn searchable(&self) -> bool {
20503        self.searchable
20504    }
20505
20506    fn open_proposed_changes_editor(
20507        &mut self,
20508        _: &OpenProposedChangesEditor,
20509        window: &mut Window,
20510        cx: &mut Context<Self>,
20511    ) {
20512        let Some(workspace) = self.workspace() else {
20513            cx.propagate();
20514            return;
20515        };
20516
20517        let selections = self.selections.all::<usize>(cx);
20518        let multi_buffer = self.buffer.read(cx);
20519        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20520        let mut new_selections_by_buffer = HashMap::default();
20521        for selection in selections {
20522            for (buffer, range, _) in
20523                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20524            {
20525                let mut range = range.to_point(buffer);
20526                range.start.column = 0;
20527                range.end.column = buffer.line_len(range.end.row);
20528                new_selections_by_buffer
20529                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20530                    .or_insert(Vec::new())
20531                    .push(range)
20532            }
20533        }
20534
20535        let proposed_changes_buffers = new_selections_by_buffer
20536            .into_iter()
20537            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20538            .collect::<Vec<_>>();
20539        let proposed_changes_editor = cx.new(|cx| {
20540            ProposedChangesEditor::new(
20541                "Proposed changes",
20542                proposed_changes_buffers,
20543                self.project.clone(),
20544                window,
20545                cx,
20546            )
20547        });
20548
20549        window.defer(cx, move |window, cx| {
20550            workspace.update(cx, |workspace, cx| {
20551                workspace.active_pane().update(cx, |pane, cx| {
20552                    pane.add_item(
20553                        Box::new(proposed_changes_editor),
20554                        true,
20555                        true,
20556                        None,
20557                        window,
20558                        cx,
20559                    );
20560                });
20561            });
20562        });
20563    }
20564
20565    pub fn open_excerpts_in_split(
20566        &mut self,
20567        _: &OpenExcerptsSplit,
20568        window: &mut Window,
20569        cx: &mut Context<Self>,
20570    ) {
20571        self.open_excerpts_common(None, true, window, cx)
20572    }
20573
20574    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20575        self.open_excerpts_common(None, false, window, cx)
20576    }
20577
20578    fn open_excerpts_common(
20579        &mut self,
20580        jump_data: Option<JumpData>,
20581        split: bool,
20582        window: &mut Window,
20583        cx: &mut Context<Self>,
20584    ) {
20585        let Some(workspace) = self.workspace() else {
20586            cx.propagate();
20587            return;
20588        };
20589
20590        if self.buffer.read(cx).is_singleton() {
20591            cx.propagate();
20592            return;
20593        }
20594
20595        let mut new_selections_by_buffer = HashMap::default();
20596        match &jump_data {
20597            Some(JumpData::MultiBufferPoint {
20598                excerpt_id,
20599                position,
20600                anchor,
20601                line_offset_from_top,
20602            }) => {
20603                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20604                if let Some(buffer) = multi_buffer_snapshot
20605                    .buffer_id_for_excerpt(*excerpt_id)
20606                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20607                {
20608                    let buffer_snapshot = buffer.read(cx).snapshot();
20609                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20610                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20611                    } else {
20612                        buffer_snapshot.clip_point(*position, Bias::Left)
20613                    };
20614                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20615                    new_selections_by_buffer.insert(
20616                        buffer,
20617                        (
20618                            vec![jump_to_offset..jump_to_offset],
20619                            Some(*line_offset_from_top),
20620                        ),
20621                    );
20622                }
20623            }
20624            Some(JumpData::MultiBufferRow {
20625                row,
20626                line_offset_from_top,
20627            }) => {
20628                let point = MultiBufferPoint::new(row.0, 0);
20629                if let Some((buffer, buffer_point, _)) =
20630                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20631                {
20632                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20633                    new_selections_by_buffer
20634                        .entry(buffer)
20635                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20636                        .0
20637                        .push(buffer_offset..buffer_offset)
20638                }
20639            }
20640            None => {
20641                let selections = self.selections.all::<usize>(cx);
20642                let multi_buffer = self.buffer.read(cx);
20643                for selection in selections {
20644                    for (snapshot, range, _, anchor) in multi_buffer
20645                        .snapshot(cx)
20646                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20647                    {
20648                        if let Some(anchor) = anchor {
20649                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20650                            else {
20651                                continue;
20652                            };
20653                            let offset = text::ToOffset::to_offset(
20654                                &anchor.text_anchor,
20655                                &buffer_handle.read(cx).snapshot(),
20656                            );
20657                            let range = offset..offset;
20658                            new_selections_by_buffer
20659                                .entry(buffer_handle)
20660                                .or_insert((Vec::new(), None))
20661                                .0
20662                                .push(range)
20663                        } else {
20664                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20665                            else {
20666                                continue;
20667                            };
20668                            new_selections_by_buffer
20669                                .entry(buffer_handle)
20670                                .or_insert((Vec::new(), None))
20671                                .0
20672                                .push(range)
20673                        }
20674                    }
20675                }
20676            }
20677        }
20678
20679        new_selections_by_buffer
20680            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20681
20682        if new_selections_by_buffer.is_empty() {
20683            return;
20684        }
20685
20686        // We defer the pane interaction because we ourselves are a workspace item
20687        // and activating a new item causes the pane to call a method on us reentrantly,
20688        // which panics if we're on the stack.
20689        window.defer(cx, move |window, cx| {
20690            workspace.update(cx, |workspace, cx| {
20691                let pane = if split {
20692                    workspace.adjacent_pane(window, cx)
20693                } else {
20694                    workspace.active_pane().clone()
20695                };
20696
20697                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20698                    let editor = buffer
20699                        .read(cx)
20700                        .file()
20701                        .is_none()
20702                        .then(|| {
20703                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20704                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20705                            // Instead, we try to activate the existing editor in the pane first.
20706                            let (editor, pane_item_index) =
20707                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20708                                    let editor = item.downcast::<Editor>()?;
20709                                    let singleton_buffer =
20710                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20711                                    if singleton_buffer == buffer {
20712                                        Some((editor, i))
20713                                    } else {
20714                                        None
20715                                    }
20716                                })?;
20717                            pane.update(cx, |pane, cx| {
20718                                pane.activate_item(pane_item_index, true, true, window, cx)
20719                            });
20720                            Some(editor)
20721                        })
20722                        .flatten()
20723                        .unwrap_or_else(|| {
20724                            workspace.open_project_item::<Self>(
20725                                pane.clone(),
20726                                buffer,
20727                                true,
20728                                true,
20729                                window,
20730                                cx,
20731                            )
20732                        });
20733
20734                    editor.update(cx, |editor, cx| {
20735                        let autoscroll = match scroll_offset {
20736                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20737                            None => Autoscroll::newest(),
20738                        };
20739                        let nav_history = editor.nav_history.take();
20740                        editor.change_selections(
20741                            SelectionEffects::scroll(autoscroll),
20742                            window,
20743                            cx,
20744                            |s| {
20745                                s.select_ranges(ranges);
20746                            },
20747                        );
20748                        editor.nav_history = nav_history;
20749                    });
20750                }
20751            })
20752        });
20753    }
20754
20755    // For now, don't allow opening excerpts in buffers that aren't backed by
20756    // regular project files.
20757    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20758        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20759    }
20760
20761    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20762        let snapshot = self.buffer.read(cx).read(cx);
20763        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20764        Some(
20765            ranges
20766                .iter()
20767                .map(move |range| {
20768                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20769                })
20770                .collect(),
20771        )
20772    }
20773
20774    fn selection_replacement_ranges(
20775        &self,
20776        range: Range<OffsetUtf16>,
20777        cx: &mut App,
20778    ) -> Vec<Range<OffsetUtf16>> {
20779        let selections = self.selections.all::<OffsetUtf16>(cx);
20780        let newest_selection = selections
20781            .iter()
20782            .max_by_key(|selection| selection.id)
20783            .unwrap();
20784        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20785        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20786        let snapshot = self.buffer.read(cx).read(cx);
20787        selections
20788            .into_iter()
20789            .map(|mut selection| {
20790                selection.start.0 =
20791                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20792                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20793                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20794                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20795            })
20796            .collect()
20797    }
20798
20799    fn report_editor_event(
20800        &self,
20801        reported_event: ReportEditorEvent,
20802        file_extension: Option<String>,
20803        cx: &App,
20804    ) {
20805        if cfg!(any(test, feature = "test-support")) {
20806            return;
20807        }
20808
20809        let Some(project) = &self.project else { return };
20810
20811        // If None, we are in a file without an extension
20812        let file = self
20813            .buffer
20814            .read(cx)
20815            .as_singleton()
20816            .and_then(|b| b.read(cx).file());
20817        let file_extension = file_extension.or(file
20818            .as_ref()
20819            .and_then(|file| Path::new(file.file_name(cx)).extension())
20820            .and_then(|e| e.to_str())
20821            .map(|a| a.to_string()));
20822
20823        let vim_mode = vim_enabled(cx);
20824
20825        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20826        let copilot_enabled = edit_predictions_provider
20827            == language::language_settings::EditPredictionProvider::Copilot;
20828        let copilot_enabled_for_language = self
20829            .buffer
20830            .read(cx)
20831            .language_settings(cx)
20832            .show_edit_predictions;
20833
20834        let project = project.read(cx);
20835        let event_type = reported_event.event_type();
20836
20837        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20838            telemetry::event!(
20839                event_type,
20840                type = if auto_saved {"autosave"} else {"manual"},
20841                file_extension,
20842                vim_mode,
20843                copilot_enabled,
20844                copilot_enabled_for_language,
20845                edit_predictions_provider,
20846                is_via_ssh = project.is_via_remote_server(),
20847            );
20848        } else {
20849            telemetry::event!(
20850                event_type,
20851                file_extension,
20852                vim_mode,
20853                copilot_enabled,
20854                copilot_enabled_for_language,
20855                edit_predictions_provider,
20856                is_via_ssh = project.is_via_remote_server(),
20857            );
20858        };
20859    }
20860
20861    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20862    /// with each line being an array of {text, highlight} objects.
20863    fn copy_highlight_json(
20864        &mut self,
20865        _: &CopyHighlightJson,
20866        window: &mut Window,
20867        cx: &mut Context<Self>,
20868    ) {
20869        #[derive(Serialize)]
20870        struct Chunk<'a> {
20871            text: String,
20872            highlight: Option<&'a str>,
20873        }
20874
20875        let snapshot = self.buffer.read(cx).snapshot(cx);
20876        let range = self
20877            .selected_text_range(false, window, cx)
20878            .and_then(|selection| {
20879                if selection.range.is_empty() {
20880                    None
20881                } else {
20882                    Some(selection.range)
20883                }
20884            })
20885            .unwrap_or_else(|| 0..snapshot.len());
20886
20887        let chunks = snapshot.chunks(range, true);
20888        let mut lines = Vec::new();
20889        let mut line: VecDeque<Chunk> = VecDeque::new();
20890
20891        let Some(style) = self.style.as_ref() else {
20892            return;
20893        };
20894
20895        for chunk in chunks {
20896            let highlight = chunk
20897                .syntax_highlight_id
20898                .and_then(|id| id.name(&style.syntax));
20899            let mut chunk_lines = chunk.text.split('\n').peekable();
20900            while let Some(text) = chunk_lines.next() {
20901                let mut merged_with_last_token = false;
20902                if let Some(last_token) = line.back_mut()
20903                    && last_token.highlight == highlight
20904                {
20905                    last_token.text.push_str(text);
20906                    merged_with_last_token = true;
20907                }
20908
20909                if !merged_with_last_token {
20910                    line.push_back(Chunk {
20911                        text: text.into(),
20912                        highlight,
20913                    });
20914                }
20915
20916                if chunk_lines.peek().is_some() {
20917                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20918                        line.pop_front();
20919                    }
20920                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20921                        line.pop_back();
20922                    }
20923
20924                    lines.push(mem::take(&mut line));
20925                }
20926            }
20927        }
20928
20929        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20930            return;
20931        };
20932        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20933    }
20934
20935    pub fn open_context_menu(
20936        &mut self,
20937        _: &OpenContextMenu,
20938        window: &mut Window,
20939        cx: &mut Context<Self>,
20940    ) {
20941        self.request_autoscroll(Autoscroll::newest(), cx);
20942        let position = self.selections.newest_display(cx).start;
20943        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20944    }
20945
20946    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20947        &self.inlay_hint_cache
20948    }
20949
20950    pub fn replay_insert_event(
20951        &mut self,
20952        text: &str,
20953        relative_utf16_range: Option<Range<isize>>,
20954        window: &mut Window,
20955        cx: &mut Context<Self>,
20956    ) {
20957        if !self.input_enabled {
20958            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20959            return;
20960        }
20961        if let Some(relative_utf16_range) = relative_utf16_range {
20962            let selections = self.selections.all::<OffsetUtf16>(cx);
20963            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20964                let new_ranges = selections.into_iter().map(|range| {
20965                    let start = OffsetUtf16(
20966                        range
20967                            .head()
20968                            .0
20969                            .saturating_add_signed(relative_utf16_range.start),
20970                    );
20971                    let end = OffsetUtf16(
20972                        range
20973                            .head()
20974                            .0
20975                            .saturating_add_signed(relative_utf16_range.end),
20976                    );
20977                    start..end
20978                });
20979                s.select_ranges(new_ranges);
20980            });
20981        }
20982
20983        self.handle_input(text, window, cx);
20984    }
20985
20986    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20987        let Some(provider) = self.semantics_provider.as_ref() else {
20988            return false;
20989        };
20990
20991        let mut supports = false;
20992        self.buffer().update(cx, |this, cx| {
20993            this.for_each_buffer(|buffer| {
20994                supports |= provider.supports_inlay_hints(buffer, cx);
20995            });
20996        });
20997
20998        supports
20999    }
21000
21001    pub fn is_focused(&self, window: &Window) -> bool {
21002        self.focus_handle.is_focused(window)
21003    }
21004
21005    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21006        cx.emit(EditorEvent::Focused);
21007
21008        if let Some(descendant) = self
21009            .last_focused_descendant
21010            .take()
21011            .and_then(|descendant| descendant.upgrade())
21012        {
21013            window.focus(&descendant);
21014        } else {
21015            if let Some(blame) = self.blame.as_ref() {
21016                blame.update(cx, GitBlame::focus)
21017            }
21018
21019            self.blink_manager.update(cx, BlinkManager::enable);
21020            self.show_cursor_names(window, cx);
21021            self.buffer.update(cx, |buffer, cx| {
21022                buffer.finalize_last_transaction(cx);
21023                if self.leader_id.is_none() {
21024                    buffer.set_active_selections(
21025                        &self.selections.disjoint_anchors(),
21026                        self.selections.line_mode,
21027                        self.cursor_shape,
21028                        cx,
21029                    );
21030                }
21031            });
21032        }
21033    }
21034
21035    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21036        cx.emit(EditorEvent::FocusedIn)
21037    }
21038
21039    fn handle_focus_out(
21040        &mut self,
21041        event: FocusOutEvent,
21042        _window: &mut Window,
21043        cx: &mut Context<Self>,
21044    ) {
21045        if event.blurred != self.focus_handle {
21046            self.last_focused_descendant = Some(event.blurred);
21047        }
21048        self.selection_drag_state = SelectionDragState::None;
21049        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21050    }
21051
21052    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21053        self.blink_manager.update(cx, BlinkManager::disable);
21054        self.buffer
21055            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21056
21057        if let Some(blame) = self.blame.as_ref() {
21058            blame.update(cx, GitBlame::blur)
21059        }
21060        if !self.hover_state.focused(window, cx) {
21061            hide_hover(self, cx);
21062        }
21063        if !self
21064            .context_menu
21065            .borrow()
21066            .as_ref()
21067            .is_some_and(|context_menu| context_menu.focused(window, cx))
21068        {
21069            self.hide_context_menu(window, cx);
21070        }
21071        self.discard_edit_prediction(false, cx);
21072        cx.emit(EditorEvent::Blurred);
21073        cx.notify();
21074    }
21075
21076    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21077        let mut pending: String = window
21078            .pending_input_keystrokes()
21079            .into_iter()
21080            .flatten()
21081            .filter_map(|keystroke| {
21082                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21083                    keystroke.key_char.clone()
21084                } else {
21085                    None
21086                }
21087            })
21088            .collect();
21089
21090        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21091            pending = "".to_string();
21092        }
21093
21094        let existing_pending = self
21095            .text_highlights::<PendingInput>(cx)
21096            .map(|(_, ranges)| ranges.to_vec());
21097        if existing_pending.is_none() && pending.is_empty() {
21098            return;
21099        }
21100        let transaction =
21101            self.transact(window, cx, |this, window, cx| {
21102                let selections = this.selections.all::<usize>(cx);
21103                let edits = selections
21104                    .iter()
21105                    .map(|selection| (selection.end..selection.end, pending.clone()));
21106                this.edit(edits, cx);
21107                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21108                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21109                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21110                    }));
21111                });
21112                if let Some(existing_ranges) = existing_pending {
21113                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21114                    this.edit(edits, cx);
21115                }
21116            });
21117
21118        let snapshot = self.snapshot(window, cx);
21119        let ranges = self
21120            .selections
21121            .all::<usize>(cx)
21122            .into_iter()
21123            .map(|selection| {
21124                snapshot.buffer_snapshot.anchor_after(selection.end)
21125                    ..snapshot
21126                        .buffer_snapshot
21127                        .anchor_before(selection.end + pending.len())
21128            })
21129            .collect();
21130
21131        if pending.is_empty() {
21132            self.clear_highlights::<PendingInput>(cx);
21133        } else {
21134            self.highlight_text::<PendingInput>(
21135                ranges,
21136                HighlightStyle {
21137                    underline: Some(UnderlineStyle {
21138                        thickness: px(1.),
21139                        color: None,
21140                        wavy: false,
21141                    }),
21142                    ..Default::default()
21143                },
21144                cx,
21145            );
21146        }
21147
21148        self.ime_transaction = self.ime_transaction.or(transaction);
21149        if let Some(transaction) = self.ime_transaction {
21150            self.buffer.update(cx, |buffer, cx| {
21151                buffer.group_until_transaction(transaction, cx);
21152            });
21153        }
21154
21155        if self.text_highlights::<PendingInput>(cx).is_none() {
21156            self.ime_transaction.take();
21157        }
21158    }
21159
21160    pub fn register_action_renderer(
21161        &mut self,
21162        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21163    ) -> Subscription {
21164        let id = self.next_editor_action_id.post_inc();
21165        self.editor_actions
21166            .borrow_mut()
21167            .insert(id, Box::new(listener));
21168
21169        let editor_actions = self.editor_actions.clone();
21170        Subscription::new(move || {
21171            editor_actions.borrow_mut().remove(&id);
21172        })
21173    }
21174
21175    pub fn register_action<A: Action>(
21176        &mut self,
21177        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21178    ) -> Subscription {
21179        let id = self.next_editor_action_id.post_inc();
21180        let listener = Arc::new(listener);
21181        self.editor_actions.borrow_mut().insert(
21182            id,
21183            Box::new(move |_, window, _| {
21184                let listener = listener.clone();
21185                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21186                    let action = action.downcast_ref().unwrap();
21187                    if phase == DispatchPhase::Bubble {
21188                        listener(action, window, cx)
21189                    }
21190                })
21191            }),
21192        );
21193
21194        let editor_actions = self.editor_actions.clone();
21195        Subscription::new(move || {
21196            editor_actions.borrow_mut().remove(&id);
21197        })
21198    }
21199
21200    pub fn file_header_size(&self) -> u32 {
21201        FILE_HEADER_HEIGHT
21202    }
21203
21204    pub fn restore(
21205        &mut self,
21206        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21207        window: &mut Window,
21208        cx: &mut Context<Self>,
21209    ) {
21210        let workspace = self.workspace();
21211        let project = self.project();
21212        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21213            let mut tasks = Vec::new();
21214            for (buffer_id, changes) in revert_changes {
21215                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21216                    buffer.update(cx, |buffer, cx| {
21217                        buffer.edit(
21218                            changes
21219                                .into_iter()
21220                                .map(|(range, text)| (range, text.to_string())),
21221                            None,
21222                            cx,
21223                        );
21224                    });
21225
21226                    if let Some(project) =
21227                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21228                    {
21229                        project.update(cx, |project, cx| {
21230                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21231                        })
21232                    }
21233                }
21234            }
21235            tasks
21236        });
21237        cx.spawn_in(window, async move |_, cx| {
21238            for (buffer, task) in save_tasks {
21239                let result = task.await;
21240                if result.is_err() {
21241                    let Some(path) = buffer
21242                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21243                        .ok()
21244                    else {
21245                        continue;
21246                    };
21247                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21248                        let Some(task) = cx
21249                            .update_window_entity(workspace, |workspace, window, cx| {
21250                                workspace
21251                                    .open_path_preview(path, None, false, false, false, window, cx)
21252                            })
21253                            .ok()
21254                        else {
21255                            continue;
21256                        };
21257                        task.await.log_err();
21258                    }
21259                }
21260            }
21261        })
21262        .detach();
21263        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21264            selections.refresh()
21265        });
21266    }
21267
21268    pub fn to_pixel_point(
21269        &self,
21270        source: multi_buffer::Anchor,
21271        editor_snapshot: &EditorSnapshot,
21272        window: &mut Window,
21273    ) -> Option<gpui::Point<Pixels>> {
21274        let source_point = source.to_display_point(editor_snapshot);
21275        self.display_to_pixel_point(source_point, editor_snapshot, window)
21276    }
21277
21278    pub fn display_to_pixel_point(
21279        &self,
21280        source: DisplayPoint,
21281        editor_snapshot: &EditorSnapshot,
21282        window: &mut Window,
21283    ) -> Option<gpui::Point<Pixels>> {
21284        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21285        let text_layout_details = self.text_layout_details(window);
21286        let scroll_top = text_layout_details
21287            .scroll_anchor
21288            .scroll_position(editor_snapshot)
21289            .y;
21290
21291        if source.row().as_f32() < scroll_top.floor() {
21292            return None;
21293        }
21294        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21295        let source_y = line_height * (source.row().as_f32() - scroll_top);
21296        Some(gpui::Point::new(source_x, source_y))
21297    }
21298
21299    pub fn has_visible_completions_menu(&self) -> bool {
21300        !self.edit_prediction_preview_is_active()
21301            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21302                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21303            })
21304    }
21305
21306    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21307        if self.mode.is_minimap() {
21308            return;
21309        }
21310        self.addons
21311            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21312    }
21313
21314    pub fn unregister_addon<T: Addon>(&mut self) {
21315        self.addons.remove(&std::any::TypeId::of::<T>());
21316    }
21317
21318    pub fn addon<T: Addon>(&self) -> Option<&T> {
21319        let type_id = std::any::TypeId::of::<T>();
21320        self.addons
21321            .get(&type_id)
21322            .and_then(|item| item.to_any().downcast_ref::<T>())
21323    }
21324
21325    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21326        let type_id = std::any::TypeId::of::<T>();
21327        self.addons
21328            .get_mut(&type_id)
21329            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21330    }
21331
21332    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21333        let text_layout_details = self.text_layout_details(window);
21334        let style = &text_layout_details.editor_style;
21335        let font_id = window.text_system().resolve_font(&style.text.font());
21336        let font_size = style.text.font_size.to_pixels(window.rem_size());
21337        let line_height = style.text.line_height_in_pixels(window.rem_size());
21338        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21339        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21340
21341        CharacterDimensions {
21342            em_width,
21343            em_advance,
21344            line_height,
21345        }
21346    }
21347
21348    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21349        self.load_diff_task.clone()
21350    }
21351
21352    fn read_metadata_from_db(
21353        &mut self,
21354        item_id: u64,
21355        workspace_id: WorkspaceId,
21356        window: &mut Window,
21357        cx: &mut Context<Editor>,
21358    ) {
21359        if self.is_singleton(cx)
21360            && !self.mode.is_minimap()
21361            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21362        {
21363            let buffer_snapshot = OnceCell::new();
21364
21365            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21366                && !folds.is_empty()
21367            {
21368                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21369                self.fold_ranges(
21370                    folds
21371                        .into_iter()
21372                        .map(|(start, end)| {
21373                            snapshot.clip_offset(start, Bias::Left)
21374                                ..snapshot.clip_offset(end, Bias::Right)
21375                        })
21376                        .collect(),
21377                    false,
21378                    window,
21379                    cx,
21380                );
21381            }
21382
21383            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21384                && !selections.is_empty()
21385            {
21386                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21387                // skip adding the initial selection to selection history
21388                self.selection_history.mode = SelectionHistoryMode::Skipping;
21389                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21390                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21391                        snapshot.clip_offset(start, Bias::Left)
21392                            ..snapshot.clip_offset(end, Bias::Right)
21393                    }));
21394                });
21395                self.selection_history.mode = SelectionHistoryMode::Normal;
21396            };
21397        }
21398
21399        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21400    }
21401
21402    fn update_lsp_data(
21403        &mut self,
21404        ignore_cache: bool,
21405        for_buffer: Option<BufferId>,
21406        window: &mut Window,
21407        cx: &mut Context<'_, Self>,
21408    ) {
21409        self.pull_diagnostics(for_buffer, window, cx);
21410        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21411    }
21412}
21413
21414fn vim_enabled(cx: &App) -> bool {
21415    cx.global::<SettingsStore>()
21416        .raw_user_settings()
21417        .get("vim_mode")
21418        == Some(&serde_json::Value::Bool(true))
21419}
21420
21421fn process_completion_for_edit(
21422    completion: &Completion,
21423    intent: CompletionIntent,
21424    buffer: &Entity<Buffer>,
21425    cursor_position: &text::Anchor,
21426    cx: &mut Context<Editor>,
21427) -> CompletionEdit {
21428    let buffer = buffer.read(cx);
21429    let buffer_snapshot = buffer.snapshot();
21430    let (snippet, new_text) = if completion.is_snippet() {
21431        // Workaround for typescript language server issues so that methods don't expand within
21432        // strings and functions with type expressions. The previous point is used because the query
21433        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21434        let mut snippet_source = completion.new_text.clone();
21435        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21436        previous_point.column = previous_point.column.saturating_sub(1);
21437        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21438            && scope.prefers_label_for_snippet_in_completion()
21439            && let Some(label) = completion.label()
21440            && matches!(
21441                completion.kind(),
21442                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21443            )
21444        {
21445            snippet_source = label;
21446        }
21447        match Snippet::parse(&snippet_source).log_err() {
21448            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21449            None => (None, completion.new_text.clone()),
21450        }
21451    } else {
21452        (None, completion.new_text.clone())
21453    };
21454
21455    let mut range_to_replace = {
21456        let replace_range = &completion.replace_range;
21457        if let CompletionSource::Lsp {
21458            insert_range: Some(insert_range),
21459            ..
21460        } = &completion.source
21461        {
21462            debug_assert_eq!(
21463                insert_range.start, replace_range.start,
21464                "insert_range and replace_range should start at the same position"
21465            );
21466            debug_assert!(
21467                insert_range
21468                    .start
21469                    .cmp(cursor_position, &buffer_snapshot)
21470                    .is_le(),
21471                "insert_range should start before or at cursor position"
21472            );
21473            debug_assert!(
21474                replace_range
21475                    .start
21476                    .cmp(cursor_position, &buffer_snapshot)
21477                    .is_le(),
21478                "replace_range should start before or at cursor position"
21479            );
21480
21481            let should_replace = match intent {
21482                CompletionIntent::CompleteWithInsert => false,
21483                CompletionIntent::CompleteWithReplace => true,
21484                CompletionIntent::Complete | CompletionIntent::Compose => {
21485                    let insert_mode =
21486                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21487                            .completions
21488                            .lsp_insert_mode;
21489                    match insert_mode {
21490                        LspInsertMode::Insert => false,
21491                        LspInsertMode::Replace => true,
21492                        LspInsertMode::ReplaceSubsequence => {
21493                            let mut text_to_replace = buffer.chars_for_range(
21494                                buffer.anchor_before(replace_range.start)
21495                                    ..buffer.anchor_after(replace_range.end),
21496                            );
21497                            let mut current_needle = text_to_replace.next();
21498                            for haystack_ch in completion.label.text.chars() {
21499                                if let Some(needle_ch) = current_needle
21500                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21501                                {
21502                                    current_needle = text_to_replace.next();
21503                                }
21504                            }
21505                            current_needle.is_none()
21506                        }
21507                        LspInsertMode::ReplaceSuffix => {
21508                            if replace_range
21509                                .end
21510                                .cmp(cursor_position, &buffer_snapshot)
21511                                .is_gt()
21512                            {
21513                                let range_after_cursor = *cursor_position..replace_range.end;
21514                                let text_after_cursor = buffer
21515                                    .text_for_range(
21516                                        buffer.anchor_before(range_after_cursor.start)
21517                                            ..buffer.anchor_after(range_after_cursor.end),
21518                                    )
21519                                    .collect::<String>()
21520                                    .to_ascii_lowercase();
21521                                completion
21522                                    .label
21523                                    .text
21524                                    .to_ascii_lowercase()
21525                                    .ends_with(&text_after_cursor)
21526                            } else {
21527                                true
21528                            }
21529                        }
21530                    }
21531                }
21532            };
21533
21534            if should_replace {
21535                replace_range.clone()
21536            } else {
21537                insert_range.clone()
21538            }
21539        } else {
21540            replace_range.clone()
21541        }
21542    };
21543
21544    if range_to_replace
21545        .end
21546        .cmp(cursor_position, &buffer_snapshot)
21547        .is_lt()
21548    {
21549        range_to_replace.end = *cursor_position;
21550    }
21551
21552    CompletionEdit {
21553        new_text,
21554        replace_range: range_to_replace.to_offset(buffer),
21555        snippet,
21556    }
21557}
21558
21559struct CompletionEdit {
21560    new_text: String,
21561    replace_range: Range<usize>,
21562    snippet: Option<Snippet>,
21563}
21564
21565fn insert_extra_newline_brackets(
21566    buffer: &MultiBufferSnapshot,
21567    range: Range<usize>,
21568    language: &language::LanguageScope,
21569) -> bool {
21570    let leading_whitespace_len = buffer
21571        .reversed_chars_at(range.start)
21572        .take_while(|c| c.is_whitespace() && *c != '\n')
21573        .map(|c| c.len_utf8())
21574        .sum::<usize>();
21575    let trailing_whitespace_len = buffer
21576        .chars_at(range.end)
21577        .take_while(|c| c.is_whitespace() && *c != '\n')
21578        .map(|c| c.len_utf8())
21579        .sum::<usize>();
21580    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21581
21582    language.brackets().any(|(pair, enabled)| {
21583        let pair_start = pair.start.trim_end();
21584        let pair_end = pair.end.trim_start();
21585
21586        enabled
21587            && pair.newline
21588            && buffer.contains_str_at(range.end, pair_end)
21589            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21590    })
21591}
21592
21593fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21594    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21595        [(buffer, range, _)] => (*buffer, range.clone()),
21596        _ => return false,
21597    };
21598    let pair = {
21599        let mut result: Option<BracketMatch> = None;
21600
21601        for pair in buffer
21602            .all_bracket_ranges(range.clone())
21603            .filter(move |pair| {
21604                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21605            })
21606        {
21607            let len = pair.close_range.end - pair.open_range.start;
21608
21609            if let Some(existing) = &result {
21610                let existing_len = existing.close_range.end - existing.open_range.start;
21611                if len > existing_len {
21612                    continue;
21613                }
21614            }
21615
21616            result = Some(pair);
21617        }
21618
21619        result
21620    };
21621    let Some(pair) = pair else {
21622        return false;
21623    };
21624    pair.newline_only
21625        && buffer
21626            .chars_for_range(pair.open_range.end..range.start)
21627            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21628            .all(|c| c.is_whitespace() && c != '\n')
21629}
21630
21631fn update_uncommitted_diff_for_buffer(
21632    editor: Entity<Editor>,
21633    project: &Entity<Project>,
21634    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21635    buffer: Entity<MultiBuffer>,
21636    cx: &mut App,
21637) -> Task<()> {
21638    let mut tasks = Vec::new();
21639    project.update(cx, |project, cx| {
21640        for buffer in buffers {
21641            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21642                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21643            }
21644        }
21645    });
21646    cx.spawn(async move |cx| {
21647        let diffs = future::join_all(tasks).await;
21648        if editor
21649            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21650            .unwrap_or(false)
21651        {
21652            return;
21653        }
21654
21655        buffer
21656            .update(cx, |buffer, cx| {
21657                for diff in diffs.into_iter().flatten() {
21658                    buffer.add_diff(diff, cx);
21659                }
21660            })
21661            .ok();
21662    })
21663}
21664
21665fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21666    let tab_size = tab_size.get() as usize;
21667    let mut width = offset;
21668
21669    for ch in text.chars() {
21670        width += if ch == '\t' {
21671            tab_size - (width % tab_size)
21672        } else {
21673            1
21674        };
21675    }
21676
21677    width - offset
21678}
21679
21680#[cfg(test)]
21681mod tests {
21682    use super::*;
21683
21684    #[test]
21685    fn test_string_size_with_expanded_tabs() {
21686        let nz = |val| NonZeroU32::new(val).unwrap();
21687        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21688        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21689        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21690        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21691        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21692        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21693        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21694        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21695    }
21696}
21697
21698/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21699struct WordBreakingTokenizer<'a> {
21700    input: &'a str,
21701}
21702
21703impl<'a> WordBreakingTokenizer<'a> {
21704    fn new(input: &'a str) -> Self {
21705        Self { input }
21706    }
21707}
21708
21709fn is_char_ideographic(ch: char) -> bool {
21710    use unicode_script::Script::*;
21711    use unicode_script::UnicodeScript;
21712    matches!(ch.script(), Han | Tangut | Yi)
21713}
21714
21715fn is_grapheme_ideographic(text: &str) -> bool {
21716    text.chars().any(is_char_ideographic)
21717}
21718
21719fn is_grapheme_whitespace(text: &str) -> bool {
21720    text.chars().any(|x| x.is_whitespace())
21721}
21722
21723fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21724    text.chars()
21725        .next()
21726        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21727}
21728
21729#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21730enum WordBreakToken<'a> {
21731    Word { token: &'a str, grapheme_len: usize },
21732    InlineWhitespace { token: &'a str, grapheme_len: usize },
21733    Newline,
21734}
21735
21736impl<'a> Iterator for WordBreakingTokenizer<'a> {
21737    /// Yields a span, the count of graphemes in the token, and whether it was
21738    /// whitespace. Note that it also breaks at word boundaries.
21739    type Item = WordBreakToken<'a>;
21740
21741    fn next(&mut self) -> Option<Self::Item> {
21742        use unicode_segmentation::UnicodeSegmentation;
21743        if self.input.is_empty() {
21744            return None;
21745        }
21746
21747        let mut iter = self.input.graphemes(true).peekable();
21748        let mut offset = 0;
21749        let mut grapheme_len = 0;
21750        if let Some(first_grapheme) = iter.next() {
21751            let is_newline = first_grapheme == "\n";
21752            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21753            offset += first_grapheme.len();
21754            grapheme_len += 1;
21755            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21756                if let Some(grapheme) = iter.peek().copied()
21757                    && should_stay_with_preceding_ideograph(grapheme)
21758                {
21759                    offset += grapheme.len();
21760                    grapheme_len += 1;
21761                }
21762            } else {
21763                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21764                let mut next_word_bound = words.peek().copied();
21765                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21766                    next_word_bound = words.next();
21767                }
21768                while let Some(grapheme) = iter.peek().copied() {
21769                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21770                        break;
21771                    };
21772                    if is_grapheme_whitespace(grapheme) != is_whitespace
21773                        || (grapheme == "\n") != is_newline
21774                    {
21775                        break;
21776                    };
21777                    offset += grapheme.len();
21778                    grapheme_len += 1;
21779                    iter.next();
21780                }
21781            }
21782            let token = &self.input[..offset];
21783            self.input = &self.input[offset..];
21784            if token == "\n" {
21785                Some(WordBreakToken::Newline)
21786            } else if is_whitespace {
21787                Some(WordBreakToken::InlineWhitespace {
21788                    token,
21789                    grapheme_len,
21790                })
21791            } else {
21792                Some(WordBreakToken::Word {
21793                    token,
21794                    grapheme_len,
21795                })
21796            }
21797        } else {
21798            None
21799        }
21800    }
21801}
21802
21803#[test]
21804fn test_word_breaking_tokenizer() {
21805    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21806        ("", &[]),
21807        ("  ", &[whitespace("  ", 2)]),
21808        ("Ʒ", &[word("Ʒ", 1)]),
21809        ("Ǽ", &[word("Ǽ", 1)]),
21810        ("", &[word("", 1)]),
21811        ("⋑⋑", &[word("⋑⋑", 2)]),
21812        (
21813            "原理,进而",
21814            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21815        ),
21816        (
21817            "hello world",
21818            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21819        ),
21820        (
21821            "hello, world",
21822            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21823        ),
21824        (
21825            "  hello world",
21826            &[
21827                whitespace("  ", 2),
21828                word("hello", 5),
21829                whitespace(" ", 1),
21830                word("world", 5),
21831            ],
21832        ),
21833        (
21834            "这是什么 \n 钢笔",
21835            &[
21836                word("", 1),
21837                word("", 1),
21838                word("", 1),
21839                word("", 1),
21840                whitespace(" ", 1),
21841                newline(),
21842                whitespace(" ", 1),
21843                word("", 1),
21844                word("", 1),
21845            ],
21846        ),
21847        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21848    ];
21849
21850    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21851        WordBreakToken::Word {
21852            token,
21853            grapheme_len,
21854        }
21855    }
21856
21857    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21858        WordBreakToken::InlineWhitespace {
21859            token,
21860            grapheme_len,
21861        }
21862    }
21863
21864    fn newline() -> WordBreakToken<'static> {
21865        WordBreakToken::Newline
21866    }
21867
21868    for (input, result) in tests {
21869        assert_eq!(
21870            WordBreakingTokenizer::new(input)
21871                .collect::<Vec<_>>()
21872                .as_slice(),
21873            *result,
21874        );
21875    }
21876}
21877
21878fn wrap_with_prefix(
21879    first_line_prefix: String,
21880    subsequent_lines_prefix: String,
21881    unwrapped_text: String,
21882    wrap_column: usize,
21883    tab_size: NonZeroU32,
21884    preserve_existing_whitespace: bool,
21885) -> String {
21886    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21887    let subsequent_lines_prefix_len =
21888        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21889    let mut wrapped_text = String::new();
21890    let mut current_line = first_line_prefix;
21891    let mut is_first_line = true;
21892
21893    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21894    let mut current_line_len = first_line_prefix_len;
21895    let mut in_whitespace = false;
21896    for token in tokenizer {
21897        let have_preceding_whitespace = in_whitespace;
21898        match token {
21899            WordBreakToken::Word {
21900                token,
21901                grapheme_len,
21902            } => {
21903                in_whitespace = false;
21904                let current_prefix_len = if is_first_line {
21905                    first_line_prefix_len
21906                } else {
21907                    subsequent_lines_prefix_len
21908                };
21909                if current_line_len + grapheme_len > wrap_column
21910                    && current_line_len != current_prefix_len
21911                {
21912                    wrapped_text.push_str(current_line.trim_end());
21913                    wrapped_text.push('\n');
21914                    is_first_line = false;
21915                    current_line = subsequent_lines_prefix.clone();
21916                    current_line_len = subsequent_lines_prefix_len;
21917                }
21918                current_line.push_str(token);
21919                current_line_len += grapheme_len;
21920            }
21921            WordBreakToken::InlineWhitespace {
21922                mut token,
21923                mut grapheme_len,
21924            } => {
21925                in_whitespace = true;
21926                if have_preceding_whitespace && !preserve_existing_whitespace {
21927                    continue;
21928                }
21929                if !preserve_existing_whitespace {
21930                    token = " ";
21931                    grapheme_len = 1;
21932                }
21933                let current_prefix_len = if is_first_line {
21934                    first_line_prefix_len
21935                } else {
21936                    subsequent_lines_prefix_len
21937                };
21938                if current_line_len + grapheme_len > wrap_column {
21939                    wrapped_text.push_str(current_line.trim_end());
21940                    wrapped_text.push('\n');
21941                    is_first_line = false;
21942                    current_line = subsequent_lines_prefix.clone();
21943                    current_line_len = subsequent_lines_prefix_len;
21944                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21945                    current_line.push_str(token);
21946                    current_line_len += grapheme_len;
21947                }
21948            }
21949            WordBreakToken::Newline => {
21950                in_whitespace = true;
21951                let current_prefix_len = if is_first_line {
21952                    first_line_prefix_len
21953                } else {
21954                    subsequent_lines_prefix_len
21955                };
21956                if preserve_existing_whitespace {
21957                    wrapped_text.push_str(current_line.trim_end());
21958                    wrapped_text.push('\n');
21959                    is_first_line = false;
21960                    current_line = subsequent_lines_prefix.clone();
21961                    current_line_len = subsequent_lines_prefix_len;
21962                } else if have_preceding_whitespace {
21963                    continue;
21964                } else if current_line_len + 1 > wrap_column
21965                    && current_line_len != current_prefix_len
21966                {
21967                    wrapped_text.push_str(current_line.trim_end());
21968                    wrapped_text.push('\n');
21969                    is_first_line = false;
21970                    current_line = subsequent_lines_prefix.clone();
21971                    current_line_len = subsequent_lines_prefix_len;
21972                } else if current_line_len != current_prefix_len {
21973                    current_line.push(' ');
21974                    current_line_len += 1;
21975                }
21976            }
21977        }
21978    }
21979
21980    if !current_line.is_empty() {
21981        wrapped_text.push_str(&current_line);
21982    }
21983    wrapped_text
21984}
21985
21986#[test]
21987fn test_wrap_with_prefix() {
21988    assert_eq!(
21989        wrap_with_prefix(
21990            "# ".to_string(),
21991            "# ".to_string(),
21992            "abcdefg".to_string(),
21993            4,
21994            NonZeroU32::new(4).unwrap(),
21995            false,
21996        ),
21997        "# abcdefg"
21998    );
21999    assert_eq!(
22000        wrap_with_prefix(
22001            "".to_string(),
22002            "".to_string(),
22003            "\thello world".to_string(),
22004            8,
22005            NonZeroU32::new(4).unwrap(),
22006            false,
22007        ),
22008        "hello\nworld"
22009    );
22010    assert_eq!(
22011        wrap_with_prefix(
22012            "// ".to_string(),
22013            "// ".to_string(),
22014            "xx \nyy zz aa bb cc".to_string(),
22015            12,
22016            NonZeroU32::new(4).unwrap(),
22017            false,
22018        ),
22019        "// xx yy zz\n// aa bb cc"
22020    );
22021    assert_eq!(
22022        wrap_with_prefix(
22023            String::new(),
22024            String::new(),
22025            "这是什么 \n 钢笔".to_string(),
22026            3,
22027            NonZeroU32::new(4).unwrap(),
22028            false,
22029        ),
22030        "这是什\n么 钢\n"
22031    );
22032}
22033
22034pub trait CollaborationHub {
22035    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22036    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22037    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22038}
22039
22040impl CollaborationHub for Entity<Project> {
22041    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22042        self.read(cx).collaborators()
22043    }
22044
22045    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22046        self.read(cx).user_store().read(cx).participant_indices()
22047    }
22048
22049    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22050        let this = self.read(cx);
22051        let user_ids = this.collaborators().values().map(|c| c.user_id);
22052        this.user_store().read(cx).participant_names(user_ids, cx)
22053    }
22054}
22055
22056pub trait SemanticsProvider {
22057    fn hover(
22058        &self,
22059        buffer: &Entity<Buffer>,
22060        position: text::Anchor,
22061        cx: &mut App,
22062    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22063
22064    fn inline_values(
22065        &self,
22066        buffer_handle: Entity<Buffer>,
22067        range: Range<text::Anchor>,
22068        cx: &mut App,
22069    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22070
22071    fn inlay_hints(
22072        &self,
22073        buffer_handle: Entity<Buffer>,
22074        range: Range<text::Anchor>,
22075        cx: &mut App,
22076    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22077
22078    fn resolve_inlay_hint(
22079        &self,
22080        hint: InlayHint,
22081        buffer_handle: Entity<Buffer>,
22082        server_id: LanguageServerId,
22083        cx: &mut App,
22084    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22085
22086    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22087
22088    fn document_highlights(
22089        &self,
22090        buffer: &Entity<Buffer>,
22091        position: text::Anchor,
22092        cx: &mut App,
22093    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22094
22095    fn definitions(
22096        &self,
22097        buffer: &Entity<Buffer>,
22098        position: text::Anchor,
22099        kind: GotoDefinitionKind,
22100        cx: &mut App,
22101    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22102
22103    fn range_for_rename(
22104        &self,
22105        buffer: &Entity<Buffer>,
22106        position: text::Anchor,
22107        cx: &mut App,
22108    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22109
22110    fn perform_rename(
22111        &self,
22112        buffer: &Entity<Buffer>,
22113        position: text::Anchor,
22114        new_name: String,
22115        cx: &mut App,
22116    ) -> Option<Task<Result<ProjectTransaction>>>;
22117}
22118
22119pub trait CompletionProvider {
22120    fn completions(
22121        &self,
22122        excerpt_id: ExcerptId,
22123        buffer: &Entity<Buffer>,
22124        buffer_position: text::Anchor,
22125        trigger: CompletionContext,
22126        window: &mut Window,
22127        cx: &mut Context<Editor>,
22128    ) -> Task<Result<Vec<CompletionResponse>>>;
22129
22130    fn resolve_completions(
22131        &self,
22132        _buffer: Entity<Buffer>,
22133        _completion_indices: Vec<usize>,
22134        _completions: Rc<RefCell<Box<[Completion]>>>,
22135        _cx: &mut Context<Editor>,
22136    ) -> Task<Result<bool>> {
22137        Task::ready(Ok(false))
22138    }
22139
22140    fn apply_additional_edits_for_completion(
22141        &self,
22142        _buffer: Entity<Buffer>,
22143        _completions: Rc<RefCell<Box<[Completion]>>>,
22144        _completion_index: usize,
22145        _push_to_history: bool,
22146        _cx: &mut Context<Editor>,
22147    ) -> Task<Result<Option<language::Transaction>>> {
22148        Task::ready(Ok(None))
22149    }
22150
22151    fn is_completion_trigger(
22152        &self,
22153        buffer: &Entity<Buffer>,
22154        position: language::Anchor,
22155        text: &str,
22156        trigger_in_words: bool,
22157        menu_is_open: bool,
22158        cx: &mut Context<Editor>,
22159    ) -> bool;
22160
22161    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22162
22163    fn sort_completions(&self) -> bool {
22164        true
22165    }
22166
22167    fn filter_completions(&self) -> bool {
22168        true
22169    }
22170}
22171
22172pub trait CodeActionProvider {
22173    fn id(&self) -> Arc<str>;
22174
22175    fn code_actions(
22176        &self,
22177        buffer: &Entity<Buffer>,
22178        range: Range<text::Anchor>,
22179        window: &mut Window,
22180        cx: &mut App,
22181    ) -> Task<Result<Vec<CodeAction>>>;
22182
22183    fn apply_code_action(
22184        &self,
22185        buffer_handle: Entity<Buffer>,
22186        action: CodeAction,
22187        excerpt_id: ExcerptId,
22188        push_to_history: bool,
22189        window: &mut Window,
22190        cx: &mut App,
22191    ) -> Task<Result<ProjectTransaction>>;
22192}
22193
22194impl CodeActionProvider for Entity<Project> {
22195    fn id(&self) -> Arc<str> {
22196        "project".into()
22197    }
22198
22199    fn code_actions(
22200        &self,
22201        buffer: &Entity<Buffer>,
22202        range: Range<text::Anchor>,
22203        _window: &mut Window,
22204        cx: &mut App,
22205    ) -> Task<Result<Vec<CodeAction>>> {
22206        self.update(cx, |project, cx| {
22207            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22208            let code_actions = project.code_actions(buffer, range, None, cx);
22209            cx.background_spawn(async move {
22210                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22211                Ok(code_lens_actions
22212                    .context("code lens fetch")?
22213                    .into_iter()
22214                    .flatten()
22215                    .chain(
22216                        code_actions
22217                            .context("code action fetch")?
22218                            .into_iter()
22219                            .flatten(),
22220                    )
22221                    .collect())
22222            })
22223        })
22224    }
22225
22226    fn apply_code_action(
22227        &self,
22228        buffer_handle: Entity<Buffer>,
22229        action: CodeAction,
22230        _excerpt_id: ExcerptId,
22231        push_to_history: bool,
22232        _window: &mut Window,
22233        cx: &mut App,
22234    ) -> Task<Result<ProjectTransaction>> {
22235        self.update(cx, |project, cx| {
22236            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22237        })
22238    }
22239}
22240
22241fn snippet_completions(
22242    project: &Project,
22243    buffer: &Entity<Buffer>,
22244    buffer_position: text::Anchor,
22245    cx: &mut App,
22246) -> Task<Result<CompletionResponse>> {
22247    let languages = buffer.read(cx).languages_at(buffer_position);
22248    let snippet_store = project.snippets().read(cx);
22249
22250    let scopes: Vec<_> = languages
22251        .iter()
22252        .filter_map(|language| {
22253            let language_name = language.lsp_id();
22254            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22255
22256            if snippets.is_empty() {
22257                None
22258            } else {
22259                Some((language.default_scope(), snippets))
22260            }
22261        })
22262        .collect();
22263
22264    if scopes.is_empty() {
22265        return Task::ready(Ok(CompletionResponse {
22266            completions: vec![],
22267            display_options: CompletionDisplayOptions::default(),
22268            is_incomplete: false,
22269        }));
22270    }
22271
22272    let snapshot = buffer.read(cx).text_snapshot();
22273    let chars: String = snapshot
22274        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22275        .collect();
22276    let executor = cx.background_executor().clone();
22277
22278    cx.background_spawn(async move {
22279        let mut is_incomplete = false;
22280        let mut completions: Vec<Completion> = Vec::new();
22281        for (scope, snippets) in scopes.into_iter() {
22282            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22283            let mut last_word = chars
22284                .chars()
22285                .take_while(|c| classifier.is_word(*c))
22286                .collect::<String>();
22287            last_word = last_word.chars().rev().collect();
22288
22289            if last_word.is_empty() {
22290                return Ok(CompletionResponse {
22291                    completions: vec![],
22292                    display_options: CompletionDisplayOptions::default(),
22293                    is_incomplete: true,
22294                });
22295            }
22296
22297            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22298            let to_lsp = |point: &text::Anchor| {
22299                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22300                point_to_lsp(end)
22301            };
22302            let lsp_end = to_lsp(&buffer_position);
22303
22304            let candidates = snippets
22305                .iter()
22306                .enumerate()
22307                .flat_map(|(ix, snippet)| {
22308                    snippet
22309                        .prefix
22310                        .iter()
22311                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22312                })
22313                .collect::<Vec<StringMatchCandidate>>();
22314
22315            const MAX_RESULTS: usize = 100;
22316            let mut matches = fuzzy::match_strings(
22317                &candidates,
22318                &last_word,
22319                last_word.chars().any(|c| c.is_uppercase()),
22320                true,
22321                MAX_RESULTS,
22322                &Default::default(),
22323                executor.clone(),
22324            )
22325            .await;
22326
22327            if matches.len() >= MAX_RESULTS {
22328                is_incomplete = true;
22329            }
22330
22331            // Remove all candidates where the query's start does not match the start of any word in the candidate
22332            if let Some(query_start) = last_word.chars().next() {
22333                matches.retain(|string_match| {
22334                    split_words(&string_match.string).any(|word| {
22335                        // Check that the first codepoint of the word as lowercase matches the first
22336                        // codepoint of the query as lowercase
22337                        word.chars()
22338                            .flat_map(|codepoint| codepoint.to_lowercase())
22339                            .zip(query_start.to_lowercase())
22340                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22341                    })
22342                });
22343            }
22344
22345            let matched_strings = matches
22346                .into_iter()
22347                .map(|m| m.string)
22348                .collect::<HashSet<_>>();
22349
22350            completions.extend(snippets.iter().filter_map(|snippet| {
22351                let matching_prefix = snippet
22352                    .prefix
22353                    .iter()
22354                    .find(|prefix| matched_strings.contains(*prefix))?;
22355                let start = as_offset - last_word.len();
22356                let start = snapshot.anchor_before(start);
22357                let range = start..buffer_position;
22358                let lsp_start = to_lsp(&start);
22359                let lsp_range = lsp::Range {
22360                    start: lsp_start,
22361                    end: lsp_end,
22362                };
22363                Some(Completion {
22364                    replace_range: range,
22365                    new_text: snippet.body.clone(),
22366                    source: CompletionSource::Lsp {
22367                        insert_range: None,
22368                        server_id: LanguageServerId(usize::MAX),
22369                        resolved: true,
22370                        lsp_completion: Box::new(lsp::CompletionItem {
22371                            label: snippet.prefix.first().unwrap().clone(),
22372                            kind: Some(CompletionItemKind::SNIPPET),
22373                            label_details: snippet.description.as_ref().map(|description| {
22374                                lsp::CompletionItemLabelDetails {
22375                                    detail: Some(description.clone()),
22376                                    description: None,
22377                                }
22378                            }),
22379                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22380                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22381                                lsp::InsertReplaceEdit {
22382                                    new_text: snippet.body.clone(),
22383                                    insert: lsp_range,
22384                                    replace: lsp_range,
22385                                },
22386                            )),
22387                            filter_text: Some(snippet.body.clone()),
22388                            sort_text: Some(char::MAX.to_string()),
22389                            ..lsp::CompletionItem::default()
22390                        }),
22391                        lsp_defaults: None,
22392                    },
22393                    label: CodeLabel {
22394                        text: matching_prefix.clone(),
22395                        runs: Vec::new(),
22396                        filter_range: 0..matching_prefix.len(),
22397                    },
22398                    icon_path: None,
22399                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22400                        single_line: snippet.name.clone().into(),
22401                        plain_text: snippet
22402                            .description
22403                            .clone()
22404                            .map(|description| description.into()),
22405                    }),
22406                    insert_text_mode: None,
22407                    confirm: None,
22408                })
22409            }))
22410        }
22411
22412        Ok(CompletionResponse {
22413            completions,
22414            display_options: CompletionDisplayOptions::default(),
22415            is_incomplete,
22416        })
22417    })
22418}
22419
22420impl CompletionProvider for Entity<Project> {
22421    fn completions(
22422        &self,
22423        _excerpt_id: ExcerptId,
22424        buffer: &Entity<Buffer>,
22425        buffer_position: text::Anchor,
22426        options: CompletionContext,
22427        _window: &mut Window,
22428        cx: &mut Context<Editor>,
22429    ) -> Task<Result<Vec<CompletionResponse>>> {
22430        self.update(cx, |project, cx| {
22431            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22432            let project_completions = project.completions(buffer, buffer_position, options, cx);
22433            cx.background_spawn(async move {
22434                let mut responses = project_completions.await?;
22435                let snippets = snippets.await?;
22436                if !snippets.completions.is_empty() {
22437                    responses.push(snippets);
22438                }
22439                Ok(responses)
22440            })
22441        })
22442    }
22443
22444    fn resolve_completions(
22445        &self,
22446        buffer: Entity<Buffer>,
22447        completion_indices: Vec<usize>,
22448        completions: Rc<RefCell<Box<[Completion]>>>,
22449        cx: &mut Context<Editor>,
22450    ) -> Task<Result<bool>> {
22451        self.update(cx, |project, cx| {
22452            project.lsp_store().update(cx, |lsp_store, cx| {
22453                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22454            })
22455        })
22456    }
22457
22458    fn apply_additional_edits_for_completion(
22459        &self,
22460        buffer: Entity<Buffer>,
22461        completions: Rc<RefCell<Box<[Completion]>>>,
22462        completion_index: usize,
22463        push_to_history: bool,
22464        cx: &mut Context<Editor>,
22465    ) -> Task<Result<Option<language::Transaction>>> {
22466        self.update(cx, |project, cx| {
22467            project.lsp_store().update(cx, |lsp_store, cx| {
22468                lsp_store.apply_additional_edits_for_completion(
22469                    buffer,
22470                    completions,
22471                    completion_index,
22472                    push_to_history,
22473                    cx,
22474                )
22475            })
22476        })
22477    }
22478
22479    fn is_completion_trigger(
22480        &self,
22481        buffer: &Entity<Buffer>,
22482        position: language::Anchor,
22483        text: &str,
22484        trigger_in_words: bool,
22485        menu_is_open: bool,
22486        cx: &mut Context<Editor>,
22487    ) -> bool {
22488        let mut chars = text.chars();
22489        let char = if let Some(char) = chars.next() {
22490            char
22491        } else {
22492            return false;
22493        };
22494        if chars.next().is_some() {
22495            return false;
22496        }
22497
22498        let buffer = buffer.read(cx);
22499        let snapshot = buffer.snapshot();
22500        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22501            return false;
22502        }
22503        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22504        if trigger_in_words && classifier.is_word(char) {
22505            return true;
22506        }
22507
22508        buffer.completion_triggers().contains(text)
22509    }
22510}
22511
22512impl SemanticsProvider for Entity<Project> {
22513    fn hover(
22514        &self,
22515        buffer: &Entity<Buffer>,
22516        position: text::Anchor,
22517        cx: &mut App,
22518    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22519        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22520    }
22521
22522    fn document_highlights(
22523        &self,
22524        buffer: &Entity<Buffer>,
22525        position: text::Anchor,
22526        cx: &mut App,
22527    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22528        Some(self.update(cx, |project, cx| {
22529            project.document_highlights(buffer, position, cx)
22530        }))
22531    }
22532
22533    fn definitions(
22534        &self,
22535        buffer: &Entity<Buffer>,
22536        position: text::Anchor,
22537        kind: GotoDefinitionKind,
22538        cx: &mut App,
22539    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22540        Some(self.update(cx, |project, cx| match kind {
22541            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22542            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22543            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22544            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22545        }))
22546    }
22547
22548    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22549        self.update(cx, |project, cx| {
22550            if project
22551                .active_debug_session(cx)
22552                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22553            {
22554                return true;
22555            }
22556
22557            buffer.update(cx, |buffer, cx| {
22558                project.any_language_server_supports_inlay_hints(buffer, cx)
22559            })
22560        })
22561    }
22562
22563    fn inline_values(
22564        &self,
22565        buffer_handle: Entity<Buffer>,
22566        range: Range<text::Anchor>,
22567        cx: &mut App,
22568    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22569        self.update(cx, |project, cx| {
22570            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22571
22572            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22573        })
22574    }
22575
22576    fn inlay_hints(
22577        &self,
22578        buffer_handle: Entity<Buffer>,
22579        range: Range<text::Anchor>,
22580        cx: &mut App,
22581    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22582        Some(self.update(cx, |project, cx| {
22583            project.inlay_hints(buffer_handle, range, cx)
22584        }))
22585    }
22586
22587    fn resolve_inlay_hint(
22588        &self,
22589        hint: InlayHint,
22590        buffer_handle: Entity<Buffer>,
22591        server_id: LanguageServerId,
22592        cx: &mut App,
22593    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22594        Some(self.update(cx, |project, cx| {
22595            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22596        }))
22597    }
22598
22599    fn range_for_rename(
22600        &self,
22601        buffer: &Entity<Buffer>,
22602        position: text::Anchor,
22603        cx: &mut App,
22604    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22605        Some(self.update(cx, |project, cx| {
22606            let buffer = buffer.clone();
22607            let task = project.prepare_rename(buffer.clone(), position, cx);
22608            cx.spawn(async move |_, cx| {
22609                Ok(match task.await? {
22610                    PrepareRenameResponse::Success(range) => Some(range),
22611                    PrepareRenameResponse::InvalidPosition => None,
22612                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22613                        // Fallback on using TreeSitter info to determine identifier range
22614                        buffer.read_with(cx, |buffer, _| {
22615                            let snapshot = buffer.snapshot();
22616                            let (range, kind) = snapshot.surrounding_word(position, false);
22617                            if kind != Some(CharKind::Word) {
22618                                return None;
22619                            }
22620                            Some(
22621                                snapshot.anchor_before(range.start)
22622                                    ..snapshot.anchor_after(range.end),
22623                            )
22624                        })?
22625                    }
22626                })
22627            })
22628        }))
22629    }
22630
22631    fn perform_rename(
22632        &self,
22633        buffer: &Entity<Buffer>,
22634        position: text::Anchor,
22635        new_name: String,
22636        cx: &mut App,
22637    ) -> Option<Task<Result<ProjectTransaction>>> {
22638        Some(self.update(cx, |project, cx| {
22639            project.perform_rename(buffer.clone(), position, new_name, cx)
22640        }))
22641    }
22642}
22643
22644fn inlay_hint_settings(
22645    location: Anchor,
22646    snapshot: &MultiBufferSnapshot,
22647    cx: &mut Context<Editor>,
22648) -> InlayHintSettings {
22649    let file = snapshot.file_at(location);
22650    let language = snapshot.language_at(location).map(|l| l.name());
22651    language_settings(language, file, cx).inlay_hints
22652}
22653
22654fn consume_contiguous_rows(
22655    contiguous_row_selections: &mut Vec<Selection<Point>>,
22656    selection: &Selection<Point>,
22657    display_map: &DisplaySnapshot,
22658    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22659) -> (MultiBufferRow, MultiBufferRow) {
22660    contiguous_row_selections.push(selection.clone());
22661    let start_row = starting_row(selection, display_map);
22662    let mut end_row = ending_row(selection, display_map);
22663
22664    while let Some(next_selection) = selections.peek() {
22665        if next_selection.start.row <= end_row.0 {
22666            end_row = ending_row(next_selection, display_map);
22667            contiguous_row_selections.push(selections.next().unwrap().clone());
22668        } else {
22669            break;
22670        }
22671    }
22672    (start_row, end_row)
22673}
22674
22675fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22676    if selection.start.column > 0 {
22677        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22678    } else {
22679        MultiBufferRow(selection.start.row)
22680    }
22681}
22682
22683fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22684    if next_selection.end.column > 0 || next_selection.is_empty() {
22685        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22686    } else {
22687        MultiBufferRow(next_selection.end.row)
22688    }
22689}
22690
22691impl EditorSnapshot {
22692    pub fn remote_selections_in_range<'a>(
22693        &'a self,
22694        range: &'a Range<Anchor>,
22695        collaboration_hub: &dyn CollaborationHub,
22696        cx: &'a App,
22697    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22698        let participant_names = collaboration_hub.user_names(cx);
22699        let participant_indices = collaboration_hub.user_participant_indices(cx);
22700        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22701        let collaborators_by_replica_id = collaborators_by_peer_id
22702            .values()
22703            .map(|collaborator| (collaborator.replica_id, collaborator))
22704            .collect::<HashMap<_, _>>();
22705        self.buffer_snapshot
22706            .selections_in_range(range, false)
22707            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22708                if replica_id == AGENT_REPLICA_ID {
22709                    Some(RemoteSelection {
22710                        replica_id,
22711                        selection,
22712                        cursor_shape,
22713                        line_mode,
22714                        collaborator_id: CollaboratorId::Agent,
22715                        user_name: Some("Agent".into()),
22716                        color: cx.theme().players().agent(),
22717                    })
22718                } else {
22719                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22720                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22721                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22722                    Some(RemoteSelection {
22723                        replica_id,
22724                        selection,
22725                        cursor_shape,
22726                        line_mode,
22727                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22728                        user_name,
22729                        color: if let Some(index) = participant_index {
22730                            cx.theme().players().color_for_participant(index.0)
22731                        } else {
22732                            cx.theme().players().absent()
22733                        },
22734                    })
22735                }
22736            })
22737    }
22738
22739    pub fn hunks_for_ranges(
22740        &self,
22741        ranges: impl IntoIterator<Item = Range<Point>>,
22742    ) -> Vec<MultiBufferDiffHunk> {
22743        let mut hunks = Vec::new();
22744        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22745            HashMap::default();
22746        for query_range in ranges {
22747            let query_rows =
22748                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22749            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22750                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22751            ) {
22752                // Include deleted hunks that are adjacent to the query range, because
22753                // otherwise they would be missed.
22754                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22755                if hunk.status().is_deleted() {
22756                    intersects_range |= hunk.row_range.start == query_rows.end;
22757                    intersects_range |= hunk.row_range.end == query_rows.start;
22758                }
22759                if intersects_range {
22760                    if !processed_buffer_rows
22761                        .entry(hunk.buffer_id)
22762                        .or_default()
22763                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22764                    {
22765                        continue;
22766                    }
22767                    hunks.push(hunk);
22768                }
22769            }
22770        }
22771
22772        hunks
22773    }
22774
22775    fn display_diff_hunks_for_rows<'a>(
22776        &'a self,
22777        display_rows: Range<DisplayRow>,
22778        folded_buffers: &'a HashSet<BufferId>,
22779    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22780        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22781        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22782
22783        self.buffer_snapshot
22784            .diff_hunks_in_range(buffer_start..buffer_end)
22785            .filter_map(|hunk| {
22786                if folded_buffers.contains(&hunk.buffer_id) {
22787                    return None;
22788                }
22789
22790                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22791                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22792
22793                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22794                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22795
22796                let display_hunk = if hunk_display_start.column() != 0 {
22797                    DisplayDiffHunk::Folded {
22798                        display_row: hunk_display_start.row(),
22799                    }
22800                } else {
22801                    let mut end_row = hunk_display_end.row();
22802                    if hunk_display_end.column() > 0 {
22803                        end_row.0 += 1;
22804                    }
22805                    let is_created_file = hunk.is_created_file();
22806                    DisplayDiffHunk::Unfolded {
22807                        status: hunk.status(),
22808                        diff_base_byte_range: hunk.diff_base_byte_range,
22809                        display_row_range: hunk_display_start.row()..end_row,
22810                        multi_buffer_range: Anchor::range_in_buffer(
22811                            hunk.excerpt_id,
22812                            hunk.buffer_id,
22813                            hunk.buffer_range,
22814                        ),
22815                        is_created_file,
22816                    }
22817                };
22818
22819                Some(display_hunk)
22820            })
22821    }
22822
22823    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22824        self.display_snapshot.buffer_snapshot.language_at(position)
22825    }
22826
22827    pub fn is_focused(&self) -> bool {
22828        self.is_focused
22829    }
22830
22831    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22832        self.placeholder_text.as_ref()
22833    }
22834
22835    pub fn scroll_position(&self) -> gpui::Point<f32> {
22836        self.scroll_anchor.scroll_position(&self.display_snapshot)
22837    }
22838
22839    fn gutter_dimensions(
22840        &self,
22841        font_id: FontId,
22842        font_size: Pixels,
22843        max_line_number_width: Pixels,
22844        cx: &App,
22845    ) -> Option<GutterDimensions> {
22846        if !self.show_gutter {
22847            return None;
22848        }
22849
22850        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22851        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22852
22853        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22854            matches!(
22855                ProjectSettings::get_global(cx).git.git_gutter,
22856                Some(GitGutterSetting::TrackedFiles)
22857            )
22858        });
22859        let gutter_settings = EditorSettings::get_global(cx).gutter;
22860        let show_line_numbers = self
22861            .show_line_numbers
22862            .unwrap_or(gutter_settings.line_numbers);
22863        let line_gutter_width = if show_line_numbers {
22864            // Avoid flicker-like gutter resizes when the line number gains another digit by
22865            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22866            let min_width_for_number_on_gutter =
22867                ch_advance * gutter_settings.min_line_number_digits as f32;
22868            max_line_number_width.max(min_width_for_number_on_gutter)
22869        } else {
22870            0.0.into()
22871        };
22872
22873        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22874        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22875
22876        let git_blame_entries_width =
22877            self.git_blame_gutter_max_author_length
22878                .map(|max_author_length| {
22879                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22880                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22881
22882                    /// The number of characters to dedicate to gaps and margins.
22883                    const SPACING_WIDTH: usize = 4;
22884
22885                    let max_char_count = max_author_length.min(renderer.max_author_length())
22886                        + ::git::SHORT_SHA_LENGTH
22887                        + MAX_RELATIVE_TIMESTAMP.len()
22888                        + SPACING_WIDTH;
22889
22890                    ch_advance * max_char_count
22891                });
22892
22893        let is_singleton = self.buffer_snapshot.is_singleton();
22894
22895        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22896        left_padding += if !is_singleton {
22897            ch_width * 4.0
22898        } else if show_runnables || show_breakpoints {
22899            ch_width * 3.0
22900        } else if show_git_gutter && show_line_numbers {
22901            ch_width * 2.0
22902        } else if show_git_gutter || show_line_numbers {
22903            ch_width
22904        } else {
22905            px(0.)
22906        };
22907
22908        let shows_folds = is_singleton && gutter_settings.folds;
22909
22910        let right_padding = if shows_folds && show_line_numbers {
22911            ch_width * 4.0
22912        } else if shows_folds || (!is_singleton && show_line_numbers) {
22913            ch_width * 3.0
22914        } else if show_line_numbers {
22915            ch_width
22916        } else {
22917            px(0.)
22918        };
22919
22920        Some(GutterDimensions {
22921            left_padding,
22922            right_padding,
22923            width: line_gutter_width + left_padding + right_padding,
22924            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22925            git_blame_entries_width,
22926        })
22927    }
22928
22929    pub fn render_crease_toggle(
22930        &self,
22931        buffer_row: MultiBufferRow,
22932        row_contains_cursor: bool,
22933        editor: Entity<Editor>,
22934        window: &mut Window,
22935        cx: &mut App,
22936    ) -> Option<AnyElement> {
22937        let folded = self.is_line_folded(buffer_row);
22938        let mut is_foldable = false;
22939
22940        if let Some(crease) = self
22941            .crease_snapshot
22942            .query_row(buffer_row, &self.buffer_snapshot)
22943        {
22944            is_foldable = true;
22945            match crease {
22946                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22947                    if let Some(render_toggle) = render_toggle {
22948                        let toggle_callback =
22949                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22950                                if folded {
22951                                    editor.update(cx, |editor, cx| {
22952                                        editor.fold_at(buffer_row, window, cx)
22953                                    });
22954                                } else {
22955                                    editor.update(cx, |editor, cx| {
22956                                        editor.unfold_at(buffer_row, window, cx)
22957                                    });
22958                                }
22959                            });
22960                        return Some((render_toggle)(
22961                            buffer_row,
22962                            folded,
22963                            toggle_callback,
22964                            window,
22965                            cx,
22966                        ));
22967                    }
22968                }
22969            }
22970        }
22971
22972        is_foldable |= self.starts_indent(buffer_row);
22973
22974        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22975            Some(
22976                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22977                    .toggle_state(folded)
22978                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22979                        if folded {
22980                            this.unfold_at(buffer_row, window, cx);
22981                        } else {
22982                            this.fold_at(buffer_row, window, cx);
22983                        }
22984                    }))
22985                    .into_any_element(),
22986            )
22987        } else {
22988            None
22989        }
22990    }
22991
22992    pub fn render_crease_trailer(
22993        &self,
22994        buffer_row: MultiBufferRow,
22995        window: &mut Window,
22996        cx: &mut App,
22997    ) -> Option<AnyElement> {
22998        let folded = self.is_line_folded(buffer_row);
22999        if let Crease::Inline { render_trailer, .. } = self
23000            .crease_snapshot
23001            .query_row(buffer_row, &self.buffer_snapshot)?
23002        {
23003            let render_trailer = render_trailer.as_ref()?;
23004            Some(render_trailer(buffer_row, folded, window, cx))
23005        } else {
23006            None
23007        }
23008    }
23009}
23010
23011impl Deref for EditorSnapshot {
23012    type Target = DisplaySnapshot;
23013
23014    fn deref(&self) -> &Self::Target {
23015        &self.display_snapshot
23016    }
23017}
23018
23019#[derive(Clone, Debug, PartialEq, Eq)]
23020pub enum EditorEvent {
23021    InputIgnored {
23022        text: Arc<str>,
23023    },
23024    InputHandled {
23025        utf16_range_to_replace: Option<Range<isize>>,
23026        text: Arc<str>,
23027    },
23028    ExcerptsAdded {
23029        buffer: Entity<Buffer>,
23030        predecessor: ExcerptId,
23031        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23032    },
23033    ExcerptsRemoved {
23034        ids: Vec<ExcerptId>,
23035        removed_buffer_ids: Vec<BufferId>,
23036    },
23037    BufferFoldToggled {
23038        ids: Vec<ExcerptId>,
23039        folded: bool,
23040    },
23041    ExcerptsEdited {
23042        ids: Vec<ExcerptId>,
23043    },
23044    ExcerptsExpanded {
23045        ids: Vec<ExcerptId>,
23046    },
23047    BufferEdited,
23048    Edited {
23049        transaction_id: clock::Lamport,
23050    },
23051    Reparsed(BufferId),
23052    Focused,
23053    FocusedIn,
23054    Blurred,
23055    DirtyChanged,
23056    Saved,
23057    TitleChanged,
23058    SelectionsChanged {
23059        local: bool,
23060    },
23061    ScrollPositionChanged {
23062        local: bool,
23063        autoscroll: bool,
23064    },
23065    TransactionUndone {
23066        transaction_id: clock::Lamport,
23067    },
23068    TransactionBegun {
23069        transaction_id: clock::Lamport,
23070    },
23071    CursorShapeChanged,
23072    BreadcrumbsChanged,
23073    PushedToNavHistory {
23074        anchor: Anchor,
23075        is_deactivate: bool,
23076    },
23077}
23078
23079impl EventEmitter<EditorEvent> for Editor {}
23080
23081impl Focusable for Editor {
23082    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23083        self.focus_handle.clone()
23084    }
23085}
23086
23087impl Render for Editor {
23088    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23089        let settings = ThemeSettings::get_global(cx);
23090
23091        let mut text_style = match self.mode {
23092            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23093                color: cx.theme().colors().editor_foreground,
23094                font_family: settings.ui_font.family.clone(),
23095                font_features: settings.ui_font.features.clone(),
23096                font_fallbacks: settings.ui_font.fallbacks.clone(),
23097                font_size: rems(0.875).into(),
23098                font_weight: settings.ui_font.weight,
23099                line_height: relative(settings.buffer_line_height.value()),
23100                ..Default::default()
23101            },
23102            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23103                color: cx.theme().colors().editor_foreground,
23104                font_family: settings.buffer_font.family.clone(),
23105                font_features: settings.buffer_font.features.clone(),
23106                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23107                font_size: settings.buffer_font_size(cx).into(),
23108                font_weight: settings.buffer_font.weight,
23109                line_height: relative(settings.buffer_line_height.value()),
23110                ..Default::default()
23111            },
23112        };
23113        if let Some(text_style_refinement) = &self.text_style_refinement {
23114            text_style.refine(text_style_refinement)
23115        }
23116
23117        let background = match self.mode {
23118            EditorMode::SingleLine => cx.theme().system().transparent,
23119            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23120            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23121            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23122        };
23123
23124        EditorElement::new(
23125            &cx.entity(),
23126            EditorStyle {
23127                background,
23128                border: cx.theme().colors().border,
23129                local_player: cx.theme().players().local(),
23130                text: text_style,
23131                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23132                syntax: cx.theme().syntax().clone(),
23133                status: cx.theme().status().clone(),
23134                inlay_hints_style: make_inlay_hints_style(cx),
23135                edit_prediction_styles: make_suggestion_styles(cx),
23136                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23137                show_underlines: self.diagnostics_enabled(),
23138            },
23139        )
23140    }
23141}
23142
23143impl EntityInputHandler for Editor {
23144    fn text_for_range(
23145        &mut self,
23146        range_utf16: Range<usize>,
23147        adjusted_range: &mut Option<Range<usize>>,
23148        _: &mut Window,
23149        cx: &mut Context<Self>,
23150    ) -> Option<String> {
23151        let snapshot = self.buffer.read(cx).read(cx);
23152        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23153        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23154        if (start.0..end.0) != range_utf16 {
23155            adjusted_range.replace(start.0..end.0);
23156        }
23157        Some(snapshot.text_for_range(start..end).collect())
23158    }
23159
23160    fn selected_text_range(
23161        &mut self,
23162        ignore_disabled_input: bool,
23163        _: &mut Window,
23164        cx: &mut Context<Self>,
23165    ) -> Option<UTF16Selection> {
23166        // Prevent the IME menu from appearing when holding down an alphabetic key
23167        // while input is disabled.
23168        if !ignore_disabled_input && !self.input_enabled {
23169            return None;
23170        }
23171
23172        let selection = self.selections.newest::<OffsetUtf16>(cx);
23173        let range = selection.range();
23174
23175        Some(UTF16Selection {
23176            range: range.start.0..range.end.0,
23177            reversed: selection.reversed,
23178        })
23179    }
23180
23181    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23182        let snapshot = self.buffer.read(cx).read(cx);
23183        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23184        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23185    }
23186
23187    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23188        self.clear_highlights::<InputComposition>(cx);
23189        self.ime_transaction.take();
23190    }
23191
23192    fn replace_text_in_range(
23193        &mut self,
23194        range_utf16: Option<Range<usize>>,
23195        text: &str,
23196        window: &mut Window,
23197        cx: &mut Context<Self>,
23198    ) {
23199        if !self.input_enabled {
23200            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23201            return;
23202        }
23203
23204        self.transact(window, cx, |this, window, cx| {
23205            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23206                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23207                Some(this.selection_replacement_ranges(range_utf16, cx))
23208            } else {
23209                this.marked_text_ranges(cx)
23210            };
23211
23212            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23213                let newest_selection_id = this.selections.newest_anchor().id;
23214                this.selections
23215                    .all::<OffsetUtf16>(cx)
23216                    .iter()
23217                    .zip(ranges_to_replace.iter())
23218                    .find_map(|(selection, range)| {
23219                        if selection.id == newest_selection_id {
23220                            Some(
23221                                (range.start.0 as isize - selection.head().0 as isize)
23222                                    ..(range.end.0 as isize - selection.head().0 as isize),
23223                            )
23224                        } else {
23225                            None
23226                        }
23227                    })
23228            });
23229
23230            cx.emit(EditorEvent::InputHandled {
23231                utf16_range_to_replace: range_to_replace,
23232                text: text.into(),
23233            });
23234
23235            if let Some(new_selected_ranges) = new_selected_ranges {
23236                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23237                    selections.select_ranges(new_selected_ranges)
23238                });
23239                this.backspace(&Default::default(), window, cx);
23240            }
23241
23242            this.handle_input(text, window, cx);
23243        });
23244
23245        if let Some(transaction) = self.ime_transaction {
23246            self.buffer.update(cx, |buffer, cx| {
23247                buffer.group_until_transaction(transaction, cx);
23248            });
23249        }
23250
23251        self.unmark_text(window, cx);
23252    }
23253
23254    fn replace_and_mark_text_in_range(
23255        &mut self,
23256        range_utf16: Option<Range<usize>>,
23257        text: &str,
23258        new_selected_range_utf16: Option<Range<usize>>,
23259        window: &mut Window,
23260        cx: &mut Context<Self>,
23261    ) {
23262        if !self.input_enabled {
23263            return;
23264        }
23265
23266        let transaction = self.transact(window, cx, |this, window, cx| {
23267            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23268                let snapshot = this.buffer.read(cx).read(cx);
23269                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23270                    for marked_range in &mut marked_ranges {
23271                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23272                        marked_range.start.0 += relative_range_utf16.start;
23273                        marked_range.start =
23274                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23275                        marked_range.end =
23276                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23277                    }
23278                }
23279                Some(marked_ranges)
23280            } else if let Some(range_utf16) = range_utf16 {
23281                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23282                Some(this.selection_replacement_ranges(range_utf16, cx))
23283            } else {
23284                None
23285            };
23286
23287            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23288                let newest_selection_id = this.selections.newest_anchor().id;
23289                this.selections
23290                    .all::<OffsetUtf16>(cx)
23291                    .iter()
23292                    .zip(ranges_to_replace.iter())
23293                    .find_map(|(selection, range)| {
23294                        if selection.id == newest_selection_id {
23295                            Some(
23296                                (range.start.0 as isize - selection.head().0 as isize)
23297                                    ..(range.end.0 as isize - selection.head().0 as isize),
23298                            )
23299                        } else {
23300                            None
23301                        }
23302                    })
23303            });
23304
23305            cx.emit(EditorEvent::InputHandled {
23306                utf16_range_to_replace: range_to_replace,
23307                text: text.into(),
23308            });
23309
23310            if let Some(ranges) = ranges_to_replace {
23311                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23312                    s.select_ranges(ranges)
23313                });
23314            }
23315
23316            let marked_ranges = {
23317                let snapshot = this.buffer.read(cx).read(cx);
23318                this.selections
23319                    .disjoint_anchors()
23320                    .iter()
23321                    .map(|selection| {
23322                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23323                    })
23324                    .collect::<Vec<_>>()
23325            };
23326
23327            if text.is_empty() {
23328                this.unmark_text(window, cx);
23329            } else {
23330                this.highlight_text::<InputComposition>(
23331                    marked_ranges.clone(),
23332                    HighlightStyle {
23333                        underline: Some(UnderlineStyle {
23334                            thickness: px(1.),
23335                            color: None,
23336                            wavy: false,
23337                        }),
23338                        ..Default::default()
23339                    },
23340                    cx,
23341                );
23342            }
23343
23344            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23345            let use_autoclose = this.use_autoclose;
23346            let use_auto_surround = this.use_auto_surround;
23347            this.set_use_autoclose(false);
23348            this.set_use_auto_surround(false);
23349            this.handle_input(text, window, cx);
23350            this.set_use_autoclose(use_autoclose);
23351            this.set_use_auto_surround(use_auto_surround);
23352
23353            if let Some(new_selected_range) = new_selected_range_utf16 {
23354                let snapshot = this.buffer.read(cx).read(cx);
23355                let new_selected_ranges = marked_ranges
23356                    .into_iter()
23357                    .map(|marked_range| {
23358                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23359                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23360                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23361                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23362                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23363                    })
23364                    .collect::<Vec<_>>();
23365
23366                drop(snapshot);
23367                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23368                    selections.select_ranges(new_selected_ranges)
23369                });
23370            }
23371        });
23372
23373        self.ime_transaction = self.ime_transaction.or(transaction);
23374        if let Some(transaction) = self.ime_transaction {
23375            self.buffer.update(cx, |buffer, cx| {
23376                buffer.group_until_transaction(transaction, cx);
23377            });
23378        }
23379
23380        if self.text_highlights::<InputComposition>(cx).is_none() {
23381            self.ime_transaction.take();
23382        }
23383    }
23384
23385    fn bounds_for_range(
23386        &mut self,
23387        range_utf16: Range<usize>,
23388        element_bounds: gpui::Bounds<Pixels>,
23389        window: &mut Window,
23390        cx: &mut Context<Self>,
23391    ) -> Option<gpui::Bounds<Pixels>> {
23392        let text_layout_details = self.text_layout_details(window);
23393        let CharacterDimensions {
23394            em_width,
23395            em_advance,
23396            line_height,
23397        } = self.character_dimensions(window);
23398
23399        let snapshot = self.snapshot(window, cx);
23400        let scroll_position = snapshot.scroll_position();
23401        let scroll_left = scroll_position.x * em_advance;
23402
23403        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23404        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23405            + self.gutter_dimensions.full_width();
23406        let y = line_height * (start.row().as_f32() - scroll_position.y);
23407
23408        Some(Bounds {
23409            origin: element_bounds.origin + point(x, y),
23410            size: size(em_width, line_height),
23411        })
23412    }
23413
23414    fn character_index_for_point(
23415        &mut self,
23416        point: gpui::Point<Pixels>,
23417        _window: &mut Window,
23418        _cx: &mut Context<Self>,
23419    ) -> Option<usize> {
23420        let position_map = self.last_position_map.as_ref()?;
23421        if !position_map.text_hitbox.contains(&point) {
23422            return None;
23423        }
23424        let display_point = position_map.point_for_position(point).previous_valid;
23425        let anchor = position_map
23426            .snapshot
23427            .display_point_to_anchor(display_point, Bias::Left);
23428        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23429        Some(utf16_offset.0)
23430    }
23431}
23432
23433trait SelectionExt {
23434    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23435    fn spanned_rows(
23436        &self,
23437        include_end_if_at_line_start: bool,
23438        map: &DisplaySnapshot,
23439    ) -> Range<MultiBufferRow>;
23440}
23441
23442impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23443    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23444        let start = self
23445            .start
23446            .to_point(&map.buffer_snapshot)
23447            .to_display_point(map);
23448        let end = self
23449            .end
23450            .to_point(&map.buffer_snapshot)
23451            .to_display_point(map);
23452        if self.reversed {
23453            end..start
23454        } else {
23455            start..end
23456        }
23457    }
23458
23459    fn spanned_rows(
23460        &self,
23461        include_end_if_at_line_start: bool,
23462        map: &DisplaySnapshot,
23463    ) -> Range<MultiBufferRow> {
23464        let start = self.start.to_point(&map.buffer_snapshot);
23465        let mut end = self.end.to_point(&map.buffer_snapshot);
23466        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23467            end.row -= 1;
23468        }
23469
23470        let buffer_start = map.prev_line_boundary(start).0;
23471        let buffer_end = map.next_line_boundary(end).0;
23472        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23473    }
23474}
23475
23476impl<T: InvalidationRegion> InvalidationStack<T> {
23477    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23478    where
23479        S: Clone + ToOffset,
23480    {
23481        while let Some(region) = self.last() {
23482            let all_selections_inside_invalidation_ranges =
23483                if selections.len() == region.ranges().len() {
23484                    selections
23485                        .iter()
23486                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23487                        .all(|(selection, invalidation_range)| {
23488                            let head = selection.head().to_offset(buffer);
23489                            invalidation_range.start <= head && invalidation_range.end >= head
23490                        })
23491                } else {
23492                    false
23493                };
23494
23495            if all_selections_inside_invalidation_ranges {
23496                break;
23497            } else {
23498                self.pop();
23499            }
23500        }
23501    }
23502}
23503
23504impl<T> Default for InvalidationStack<T> {
23505    fn default() -> Self {
23506        Self(Default::default())
23507    }
23508}
23509
23510impl<T> Deref for InvalidationStack<T> {
23511    type Target = Vec<T>;
23512
23513    fn deref(&self) -> &Self::Target {
23514        &self.0
23515    }
23516}
23517
23518impl<T> DerefMut for InvalidationStack<T> {
23519    fn deref_mut(&mut self) -> &mut Self::Target {
23520        &mut self.0
23521    }
23522}
23523
23524impl InvalidationRegion for SnippetState {
23525    fn ranges(&self) -> &[Range<Anchor>] {
23526        &self.ranges[self.active_index]
23527    }
23528}
23529
23530fn edit_prediction_edit_text(
23531    current_snapshot: &BufferSnapshot,
23532    edits: &[(Range<Anchor>, String)],
23533    edit_preview: &EditPreview,
23534    include_deletions: bool,
23535    cx: &App,
23536) -> HighlightedText {
23537    let edits = edits
23538        .iter()
23539        .map(|(anchor, text)| {
23540            (
23541                anchor.start.text_anchor..anchor.end.text_anchor,
23542                text.clone(),
23543            )
23544        })
23545        .collect::<Vec<_>>();
23546
23547    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23548}
23549
23550fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23551    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23552    // Just show the raw edit text with basic styling
23553    let mut text = String::new();
23554    let mut highlights = Vec::new();
23555
23556    let insertion_highlight_style = HighlightStyle {
23557        color: Some(cx.theme().colors().text),
23558        ..Default::default()
23559    };
23560
23561    for (_, edit_text) in edits {
23562        let start_offset = text.len();
23563        text.push_str(edit_text);
23564        let end_offset = text.len();
23565
23566        if start_offset < end_offset {
23567            highlights.push((start_offset..end_offset, insertion_highlight_style));
23568        }
23569    }
23570
23571    HighlightedText {
23572        text: text.into(),
23573        highlights,
23574    }
23575}
23576
23577pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23578    match severity {
23579        lsp::DiagnosticSeverity::ERROR => colors.error,
23580        lsp::DiagnosticSeverity::WARNING => colors.warning,
23581        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23582        lsp::DiagnosticSeverity::HINT => colors.info,
23583        _ => colors.ignored,
23584    }
23585}
23586
23587pub fn styled_runs_for_code_label<'a>(
23588    label: &'a CodeLabel,
23589    syntax_theme: &'a theme::SyntaxTheme,
23590) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23591    let fade_out = HighlightStyle {
23592        fade_out: Some(0.35),
23593        ..Default::default()
23594    };
23595
23596    let mut prev_end = label.filter_range.end;
23597    label
23598        .runs
23599        .iter()
23600        .enumerate()
23601        .flat_map(move |(ix, (range, highlight_id))| {
23602            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23603                style
23604            } else {
23605                return Default::default();
23606            };
23607            let mut muted_style = style;
23608            muted_style.highlight(fade_out);
23609
23610            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23611            if range.start >= label.filter_range.end {
23612                if range.start > prev_end {
23613                    runs.push((prev_end..range.start, fade_out));
23614                }
23615                runs.push((range.clone(), muted_style));
23616            } else if range.end <= label.filter_range.end {
23617                runs.push((range.clone(), style));
23618            } else {
23619                runs.push((range.start..label.filter_range.end, style));
23620                runs.push((label.filter_range.end..range.end, muted_style));
23621            }
23622            prev_end = cmp::max(prev_end, range.end);
23623
23624            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23625                runs.push((prev_end..label.text.len(), fade_out));
23626            }
23627
23628            runs
23629        })
23630}
23631
23632pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23633    let mut prev_index = 0;
23634    let mut prev_codepoint: Option<char> = None;
23635    text.char_indices()
23636        .chain([(text.len(), '\0')])
23637        .filter_map(move |(index, codepoint)| {
23638            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23639            let is_boundary = index == text.len()
23640                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23641                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23642            if is_boundary {
23643                let chunk = &text[prev_index..index];
23644                prev_index = index;
23645                Some(chunk)
23646            } else {
23647                None
23648            }
23649        })
23650}
23651
23652pub trait RangeToAnchorExt: Sized {
23653    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23654
23655    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23656        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23657        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23658    }
23659}
23660
23661impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23662    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23663        let start_offset = self.start.to_offset(snapshot);
23664        let end_offset = self.end.to_offset(snapshot);
23665        if start_offset == end_offset {
23666            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23667        } else {
23668            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23669        }
23670    }
23671}
23672
23673pub trait RowExt {
23674    fn as_f32(&self) -> f32;
23675
23676    fn next_row(&self) -> Self;
23677
23678    fn previous_row(&self) -> Self;
23679
23680    fn minus(&self, other: Self) -> u32;
23681}
23682
23683impl RowExt for DisplayRow {
23684    fn as_f32(&self) -> f32 {
23685        self.0 as f32
23686    }
23687
23688    fn next_row(&self) -> Self {
23689        Self(self.0 + 1)
23690    }
23691
23692    fn previous_row(&self) -> Self {
23693        Self(self.0.saturating_sub(1))
23694    }
23695
23696    fn minus(&self, other: Self) -> u32 {
23697        self.0 - other.0
23698    }
23699}
23700
23701impl RowExt for MultiBufferRow {
23702    fn as_f32(&self) -> f32 {
23703        self.0 as f32
23704    }
23705
23706    fn next_row(&self) -> Self {
23707        Self(self.0 + 1)
23708    }
23709
23710    fn previous_row(&self) -> Self {
23711        Self(self.0.saturating_sub(1))
23712    }
23713
23714    fn minus(&self, other: Self) -> u32 {
23715        self.0 - other.0
23716    }
23717}
23718
23719trait RowRangeExt {
23720    type Row;
23721
23722    fn len(&self) -> usize;
23723
23724    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23725}
23726
23727impl RowRangeExt for Range<MultiBufferRow> {
23728    type Row = MultiBufferRow;
23729
23730    fn len(&self) -> usize {
23731        (self.end.0 - self.start.0) as usize
23732    }
23733
23734    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23735        (self.start.0..self.end.0).map(MultiBufferRow)
23736    }
23737}
23738
23739impl RowRangeExt for Range<DisplayRow> {
23740    type Row = DisplayRow;
23741
23742    fn len(&self) -> usize {
23743        (self.end.0 - self.start.0) as usize
23744    }
23745
23746    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23747        (self.start.0..self.end.0).map(DisplayRow)
23748    }
23749}
23750
23751/// If select range has more than one line, we
23752/// just point the cursor to range.start.
23753fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23754    if range.start.row == range.end.row {
23755        range
23756    } else {
23757        range.start..range.start
23758    }
23759}
23760pub struct KillRing(ClipboardItem);
23761impl Global for KillRing {}
23762
23763const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23764
23765enum BreakpointPromptEditAction {
23766    Log,
23767    Condition,
23768    HitCondition,
23769}
23770
23771struct BreakpointPromptEditor {
23772    pub(crate) prompt: Entity<Editor>,
23773    editor: WeakEntity<Editor>,
23774    breakpoint_anchor: Anchor,
23775    breakpoint: Breakpoint,
23776    edit_action: BreakpointPromptEditAction,
23777    block_ids: HashSet<CustomBlockId>,
23778    editor_margins: Arc<Mutex<EditorMargins>>,
23779    _subscriptions: Vec<Subscription>,
23780}
23781
23782impl BreakpointPromptEditor {
23783    const MAX_LINES: u8 = 4;
23784
23785    fn new(
23786        editor: WeakEntity<Editor>,
23787        breakpoint_anchor: Anchor,
23788        breakpoint: Breakpoint,
23789        edit_action: BreakpointPromptEditAction,
23790        window: &mut Window,
23791        cx: &mut Context<Self>,
23792    ) -> Self {
23793        let base_text = match edit_action {
23794            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23795            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23796            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23797        }
23798        .map(|msg| msg.to_string())
23799        .unwrap_or_default();
23800
23801        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23802        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23803
23804        let prompt = cx.new(|cx| {
23805            let mut prompt = Editor::new(
23806                EditorMode::AutoHeight {
23807                    min_lines: 1,
23808                    max_lines: Some(Self::MAX_LINES as usize),
23809                },
23810                buffer,
23811                None,
23812                window,
23813                cx,
23814            );
23815            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23816            prompt.set_show_cursor_when_unfocused(false, cx);
23817            prompt.set_placeholder_text(
23818                match edit_action {
23819                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23820                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23821                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23822                },
23823                cx,
23824            );
23825
23826            prompt
23827        });
23828
23829        Self {
23830            prompt,
23831            editor,
23832            breakpoint_anchor,
23833            breakpoint,
23834            edit_action,
23835            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23836            block_ids: Default::default(),
23837            _subscriptions: vec![],
23838        }
23839    }
23840
23841    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23842        self.block_ids.extend(block_ids)
23843    }
23844
23845    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23846        if let Some(editor) = self.editor.upgrade() {
23847            let message = self
23848                .prompt
23849                .read(cx)
23850                .buffer
23851                .read(cx)
23852                .as_singleton()
23853                .expect("A multi buffer in breakpoint prompt isn't possible")
23854                .read(cx)
23855                .as_rope()
23856                .to_string();
23857
23858            editor.update(cx, |editor, cx| {
23859                editor.edit_breakpoint_at_anchor(
23860                    self.breakpoint_anchor,
23861                    self.breakpoint.clone(),
23862                    match self.edit_action {
23863                        BreakpointPromptEditAction::Log => {
23864                            BreakpointEditAction::EditLogMessage(message.into())
23865                        }
23866                        BreakpointPromptEditAction::Condition => {
23867                            BreakpointEditAction::EditCondition(message.into())
23868                        }
23869                        BreakpointPromptEditAction::HitCondition => {
23870                            BreakpointEditAction::EditHitCondition(message.into())
23871                        }
23872                    },
23873                    cx,
23874                );
23875
23876                editor.remove_blocks(self.block_ids.clone(), None, cx);
23877                cx.focus_self(window);
23878            });
23879        }
23880    }
23881
23882    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23883        self.editor
23884            .update(cx, |editor, cx| {
23885                editor.remove_blocks(self.block_ids.clone(), None, cx);
23886                window.focus(&editor.focus_handle);
23887            })
23888            .log_err();
23889    }
23890
23891    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23892        let settings = ThemeSettings::get_global(cx);
23893        let text_style = TextStyle {
23894            color: if self.prompt.read(cx).read_only(cx) {
23895                cx.theme().colors().text_disabled
23896            } else {
23897                cx.theme().colors().text
23898            },
23899            font_family: settings.buffer_font.family.clone(),
23900            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23901            font_size: settings.buffer_font_size(cx).into(),
23902            font_weight: settings.buffer_font.weight,
23903            line_height: relative(settings.buffer_line_height.value()),
23904            ..Default::default()
23905        };
23906        EditorElement::new(
23907            &self.prompt,
23908            EditorStyle {
23909                background: cx.theme().colors().editor_background,
23910                local_player: cx.theme().players().local(),
23911                text: text_style,
23912                ..Default::default()
23913            },
23914        )
23915    }
23916}
23917
23918impl Render for BreakpointPromptEditor {
23919    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23920        let editor_margins = *self.editor_margins.lock();
23921        let gutter_dimensions = editor_margins.gutter;
23922        h_flex()
23923            .key_context("Editor")
23924            .bg(cx.theme().colors().editor_background)
23925            .border_y_1()
23926            .border_color(cx.theme().status().info_border)
23927            .size_full()
23928            .py(window.line_height() / 2.5)
23929            .on_action(cx.listener(Self::confirm))
23930            .on_action(cx.listener(Self::cancel))
23931            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23932            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23933    }
23934}
23935
23936impl Focusable for BreakpointPromptEditor {
23937    fn focus_handle(&self, cx: &App) -> FocusHandle {
23938        self.prompt.focus_handle(cx)
23939    }
23940}
23941
23942fn all_edits_insertions_or_deletions(
23943    edits: &Vec<(Range<Anchor>, String)>,
23944    snapshot: &MultiBufferSnapshot,
23945) -> bool {
23946    let mut all_insertions = true;
23947    let mut all_deletions = true;
23948
23949    for (range, new_text) in edits.iter() {
23950        let range_is_empty = range.to_offset(snapshot).is_empty();
23951        let text_is_empty = new_text.is_empty();
23952
23953        if range_is_empty != text_is_empty {
23954            if range_is_empty {
23955                all_deletions = false;
23956            } else {
23957                all_insertions = false;
23958            }
23959        } else {
23960            return false;
23961        }
23962
23963        if !all_insertions && !all_deletions {
23964            return false;
23965        }
23966    }
23967    all_insertions || all_deletions
23968}
23969
23970struct MissingEditPredictionKeybindingTooltip;
23971
23972impl Render for MissingEditPredictionKeybindingTooltip {
23973    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23974        ui::tooltip_container(window, cx, |container, _, cx| {
23975            container
23976                .flex_shrink_0()
23977                .max_w_80()
23978                .min_h(rems_from_px(124.))
23979                .justify_between()
23980                .child(
23981                    v_flex()
23982                        .flex_1()
23983                        .text_ui_sm(cx)
23984                        .child(Label::new("Conflict with Accept Keybinding"))
23985                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23986                )
23987                .child(
23988                    h_flex()
23989                        .pb_1()
23990                        .gap_1()
23991                        .items_end()
23992                        .w_full()
23993                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23994                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23995                        }))
23996                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23997                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23998                        })),
23999                )
24000        })
24001    }
24002}
24003
24004#[derive(Debug, Clone, Copy, PartialEq)]
24005pub struct LineHighlight {
24006    pub background: Background,
24007    pub border: Option<gpui::Hsla>,
24008    pub include_gutter: bool,
24009    pub type_id: Option<TypeId>,
24010}
24011
24012struct LineManipulationResult {
24013    pub new_text: String,
24014    pub line_count_before: usize,
24015    pub line_count_after: usize,
24016}
24017
24018fn render_diff_hunk_controls(
24019    row: u32,
24020    status: &DiffHunkStatus,
24021    hunk_range: Range<Anchor>,
24022    is_created_file: bool,
24023    line_height: Pixels,
24024    editor: &Entity<Editor>,
24025    _window: &mut Window,
24026    cx: &mut App,
24027) -> AnyElement {
24028    h_flex()
24029        .h(line_height)
24030        .mr_1()
24031        .gap_1()
24032        .px_0p5()
24033        .pb_1()
24034        .border_x_1()
24035        .border_b_1()
24036        .border_color(cx.theme().colors().border_variant)
24037        .rounded_b_lg()
24038        .bg(cx.theme().colors().editor_background)
24039        .gap_1()
24040        .block_mouse_except_scroll()
24041        .shadow_md()
24042        .child(if status.has_secondary_hunk() {
24043            Button::new(("stage", row as u64), "Stage")
24044                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24045                .tooltip({
24046                    let focus_handle = editor.focus_handle(cx);
24047                    move |window, cx| {
24048                        Tooltip::for_action_in(
24049                            "Stage Hunk",
24050                            &::git::ToggleStaged,
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                            editor.stage_or_unstage_diff_hunks(
24062                                true,
24063                                vec![hunk_range.start..hunk_range.start],
24064                                cx,
24065                            );
24066                        });
24067                    }
24068                })
24069        } else {
24070            Button::new(("unstage", row as u64), "Unstage")
24071                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24072                .tooltip({
24073                    let focus_handle = editor.focus_handle(cx);
24074                    move |window, cx| {
24075                        Tooltip::for_action_in(
24076                            "Unstage Hunk",
24077                            &::git::ToggleStaged,
24078                            &focus_handle,
24079                            window,
24080                            cx,
24081                        )
24082                    }
24083                })
24084                .on_click({
24085                    let editor = editor.clone();
24086                    move |_event, _window, cx| {
24087                        editor.update(cx, |editor, cx| {
24088                            editor.stage_or_unstage_diff_hunks(
24089                                false,
24090                                vec![hunk_range.start..hunk_range.start],
24091                                cx,
24092                            );
24093                        });
24094                    }
24095                })
24096        })
24097        .child(
24098            Button::new(("restore", row as u64), "Restore")
24099                .tooltip({
24100                    let focus_handle = editor.focus_handle(cx);
24101                    move |window, cx| {
24102                        Tooltip::for_action_in(
24103                            "Restore Hunk",
24104                            &::git::Restore,
24105                            &focus_handle,
24106                            window,
24107                            cx,
24108                        )
24109                    }
24110                })
24111                .on_click({
24112                    let editor = editor.clone();
24113                    move |_event, window, cx| {
24114                        editor.update(cx, |editor, cx| {
24115                            let snapshot = editor.snapshot(window, cx);
24116                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24117                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24118                        });
24119                    }
24120                })
24121                .disabled(is_created_file),
24122        )
24123        .when(
24124            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24125            |el| {
24126                el.child(
24127                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24128                        .shape(IconButtonShape::Square)
24129                        .icon_size(IconSize::Small)
24130                        // .disabled(!has_multiple_hunks)
24131                        .tooltip({
24132                            let focus_handle = editor.focus_handle(cx);
24133                            move |window, cx| {
24134                                Tooltip::for_action_in(
24135                                    "Next Hunk",
24136                                    &GoToHunk,
24137                                    &focus_handle,
24138                                    window,
24139                                    cx,
24140                                )
24141                            }
24142                        })
24143                        .on_click({
24144                            let editor = editor.clone();
24145                            move |_event, window, cx| {
24146                                editor.update(cx, |editor, cx| {
24147                                    let snapshot = editor.snapshot(window, cx);
24148                                    let position =
24149                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24150                                    editor.go_to_hunk_before_or_after_position(
24151                                        &snapshot,
24152                                        position,
24153                                        Direction::Next,
24154                                        window,
24155                                        cx,
24156                                    );
24157                                    editor.expand_selected_diff_hunks(cx);
24158                                });
24159                            }
24160                        }),
24161                )
24162                .child(
24163                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24164                        .shape(IconButtonShape::Square)
24165                        .icon_size(IconSize::Small)
24166                        // .disabled(!has_multiple_hunks)
24167                        .tooltip({
24168                            let focus_handle = editor.focus_handle(cx);
24169                            move |window, cx| {
24170                                Tooltip::for_action_in(
24171                                    "Previous Hunk",
24172                                    &GoToPreviousHunk,
24173                                    &focus_handle,
24174                                    window,
24175                                    cx,
24176                                )
24177                            }
24178                        })
24179                        .on_click({
24180                            let editor = editor.clone();
24181                            move |_event, window, cx| {
24182                                editor.update(cx, |editor, cx| {
24183                                    let snapshot = editor.snapshot(window, cx);
24184                                    let point =
24185                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24186                                    editor.go_to_hunk_before_or_after_position(
24187                                        &snapshot,
24188                                        point,
24189                                        Direction::Prev,
24190                                        window,
24191                                        cx,
24192                                    );
24193                                    editor.expand_selected_diff_hunks(cx);
24194                                });
24195                            }
24196                        }),
24197                )
24198            },
24199        )
24200        .into_any_element()
24201}
24202
24203pub fn multibuffer_context_lines(cx: &App) -> u32 {
24204    EditorSettings::try_get(cx)
24205        .map(|settings| settings.excerpt_context_lines)
24206        .unwrap_or(2)
24207        .clamp(1, 32)
24208}