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    placeholder_display_map: Option<Entity<DisplayMap>>,
 1012    pub selections: SelectionsCollection,
 1013    pub scroll_manager: ScrollManager,
 1014    /// When inline assist editors are linked, they all render cursors because
 1015    /// typing enters text into each of them, even the ones that aren't focused.
 1016    pub(crate) show_cursor_when_unfocused: bool,
 1017    columnar_selection_state: Option<ColumnarSelectionState>,
 1018    add_selections_state: Option<AddSelectionsState>,
 1019    select_next_state: Option<SelectNextState>,
 1020    select_prev_state: Option<SelectNextState>,
 1021    selection_history: SelectionHistory,
 1022    defer_selection_effects: bool,
 1023    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1024    autoclose_regions: Vec<AutocloseRegion>,
 1025    snippet_stack: InvalidationStack<SnippetState>,
 1026    select_syntax_node_history: SelectSyntaxNodeHistory,
 1027    ime_transaction: Option<TransactionId>,
 1028    pub diagnostics_max_severity: DiagnosticSeverity,
 1029    active_diagnostics: ActiveDiagnostic,
 1030    show_inline_diagnostics: bool,
 1031    inline_diagnostics_update: Task<()>,
 1032    inline_diagnostics_enabled: bool,
 1033    diagnostics_enabled: bool,
 1034    word_completions_enabled: bool,
 1035    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1036    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1037    hard_wrap: Option<usize>,
 1038    project: Option<Entity<Project>>,
 1039    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1040    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1041    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1042    blink_manager: Entity<BlinkManager>,
 1043    show_cursor_names: bool,
 1044    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1045    pub show_local_selections: bool,
 1046    mode: EditorMode,
 1047    show_breadcrumbs: bool,
 1048    show_gutter: bool,
 1049    show_scrollbars: ScrollbarAxes,
 1050    minimap_visibility: MinimapVisibility,
 1051    offset_content: bool,
 1052    disable_expand_excerpt_buttons: bool,
 1053    show_line_numbers: Option<bool>,
 1054    use_relative_line_numbers: Option<bool>,
 1055    show_git_diff_gutter: Option<bool>,
 1056    show_code_actions: Option<bool>,
 1057    show_runnables: Option<bool>,
 1058    show_breakpoints: Option<bool>,
 1059    show_wrap_guides: Option<bool>,
 1060    show_indent_guides: Option<bool>,
 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_display_snapshot: Option<DisplaySnapshot>,
 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            placeholder_display_map: None,
 2070            selections,
 2071            scroll_manager: ScrollManager::new(cx),
 2072            columnar_selection_state: None,
 2073            add_selections_state: None,
 2074            select_next_state: None,
 2075            select_prev_state: None,
 2076            selection_history: SelectionHistory::default(),
 2077            defer_selection_effects: false,
 2078            deferred_selection_effects_state: None,
 2079            autoclose_regions: Vec::new(),
 2080            snippet_stack: InvalidationStack::default(),
 2081            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2082            ime_transaction: None,
 2083            active_diagnostics: ActiveDiagnostic::None,
 2084            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2085            inline_diagnostics_update: Task::ready(()),
 2086            inline_diagnostics: Vec::new(),
 2087            soft_wrap_mode_override,
 2088            diagnostics_max_severity,
 2089            hard_wrap: None,
 2090            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2091            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2092            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2093            project,
 2094            blink_manager: blink_manager.clone(),
 2095            show_local_selections: true,
 2096            show_scrollbars: ScrollbarAxes {
 2097                horizontal: full_mode,
 2098                vertical: full_mode,
 2099            },
 2100            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2101            offset_content: !matches!(mode, EditorMode::SingleLine),
 2102            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2103            show_gutter: full_mode,
 2104            show_line_numbers: (!full_mode).then_some(false),
 2105            use_relative_line_numbers: None,
 2106            disable_expand_excerpt_buttons: !full_mode,
 2107            show_git_diff_gutter: None,
 2108            show_code_actions: None,
 2109            show_runnables: None,
 2110            show_breakpoints: None,
 2111            show_wrap_guides: None,
 2112            show_indent_guides,
 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            placeholder_display_snapshot: self
 2732                .placeholder_display_map
 2733                .as_ref()
 2734                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2735            scroll_anchor: self.scroll_manager.anchor(),
 2736            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2737            is_focused: self.focus_handle.is_focused(window),
 2738            current_line_highlight: self
 2739                .current_line_highlight
 2740                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2741            gutter_hovered: self.gutter_hovered,
 2742        }
 2743    }
 2744
 2745    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2746        self.buffer.read(cx).language_at(point, cx)
 2747    }
 2748
 2749    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2750        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2751    }
 2752
 2753    pub fn active_excerpt(
 2754        &self,
 2755        cx: &App,
 2756    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2757        self.buffer
 2758            .read(cx)
 2759            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2760    }
 2761
 2762    pub fn mode(&self) -> &EditorMode {
 2763        &self.mode
 2764    }
 2765
 2766    pub fn set_mode(&mut self, mode: EditorMode) {
 2767        self.mode = mode;
 2768    }
 2769
 2770    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2771        self.collaboration_hub.as_deref()
 2772    }
 2773
 2774    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2775        self.collaboration_hub = Some(hub);
 2776    }
 2777
 2778    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2779        self.in_project_search = in_project_search;
 2780    }
 2781
 2782    pub fn set_custom_context_menu(
 2783        &mut self,
 2784        f: impl 'static
 2785        + Fn(
 2786            &mut Self,
 2787            DisplayPoint,
 2788            &mut Window,
 2789            &mut Context<Self>,
 2790        ) -> Option<Entity<ui::ContextMenu>>,
 2791    ) {
 2792        self.custom_context_menu = Some(Box::new(f))
 2793    }
 2794
 2795    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2796        self.completion_provider = provider;
 2797    }
 2798
 2799    #[cfg(any(test, feature = "test-support"))]
 2800    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2801        self.completion_provider.clone()
 2802    }
 2803
 2804    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2805        self.semantics_provider.clone()
 2806    }
 2807
 2808    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2809        self.semantics_provider = provider;
 2810    }
 2811
 2812    pub fn set_edit_prediction_provider<T>(
 2813        &mut self,
 2814        provider: Option<Entity<T>>,
 2815        window: &mut Window,
 2816        cx: &mut Context<Self>,
 2817    ) where
 2818        T: EditPredictionProvider,
 2819    {
 2820        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2821            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2822                if this.focus_handle.is_focused(window) {
 2823                    this.update_visible_edit_prediction(window, cx);
 2824                }
 2825            }),
 2826            provider: Arc::new(provider),
 2827        });
 2828        self.update_edit_prediction_settings(cx);
 2829        self.refresh_edit_prediction(false, false, window, cx);
 2830    }
 2831
 2832    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2833        self.placeholder_display_map
 2834            .as_ref()
 2835            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2836    }
 2837
 2838    pub fn set_placeholder_text(
 2839        &mut self,
 2840        placeholder_text: &str,
 2841        window: &mut Window,
 2842        cx: &mut Context<Self>,
 2843    ) {
 2844        let multibuffer = cx
 2845            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2846
 2847        let style = window.text_style();
 2848
 2849        self.placeholder_display_map = Some(cx.new(|cx| {
 2850            DisplayMap::new(
 2851                multibuffer,
 2852                style.font(),
 2853                style.font_size.to_pixels(window.rem_size()),
 2854                None,
 2855                FILE_HEADER_HEIGHT,
 2856                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2857                Default::default(),
 2858                DiagnosticSeverity::Off,
 2859                cx,
 2860            )
 2861        }));
 2862        cx.notify();
 2863    }
 2864
 2865    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2866        self.cursor_shape = cursor_shape;
 2867
 2868        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2869        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2870
 2871        cx.notify();
 2872    }
 2873
 2874    pub fn set_current_line_highlight(
 2875        &mut self,
 2876        current_line_highlight: Option<CurrentLineHighlight>,
 2877    ) {
 2878        self.current_line_highlight = current_line_highlight;
 2879    }
 2880
 2881    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2882        self.collapse_matches = collapse_matches;
 2883    }
 2884
 2885    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2886        let buffers = self.buffer.read(cx).all_buffers();
 2887        let Some(project) = self.project.as_ref() else {
 2888            return;
 2889        };
 2890        project.update(cx, |project, cx| {
 2891            for buffer in buffers {
 2892                self.registered_buffers
 2893                    .entry(buffer.read(cx).remote_id())
 2894                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2895            }
 2896        })
 2897    }
 2898
 2899    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2900        if self.collapse_matches {
 2901            return range.start..range.start;
 2902        }
 2903        range.clone()
 2904    }
 2905
 2906    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2907        if self.display_map.read(cx).clip_at_line_ends != clip {
 2908            self.display_map
 2909                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2910        }
 2911    }
 2912
 2913    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2914        self.input_enabled = input_enabled;
 2915    }
 2916
 2917    pub fn set_edit_predictions_hidden_for_vim_mode(
 2918        &mut self,
 2919        hidden: bool,
 2920        window: &mut Window,
 2921        cx: &mut Context<Self>,
 2922    ) {
 2923        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2924            self.edit_predictions_hidden_for_vim_mode = hidden;
 2925            if hidden {
 2926                self.update_visible_edit_prediction(window, cx);
 2927            } else {
 2928                self.refresh_edit_prediction(true, false, window, cx);
 2929            }
 2930        }
 2931    }
 2932
 2933    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2934        self.menu_edit_predictions_policy = value;
 2935    }
 2936
 2937    pub fn set_autoindent(&mut self, autoindent: bool) {
 2938        if autoindent {
 2939            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2940        } else {
 2941            self.autoindent_mode = None;
 2942        }
 2943    }
 2944
 2945    pub fn read_only(&self, cx: &App) -> bool {
 2946        self.read_only || self.buffer.read(cx).read_only()
 2947    }
 2948
 2949    pub fn set_read_only(&mut self, read_only: bool) {
 2950        self.read_only = read_only;
 2951    }
 2952
 2953    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2954        self.use_autoclose = autoclose;
 2955    }
 2956
 2957    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2958        self.use_auto_surround = auto_surround;
 2959    }
 2960
 2961    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2962        self.auto_replace_emoji_shortcode = auto_replace;
 2963    }
 2964
 2965    pub fn toggle_edit_predictions(
 2966        &mut self,
 2967        _: &ToggleEditPrediction,
 2968        window: &mut Window,
 2969        cx: &mut Context<Self>,
 2970    ) {
 2971        if self.show_edit_predictions_override.is_some() {
 2972            self.set_show_edit_predictions(None, window, cx);
 2973        } else {
 2974            let show_edit_predictions = !self.edit_predictions_enabled();
 2975            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2976        }
 2977    }
 2978
 2979    pub fn set_show_edit_predictions(
 2980        &mut self,
 2981        show_edit_predictions: Option<bool>,
 2982        window: &mut Window,
 2983        cx: &mut Context<Self>,
 2984    ) {
 2985        self.show_edit_predictions_override = show_edit_predictions;
 2986        self.update_edit_prediction_settings(cx);
 2987
 2988        if let Some(false) = show_edit_predictions {
 2989            self.discard_edit_prediction(false, cx);
 2990        } else {
 2991            self.refresh_edit_prediction(false, true, window, cx);
 2992        }
 2993    }
 2994
 2995    fn edit_predictions_disabled_in_scope(
 2996        &self,
 2997        buffer: &Entity<Buffer>,
 2998        buffer_position: language::Anchor,
 2999        cx: &App,
 3000    ) -> bool {
 3001        let snapshot = buffer.read(cx).snapshot();
 3002        let settings = snapshot.settings_at(buffer_position, cx);
 3003
 3004        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3005            return false;
 3006        };
 3007
 3008        scope.override_name().is_some_and(|scope_name| {
 3009            settings
 3010                .edit_predictions_disabled_in
 3011                .iter()
 3012                .any(|s| s == scope_name)
 3013        })
 3014    }
 3015
 3016    pub fn set_use_modal_editing(&mut self, to: bool) {
 3017        self.use_modal_editing = to;
 3018    }
 3019
 3020    pub fn use_modal_editing(&self) -> bool {
 3021        self.use_modal_editing
 3022    }
 3023
 3024    fn selections_did_change(
 3025        &mut self,
 3026        local: bool,
 3027        old_cursor_position: &Anchor,
 3028        effects: SelectionEffects,
 3029        window: &mut Window,
 3030        cx: &mut Context<Self>,
 3031    ) {
 3032        window.invalidate_character_coordinates();
 3033
 3034        // Copy selections to primary selection buffer
 3035        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3036        if local {
 3037            let selections = self.selections.all::<usize>(cx);
 3038            let buffer_handle = self.buffer.read(cx).read(cx);
 3039
 3040            let mut text = String::new();
 3041            for (index, selection) in selections.iter().enumerate() {
 3042                let text_for_selection = buffer_handle
 3043                    .text_for_range(selection.start..selection.end)
 3044                    .collect::<String>();
 3045
 3046                text.push_str(&text_for_selection);
 3047                if index != selections.len() - 1 {
 3048                    text.push('\n');
 3049                }
 3050            }
 3051
 3052            if !text.is_empty() {
 3053                cx.write_to_primary(ClipboardItem::new_string(text));
 3054            }
 3055        }
 3056
 3057        let selection_anchors = self.selections.disjoint_anchors();
 3058
 3059        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3060            self.buffer.update(cx, |buffer, cx| {
 3061                buffer.set_active_selections(
 3062                    &selection_anchors,
 3063                    self.selections.line_mode,
 3064                    self.cursor_shape,
 3065                    cx,
 3066                )
 3067            });
 3068        }
 3069        let display_map = self
 3070            .display_map
 3071            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3072        let buffer = &display_map.buffer_snapshot;
 3073        if self.selections.count() == 1 {
 3074            self.add_selections_state = None;
 3075        }
 3076        self.select_next_state = None;
 3077        self.select_prev_state = None;
 3078        self.select_syntax_node_history.try_clear();
 3079        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3080        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3081        self.take_rename(false, window, cx);
 3082
 3083        let newest_selection = self.selections.newest_anchor();
 3084        let new_cursor_position = newest_selection.head();
 3085        let selection_start = newest_selection.start;
 3086
 3087        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3088            self.push_to_nav_history(
 3089                *old_cursor_position,
 3090                Some(new_cursor_position.to_point(buffer)),
 3091                false,
 3092                effects.nav_history == Some(true),
 3093                cx,
 3094            );
 3095        }
 3096
 3097        if local {
 3098            if let Some(buffer_id) = new_cursor_position.buffer_id
 3099                && !self.registered_buffers.contains_key(&buffer_id)
 3100                && let Some(project) = self.project.as_ref()
 3101            {
 3102                project.update(cx, |project, cx| {
 3103                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3104                        return;
 3105                    };
 3106                    self.registered_buffers.insert(
 3107                        buffer_id,
 3108                        project.register_buffer_with_language_servers(&buffer, cx),
 3109                    );
 3110                })
 3111            }
 3112
 3113            let mut context_menu = self.context_menu.borrow_mut();
 3114            let completion_menu = match context_menu.as_ref() {
 3115                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3116                Some(CodeContextMenu::CodeActions(_)) => {
 3117                    *context_menu = None;
 3118                    None
 3119                }
 3120                None => None,
 3121            };
 3122            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3123            drop(context_menu);
 3124
 3125            if effects.completions
 3126                && let Some(completion_position) = completion_position
 3127            {
 3128                let start_offset = selection_start.to_offset(buffer);
 3129                let position_matches = start_offset == completion_position.to_offset(buffer);
 3130                let continue_showing = if position_matches {
 3131                    if self.snippet_stack.is_empty() {
 3132                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3133                    } else {
 3134                        // Snippet choices can be shown even when the cursor is in whitespace.
 3135                        // Dismissing the menu with actions like backspace is handled by
 3136                        // invalidation regions.
 3137                        true
 3138                    }
 3139                } else {
 3140                    false
 3141                };
 3142
 3143                if continue_showing {
 3144                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3145                } else {
 3146                    self.hide_context_menu(window, cx);
 3147                }
 3148            }
 3149
 3150            hide_hover(self, cx);
 3151
 3152            if old_cursor_position.to_display_point(&display_map).row()
 3153                != new_cursor_position.to_display_point(&display_map).row()
 3154            {
 3155                self.available_code_actions.take();
 3156            }
 3157            self.refresh_code_actions(window, cx);
 3158            self.refresh_document_highlights(cx);
 3159            self.refresh_selected_text_highlights(false, window, cx);
 3160            refresh_matching_bracket_highlights(self, window, cx);
 3161            self.update_visible_edit_prediction(window, cx);
 3162            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3163            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3164            self.inline_blame_popover.take();
 3165            if self.git_blame_inline_enabled {
 3166                self.start_inline_blame_timer(window, cx);
 3167            }
 3168        }
 3169
 3170        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3171        cx.emit(EditorEvent::SelectionsChanged { local });
 3172
 3173        let selections = &self.selections.disjoint;
 3174        if selections.len() == 1 {
 3175            cx.emit(SearchEvent::ActiveMatchChanged)
 3176        }
 3177        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3178            let inmemory_selections = selections
 3179                .iter()
 3180                .map(|s| {
 3181                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3182                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3183                })
 3184                .collect();
 3185            self.update_restoration_data(cx, |data| {
 3186                data.selections = inmemory_selections;
 3187            });
 3188
 3189            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3190                && let Some(workspace_id) =
 3191                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3192            {
 3193                let snapshot = self.buffer().read(cx).snapshot(cx);
 3194                let selections = selections.clone();
 3195                let background_executor = cx.background_executor().clone();
 3196                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3197                self.serialize_selections = cx.background_spawn(async move {
 3198                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3199                            let db_selections = selections
 3200                                .iter()
 3201                                .map(|selection| {
 3202                                    (
 3203                                        selection.start.to_offset(&snapshot),
 3204                                        selection.end.to_offset(&snapshot),
 3205                                    )
 3206                                })
 3207                                .collect();
 3208
 3209                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3210                                .await
 3211                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3212                                .log_err();
 3213                        });
 3214            }
 3215        }
 3216
 3217        cx.notify();
 3218    }
 3219
 3220    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3221        use text::ToOffset as _;
 3222        use text::ToPoint as _;
 3223
 3224        if self.mode.is_minimap()
 3225            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3226        {
 3227            return;
 3228        }
 3229
 3230        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3231            return;
 3232        };
 3233
 3234        let snapshot = singleton.read(cx).snapshot();
 3235        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3236            let display_snapshot = display_map.snapshot(cx);
 3237
 3238            display_snapshot
 3239                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3240                .map(|fold| {
 3241                    fold.range.start.text_anchor.to_point(&snapshot)
 3242                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3243                })
 3244                .collect()
 3245        });
 3246        self.update_restoration_data(cx, |data| {
 3247            data.folds = inmemory_folds;
 3248        });
 3249
 3250        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3251            return;
 3252        };
 3253        let background_executor = cx.background_executor().clone();
 3254        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3255        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3256            display_map
 3257                .snapshot(cx)
 3258                .folds_in_range(0..snapshot.len())
 3259                .map(|fold| {
 3260                    (
 3261                        fold.range.start.text_anchor.to_offset(&snapshot),
 3262                        fold.range.end.text_anchor.to_offset(&snapshot),
 3263                    )
 3264                })
 3265                .collect()
 3266        });
 3267        self.serialize_folds = cx.background_spawn(async move {
 3268            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3269            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3270                .await
 3271                .with_context(|| {
 3272                    format!(
 3273                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3274                    )
 3275                })
 3276                .log_err();
 3277        });
 3278    }
 3279
 3280    pub fn sync_selections(
 3281        &mut self,
 3282        other: Entity<Editor>,
 3283        cx: &mut Context<Self>,
 3284    ) -> gpui::Subscription {
 3285        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3286        self.selections.change_with(cx, |selections| {
 3287            selections.select_anchors(other_selections);
 3288        });
 3289
 3290        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3291            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3292                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3293                if other_selections.is_empty() {
 3294                    return;
 3295                }
 3296                this.selections.change_with(cx, |selections| {
 3297                    selections.select_anchors(other_selections);
 3298                });
 3299            }
 3300        });
 3301
 3302        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3303            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3304                let these_selections = this.selections.disjoint.to_vec();
 3305                if these_selections.is_empty() {
 3306                    return;
 3307                }
 3308                other.update(cx, |other_editor, cx| {
 3309                    other_editor.selections.change_with(cx, |selections| {
 3310                        selections.select_anchors(these_selections);
 3311                    })
 3312                });
 3313            }
 3314        });
 3315
 3316        Subscription::join(other_subscription, this_subscription)
 3317    }
 3318
 3319    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3320    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3321    /// effects of selection change occur at the end of the transaction.
 3322    pub fn change_selections<R>(
 3323        &mut self,
 3324        effects: SelectionEffects,
 3325        window: &mut Window,
 3326        cx: &mut Context<Self>,
 3327        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3328    ) -> R {
 3329        if let Some(state) = &mut self.deferred_selection_effects_state {
 3330            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3331            state.effects.completions = effects.completions;
 3332            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3333            let (changed, result) = self.selections.change_with(cx, change);
 3334            state.changed |= changed;
 3335            return result;
 3336        }
 3337        let mut state = DeferredSelectionEffectsState {
 3338            changed: false,
 3339            effects,
 3340            old_cursor_position: self.selections.newest_anchor().head(),
 3341            history_entry: SelectionHistoryEntry {
 3342                selections: self.selections.disjoint_anchors(),
 3343                select_next_state: self.select_next_state.clone(),
 3344                select_prev_state: self.select_prev_state.clone(),
 3345                add_selections_state: self.add_selections_state.clone(),
 3346            },
 3347        };
 3348        let (changed, result) = self.selections.change_with(cx, change);
 3349        state.changed = state.changed || changed;
 3350        if self.defer_selection_effects {
 3351            self.deferred_selection_effects_state = Some(state);
 3352        } else {
 3353            self.apply_selection_effects(state, window, cx);
 3354        }
 3355        result
 3356    }
 3357
 3358    /// Defers the effects of selection change, so that the effects of multiple calls to
 3359    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3360    /// to selection history and the state of popovers based on selection position aren't
 3361    /// erroneously updated.
 3362    pub fn with_selection_effects_deferred<R>(
 3363        &mut self,
 3364        window: &mut Window,
 3365        cx: &mut Context<Self>,
 3366        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3367    ) -> R {
 3368        let already_deferred = self.defer_selection_effects;
 3369        self.defer_selection_effects = true;
 3370        let result = update(self, window, cx);
 3371        if !already_deferred {
 3372            self.defer_selection_effects = false;
 3373            if let Some(state) = self.deferred_selection_effects_state.take() {
 3374                self.apply_selection_effects(state, window, cx);
 3375            }
 3376        }
 3377        result
 3378    }
 3379
 3380    fn apply_selection_effects(
 3381        &mut self,
 3382        state: DeferredSelectionEffectsState,
 3383        window: &mut Window,
 3384        cx: &mut Context<Self>,
 3385    ) {
 3386        if state.changed {
 3387            self.selection_history.push(state.history_entry);
 3388
 3389            if let Some(autoscroll) = state.effects.scroll {
 3390                self.request_autoscroll(autoscroll, cx);
 3391            }
 3392
 3393            let old_cursor_position = &state.old_cursor_position;
 3394
 3395            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3396
 3397            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3398                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3399            }
 3400        }
 3401    }
 3402
 3403    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3404    where
 3405        I: IntoIterator<Item = (Range<S>, T)>,
 3406        S: ToOffset,
 3407        T: Into<Arc<str>>,
 3408    {
 3409        if self.read_only(cx) {
 3410            return;
 3411        }
 3412
 3413        self.buffer
 3414            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3415    }
 3416
 3417    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3418    where
 3419        I: IntoIterator<Item = (Range<S>, T)>,
 3420        S: ToOffset,
 3421        T: Into<Arc<str>>,
 3422    {
 3423        if self.read_only(cx) {
 3424            return;
 3425        }
 3426
 3427        self.buffer.update(cx, |buffer, cx| {
 3428            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3429        });
 3430    }
 3431
 3432    pub fn edit_with_block_indent<I, S, T>(
 3433        &mut self,
 3434        edits: I,
 3435        original_indent_columns: Vec<Option<u32>>,
 3436        cx: &mut Context<Self>,
 3437    ) where
 3438        I: IntoIterator<Item = (Range<S>, T)>,
 3439        S: ToOffset,
 3440        T: Into<Arc<str>>,
 3441    {
 3442        if self.read_only(cx) {
 3443            return;
 3444        }
 3445
 3446        self.buffer.update(cx, |buffer, cx| {
 3447            buffer.edit(
 3448                edits,
 3449                Some(AutoindentMode::Block {
 3450                    original_indent_columns,
 3451                }),
 3452                cx,
 3453            )
 3454        });
 3455    }
 3456
 3457    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3458        self.hide_context_menu(window, cx);
 3459
 3460        match phase {
 3461            SelectPhase::Begin {
 3462                position,
 3463                add,
 3464                click_count,
 3465            } => self.begin_selection(position, add, click_count, window, cx),
 3466            SelectPhase::BeginColumnar {
 3467                position,
 3468                goal_column,
 3469                reset,
 3470                mode,
 3471            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3472            SelectPhase::Extend {
 3473                position,
 3474                click_count,
 3475            } => self.extend_selection(position, click_count, window, cx),
 3476            SelectPhase::Update {
 3477                position,
 3478                goal_column,
 3479                scroll_delta,
 3480            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3481            SelectPhase::End => self.end_selection(window, cx),
 3482        }
 3483    }
 3484
 3485    fn extend_selection(
 3486        &mut self,
 3487        position: DisplayPoint,
 3488        click_count: usize,
 3489        window: &mut Window,
 3490        cx: &mut Context<Self>,
 3491    ) {
 3492        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3493        let tail = self.selections.newest::<usize>(cx).tail();
 3494        self.begin_selection(position, false, click_count, window, cx);
 3495
 3496        let position = position.to_offset(&display_map, Bias::Left);
 3497        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3498
 3499        let mut pending_selection = self
 3500            .selections
 3501            .pending_anchor()
 3502            .expect("extend_selection not called with pending selection");
 3503        if position >= tail {
 3504            pending_selection.start = tail_anchor;
 3505        } else {
 3506            pending_selection.end = tail_anchor;
 3507            pending_selection.reversed = true;
 3508        }
 3509
 3510        let mut pending_mode = self.selections.pending_mode().unwrap();
 3511        match &mut pending_mode {
 3512            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3513            _ => {}
 3514        }
 3515
 3516        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3517            SelectionEffects::scroll(Autoscroll::fit())
 3518        } else {
 3519            SelectionEffects::no_scroll()
 3520        };
 3521
 3522        self.change_selections(effects, window, cx, |s| {
 3523            s.set_pending(pending_selection, pending_mode)
 3524        });
 3525    }
 3526
 3527    fn begin_selection(
 3528        &mut self,
 3529        position: DisplayPoint,
 3530        add: bool,
 3531        click_count: usize,
 3532        window: &mut Window,
 3533        cx: &mut Context<Self>,
 3534    ) {
 3535        if !self.focus_handle.is_focused(window) {
 3536            self.last_focused_descendant = None;
 3537            window.focus(&self.focus_handle);
 3538        }
 3539
 3540        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3541        let buffer = &display_map.buffer_snapshot;
 3542        let position = display_map.clip_point(position, Bias::Left);
 3543
 3544        let start;
 3545        let end;
 3546        let mode;
 3547        let mut auto_scroll;
 3548        match click_count {
 3549            1 => {
 3550                start = buffer.anchor_before(position.to_point(&display_map));
 3551                end = start;
 3552                mode = SelectMode::Character;
 3553                auto_scroll = true;
 3554            }
 3555            2 => {
 3556                let position = display_map
 3557                    .clip_point(position, Bias::Left)
 3558                    .to_offset(&display_map, Bias::Left);
 3559                let (range, _) = buffer.surrounding_word(position, false);
 3560                start = buffer.anchor_before(range.start);
 3561                end = buffer.anchor_before(range.end);
 3562                mode = SelectMode::Word(start..end);
 3563                auto_scroll = true;
 3564            }
 3565            3 => {
 3566                let position = display_map
 3567                    .clip_point(position, Bias::Left)
 3568                    .to_point(&display_map);
 3569                let line_start = display_map.prev_line_boundary(position).0;
 3570                let next_line_start = buffer.clip_point(
 3571                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3572                    Bias::Left,
 3573                );
 3574                start = buffer.anchor_before(line_start);
 3575                end = buffer.anchor_before(next_line_start);
 3576                mode = SelectMode::Line(start..end);
 3577                auto_scroll = true;
 3578            }
 3579            _ => {
 3580                start = buffer.anchor_before(0);
 3581                end = buffer.anchor_before(buffer.len());
 3582                mode = SelectMode::All;
 3583                auto_scroll = false;
 3584            }
 3585        }
 3586        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3587
 3588        let point_to_delete: Option<usize> = {
 3589            let selected_points: Vec<Selection<Point>> =
 3590                self.selections.disjoint_in_range(start..end, cx);
 3591
 3592            if !add || click_count > 1 {
 3593                None
 3594            } else if !selected_points.is_empty() {
 3595                Some(selected_points[0].id)
 3596            } else {
 3597                let clicked_point_already_selected =
 3598                    self.selections.disjoint.iter().find(|selection| {
 3599                        selection.start.to_point(buffer) == start.to_point(buffer)
 3600                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3601                    });
 3602
 3603                clicked_point_already_selected.map(|selection| selection.id)
 3604            }
 3605        };
 3606
 3607        let selections_count = self.selections.count();
 3608        let effects = if auto_scroll {
 3609            SelectionEffects::default()
 3610        } else {
 3611            SelectionEffects::no_scroll()
 3612        };
 3613
 3614        self.change_selections(effects, window, cx, |s| {
 3615            if let Some(point_to_delete) = point_to_delete {
 3616                s.delete(point_to_delete);
 3617
 3618                if selections_count == 1 {
 3619                    s.set_pending_anchor_range(start..end, mode);
 3620                }
 3621            } else {
 3622                if !add {
 3623                    s.clear_disjoint();
 3624                }
 3625
 3626                s.set_pending_anchor_range(start..end, mode);
 3627            }
 3628        });
 3629    }
 3630
 3631    fn begin_columnar_selection(
 3632        &mut self,
 3633        position: DisplayPoint,
 3634        goal_column: u32,
 3635        reset: bool,
 3636        mode: ColumnarMode,
 3637        window: &mut Window,
 3638        cx: &mut Context<Self>,
 3639    ) {
 3640        if !self.focus_handle.is_focused(window) {
 3641            self.last_focused_descendant = None;
 3642            window.focus(&self.focus_handle);
 3643        }
 3644
 3645        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3646
 3647        if reset {
 3648            let pointer_position = display_map
 3649                .buffer_snapshot
 3650                .anchor_before(position.to_point(&display_map));
 3651
 3652            self.change_selections(
 3653                SelectionEffects::scroll(Autoscroll::newest()),
 3654                window,
 3655                cx,
 3656                |s| {
 3657                    s.clear_disjoint();
 3658                    s.set_pending_anchor_range(
 3659                        pointer_position..pointer_position,
 3660                        SelectMode::Character,
 3661                    );
 3662                },
 3663            );
 3664        };
 3665
 3666        let tail = self.selections.newest::<Point>(cx).tail();
 3667        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3668        self.columnar_selection_state = match mode {
 3669            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3670                selection_tail: selection_anchor,
 3671                display_point: if reset {
 3672                    if position.column() != goal_column {
 3673                        Some(DisplayPoint::new(position.row(), goal_column))
 3674                    } else {
 3675                        None
 3676                    }
 3677                } else {
 3678                    None
 3679                },
 3680            }),
 3681            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3682                selection_tail: selection_anchor,
 3683            }),
 3684        };
 3685
 3686        if !reset {
 3687            self.select_columns(position, goal_column, &display_map, window, cx);
 3688        }
 3689    }
 3690
 3691    fn update_selection(
 3692        &mut self,
 3693        position: DisplayPoint,
 3694        goal_column: u32,
 3695        scroll_delta: gpui::Point<f32>,
 3696        window: &mut Window,
 3697        cx: &mut Context<Self>,
 3698    ) {
 3699        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3700
 3701        if self.columnar_selection_state.is_some() {
 3702            self.select_columns(position, goal_column, &display_map, window, cx);
 3703        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3704            let buffer = &display_map.buffer_snapshot;
 3705            let head;
 3706            let tail;
 3707            let mode = self.selections.pending_mode().unwrap();
 3708            match &mode {
 3709                SelectMode::Character => {
 3710                    head = position.to_point(&display_map);
 3711                    tail = pending.tail().to_point(buffer);
 3712                }
 3713                SelectMode::Word(original_range) => {
 3714                    let offset = display_map
 3715                        .clip_point(position, Bias::Left)
 3716                        .to_offset(&display_map, Bias::Left);
 3717                    let original_range = original_range.to_offset(buffer);
 3718
 3719                    let head_offset = if buffer.is_inside_word(offset, false)
 3720                        || original_range.contains(&offset)
 3721                    {
 3722                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3723                        if word_range.start < original_range.start {
 3724                            word_range.start
 3725                        } else {
 3726                            word_range.end
 3727                        }
 3728                    } else {
 3729                        offset
 3730                    };
 3731
 3732                    head = head_offset.to_point(buffer);
 3733                    if head_offset <= original_range.start {
 3734                        tail = original_range.end.to_point(buffer);
 3735                    } else {
 3736                        tail = original_range.start.to_point(buffer);
 3737                    }
 3738                }
 3739                SelectMode::Line(original_range) => {
 3740                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3741
 3742                    let position = display_map
 3743                        .clip_point(position, Bias::Left)
 3744                        .to_point(&display_map);
 3745                    let line_start = display_map.prev_line_boundary(position).0;
 3746                    let next_line_start = buffer.clip_point(
 3747                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3748                        Bias::Left,
 3749                    );
 3750
 3751                    if line_start < original_range.start {
 3752                        head = line_start
 3753                    } else {
 3754                        head = next_line_start
 3755                    }
 3756
 3757                    if head <= original_range.start {
 3758                        tail = original_range.end;
 3759                    } else {
 3760                        tail = original_range.start;
 3761                    }
 3762                }
 3763                SelectMode::All => {
 3764                    return;
 3765                }
 3766            };
 3767
 3768            if head < tail {
 3769                pending.start = buffer.anchor_before(head);
 3770                pending.end = buffer.anchor_before(tail);
 3771                pending.reversed = true;
 3772            } else {
 3773                pending.start = buffer.anchor_before(tail);
 3774                pending.end = buffer.anchor_before(head);
 3775                pending.reversed = false;
 3776            }
 3777
 3778            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3779                s.set_pending(pending, mode);
 3780            });
 3781        } else {
 3782            log::error!("update_selection dispatched with no pending selection");
 3783            return;
 3784        }
 3785
 3786        self.apply_scroll_delta(scroll_delta, window, cx);
 3787        cx.notify();
 3788    }
 3789
 3790    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3791        self.columnar_selection_state.take();
 3792        if self.selections.pending_anchor().is_some() {
 3793            let selections = self.selections.all::<usize>(cx);
 3794            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3795                s.select(selections);
 3796                s.clear_pending();
 3797            });
 3798        }
 3799    }
 3800
 3801    fn select_columns(
 3802        &mut self,
 3803        head: DisplayPoint,
 3804        goal_column: u32,
 3805        display_map: &DisplaySnapshot,
 3806        window: &mut Window,
 3807        cx: &mut Context<Self>,
 3808    ) {
 3809        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3810            return;
 3811        };
 3812
 3813        let tail = match columnar_state {
 3814            ColumnarSelectionState::FromMouse {
 3815                selection_tail,
 3816                display_point,
 3817            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3818            ColumnarSelectionState::FromSelection { selection_tail } => {
 3819                selection_tail.to_display_point(display_map)
 3820            }
 3821        };
 3822
 3823        let start_row = cmp::min(tail.row(), head.row());
 3824        let end_row = cmp::max(tail.row(), head.row());
 3825        let start_column = cmp::min(tail.column(), goal_column);
 3826        let end_column = cmp::max(tail.column(), goal_column);
 3827        let reversed = start_column < tail.column();
 3828
 3829        let selection_ranges = (start_row.0..=end_row.0)
 3830            .map(DisplayRow)
 3831            .filter_map(|row| {
 3832                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3833                    || start_column <= display_map.line_len(row))
 3834                    && !display_map.is_block_line(row)
 3835                {
 3836                    let start = display_map
 3837                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3838                        .to_point(display_map);
 3839                    let end = display_map
 3840                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3841                        .to_point(display_map);
 3842                    if reversed {
 3843                        Some(end..start)
 3844                    } else {
 3845                        Some(start..end)
 3846                    }
 3847                } else {
 3848                    None
 3849                }
 3850            })
 3851            .collect::<Vec<_>>();
 3852
 3853        let ranges = match columnar_state {
 3854            ColumnarSelectionState::FromMouse { .. } => {
 3855                let mut non_empty_ranges = selection_ranges
 3856                    .iter()
 3857                    .filter(|selection_range| selection_range.start != selection_range.end)
 3858                    .peekable();
 3859                if non_empty_ranges.peek().is_some() {
 3860                    non_empty_ranges.cloned().collect()
 3861                } else {
 3862                    selection_ranges
 3863                }
 3864            }
 3865            _ => selection_ranges,
 3866        };
 3867
 3868        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3869            s.select_ranges(ranges);
 3870        });
 3871        cx.notify();
 3872    }
 3873
 3874    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3875        self.selections
 3876            .all_adjusted(cx)
 3877            .iter()
 3878            .any(|selection| !selection.is_empty())
 3879    }
 3880
 3881    pub fn has_pending_nonempty_selection(&self) -> bool {
 3882        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3883            Some(Selection { start, end, .. }) => start != end,
 3884            None => false,
 3885        };
 3886
 3887        pending_nonempty_selection
 3888            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3889    }
 3890
 3891    pub fn has_pending_selection(&self) -> bool {
 3892        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3893    }
 3894
 3895    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3896        self.selection_mark_mode = false;
 3897        self.selection_drag_state = SelectionDragState::None;
 3898
 3899        if self.clear_expanded_diff_hunks(cx) {
 3900            cx.notify();
 3901            return;
 3902        }
 3903        if self.dismiss_menus_and_popups(true, window, cx) {
 3904            return;
 3905        }
 3906
 3907        if self.mode.is_full()
 3908            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3909        {
 3910            return;
 3911        }
 3912
 3913        cx.propagate();
 3914    }
 3915
 3916    pub fn dismiss_menus_and_popups(
 3917        &mut self,
 3918        is_user_requested: bool,
 3919        window: &mut Window,
 3920        cx: &mut Context<Self>,
 3921    ) -> bool {
 3922        if self.take_rename(false, window, cx).is_some() {
 3923            return true;
 3924        }
 3925
 3926        if hide_hover(self, cx) {
 3927            return true;
 3928        }
 3929
 3930        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3931            return true;
 3932        }
 3933
 3934        if self.hide_context_menu(window, cx).is_some() {
 3935            return true;
 3936        }
 3937
 3938        if self.mouse_context_menu.take().is_some() {
 3939            return true;
 3940        }
 3941
 3942        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3943            return true;
 3944        }
 3945
 3946        if self.snippet_stack.pop().is_some() {
 3947            return true;
 3948        }
 3949
 3950        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3951            self.dismiss_diagnostics(cx);
 3952            return true;
 3953        }
 3954
 3955        false
 3956    }
 3957
 3958    fn linked_editing_ranges_for(
 3959        &self,
 3960        selection: Range<text::Anchor>,
 3961        cx: &App,
 3962    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3963        if self.linked_edit_ranges.is_empty() {
 3964            return None;
 3965        }
 3966        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3967            selection.end.buffer_id.and_then(|end_buffer_id| {
 3968                if selection.start.buffer_id != Some(end_buffer_id) {
 3969                    return None;
 3970                }
 3971                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3972                let snapshot = buffer.read(cx).snapshot();
 3973                self.linked_edit_ranges
 3974                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3975                    .map(|ranges| (ranges, snapshot, buffer))
 3976            })?;
 3977        use text::ToOffset as TO;
 3978        // find offset from the start of current range to current cursor position
 3979        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3980
 3981        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3982        let start_difference = start_offset - start_byte_offset;
 3983        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3984        let end_difference = end_offset - start_byte_offset;
 3985        // Current range has associated linked ranges.
 3986        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3987        for range in linked_ranges.iter() {
 3988            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3989            let end_offset = start_offset + end_difference;
 3990            let start_offset = start_offset + start_difference;
 3991            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3992                continue;
 3993            }
 3994            if self.selections.disjoint_anchor_ranges().any(|s| {
 3995                if s.start.buffer_id != selection.start.buffer_id
 3996                    || s.end.buffer_id != selection.end.buffer_id
 3997                {
 3998                    return false;
 3999                }
 4000                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4001                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4002            }) {
 4003                continue;
 4004            }
 4005            let start = buffer_snapshot.anchor_after(start_offset);
 4006            let end = buffer_snapshot.anchor_after(end_offset);
 4007            linked_edits
 4008                .entry(buffer.clone())
 4009                .or_default()
 4010                .push(start..end);
 4011        }
 4012        Some(linked_edits)
 4013    }
 4014
 4015    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4016        let text: Arc<str> = text.into();
 4017
 4018        if self.read_only(cx) {
 4019            return;
 4020        }
 4021
 4022        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4023
 4024        let selections = self.selections.all_adjusted(cx);
 4025        let mut bracket_inserted = false;
 4026        let mut edits = Vec::new();
 4027        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4028        let mut new_selections = Vec::with_capacity(selections.len());
 4029        let mut new_autoclose_regions = Vec::new();
 4030        let snapshot = self.buffer.read(cx).read(cx);
 4031        let mut clear_linked_edit_ranges = false;
 4032
 4033        for (selection, autoclose_region) in
 4034            self.selections_with_autoclose_regions(selections, &snapshot)
 4035        {
 4036            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4037                // Determine if the inserted text matches the opening or closing
 4038                // bracket of any of this language's bracket pairs.
 4039                let mut bracket_pair = None;
 4040                let mut is_bracket_pair_start = false;
 4041                let mut is_bracket_pair_end = false;
 4042                if !text.is_empty() {
 4043                    let mut bracket_pair_matching_end = None;
 4044                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4045                    //  and they are removing the character that triggered IME popup.
 4046                    for (pair, enabled) in scope.brackets() {
 4047                        if !pair.close && !pair.surround {
 4048                            continue;
 4049                        }
 4050
 4051                        if enabled && pair.start.ends_with(text.as_ref()) {
 4052                            let prefix_len = pair.start.len() - text.len();
 4053                            let preceding_text_matches_prefix = prefix_len == 0
 4054                                || (selection.start.column >= (prefix_len as u32)
 4055                                    && snapshot.contains_str_at(
 4056                                        Point::new(
 4057                                            selection.start.row,
 4058                                            selection.start.column - (prefix_len as u32),
 4059                                        ),
 4060                                        &pair.start[..prefix_len],
 4061                                    ));
 4062                            if preceding_text_matches_prefix {
 4063                                bracket_pair = Some(pair.clone());
 4064                                is_bracket_pair_start = true;
 4065                                break;
 4066                            }
 4067                        }
 4068                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4069                        {
 4070                            // take first bracket pair matching end, but don't break in case a later bracket
 4071                            // pair matches start
 4072                            bracket_pair_matching_end = Some(pair.clone());
 4073                        }
 4074                    }
 4075                    if let Some(end) = bracket_pair_matching_end
 4076                        && bracket_pair.is_none()
 4077                    {
 4078                        bracket_pair = Some(end);
 4079                        is_bracket_pair_end = true;
 4080                    }
 4081                }
 4082
 4083                if let Some(bracket_pair) = bracket_pair {
 4084                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4085                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4086                    let auto_surround =
 4087                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4088                    if selection.is_empty() {
 4089                        if is_bracket_pair_start {
 4090                            // If the inserted text is a suffix of an opening bracket and the
 4091                            // selection is preceded by the rest of the opening bracket, then
 4092                            // insert the closing bracket.
 4093                            let following_text_allows_autoclose = snapshot
 4094                                .chars_at(selection.start)
 4095                                .next()
 4096                                .is_none_or(|c| scope.should_autoclose_before(c));
 4097
 4098                            let preceding_text_allows_autoclose = selection.start.column == 0
 4099                                || snapshot
 4100                                    .reversed_chars_at(selection.start)
 4101                                    .next()
 4102                                    .is_none_or(|c| {
 4103                                        bracket_pair.start != bracket_pair.end
 4104                                            || !snapshot
 4105                                                .char_classifier_at(selection.start)
 4106                                                .is_word(c)
 4107                                    });
 4108
 4109                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4110                                && bracket_pair.start.len() == 1
 4111                            {
 4112                                let target = bracket_pair.start.chars().next().unwrap();
 4113                                let current_line_count = snapshot
 4114                                    .reversed_chars_at(selection.start)
 4115                                    .take_while(|&c| c != '\n')
 4116                                    .filter(|&c| c == target)
 4117                                    .count();
 4118                                current_line_count % 2 == 1
 4119                            } else {
 4120                                false
 4121                            };
 4122
 4123                            if autoclose
 4124                                && bracket_pair.close
 4125                                && following_text_allows_autoclose
 4126                                && preceding_text_allows_autoclose
 4127                                && !is_closing_quote
 4128                            {
 4129                                let anchor = snapshot.anchor_before(selection.end);
 4130                                new_selections.push((selection.map(|_| anchor), text.len()));
 4131                                new_autoclose_regions.push((
 4132                                    anchor,
 4133                                    text.len(),
 4134                                    selection.id,
 4135                                    bracket_pair.clone(),
 4136                                ));
 4137                                edits.push((
 4138                                    selection.range(),
 4139                                    format!("{}{}", text, bracket_pair.end).into(),
 4140                                ));
 4141                                bracket_inserted = true;
 4142                                continue;
 4143                            }
 4144                        }
 4145
 4146                        if let Some(region) = autoclose_region {
 4147                            // If the selection is followed by an auto-inserted closing bracket,
 4148                            // then don't insert that closing bracket again; just move the selection
 4149                            // past the closing bracket.
 4150                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4151                                && text.as_ref() == region.pair.end.as_str()
 4152                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4153                            if should_skip {
 4154                                let anchor = snapshot.anchor_after(selection.end);
 4155                                new_selections
 4156                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4157                                continue;
 4158                            }
 4159                        }
 4160
 4161                        let always_treat_brackets_as_autoclosed = snapshot
 4162                            .language_settings_at(selection.start, cx)
 4163                            .always_treat_brackets_as_autoclosed;
 4164                        if always_treat_brackets_as_autoclosed
 4165                            && is_bracket_pair_end
 4166                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4167                        {
 4168                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4169                            // and the inserted text is a closing bracket and the selection is followed
 4170                            // by the closing bracket then move the selection past the closing bracket.
 4171                            let anchor = snapshot.anchor_after(selection.end);
 4172                            new_selections.push((selection.map(|_| anchor), text.len()));
 4173                            continue;
 4174                        }
 4175                    }
 4176                    // If an opening bracket is 1 character long and is typed while
 4177                    // text is selected, then surround that text with the bracket pair.
 4178                    else if auto_surround
 4179                        && bracket_pair.surround
 4180                        && is_bracket_pair_start
 4181                        && bracket_pair.start.chars().count() == 1
 4182                    {
 4183                        edits.push((selection.start..selection.start, text.clone()));
 4184                        edits.push((
 4185                            selection.end..selection.end,
 4186                            bracket_pair.end.as_str().into(),
 4187                        ));
 4188                        bracket_inserted = true;
 4189                        new_selections.push((
 4190                            Selection {
 4191                                id: selection.id,
 4192                                start: snapshot.anchor_after(selection.start),
 4193                                end: snapshot.anchor_before(selection.end),
 4194                                reversed: selection.reversed,
 4195                                goal: selection.goal,
 4196                            },
 4197                            0,
 4198                        ));
 4199                        continue;
 4200                    }
 4201                }
 4202            }
 4203
 4204            if self.auto_replace_emoji_shortcode
 4205                && selection.is_empty()
 4206                && text.as_ref().ends_with(':')
 4207                && let Some(possible_emoji_short_code) =
 4208                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4209                && !possible_emoji_short_code.is_empty()
 4210                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4211            {
 4212                let emoji_shortcode_start = Point::new(
 4213                    selection.start.row,
 4214                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4215                );
 4216
 4217                // Remove shortcode from buffer
 4218                edits.push((
 4219                    emoji_shortcode_start..selection.start,
 4220                    "".to_string().into(),
 4221                ));
 4222                new_selections.push((
 4223                    Selection {
 4224                        id: selection.id,
 4225                        start: snapshot.anchor_after(emoji_shortcode_start),
 4226                        end: snapshot.anchor_before(selection.start),
 4227                        reversed: selection.reversed,
 4228                        goal: selection.goal,
 4229                    },
 4230                    0,
 4231                ));
 4232
 4233                // Insert emoji
 4234                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4235                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4236                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4237
 4238                continue;
 4239            }
 4240
 4241            // If not handling any auto-close operation, then just replace the selected
 4242            // text with the given input and move the selection to the end of the
 4243            // newly inserted text.
 4244            let anchor = snapshot.anchor_after(selection.end);
 4245            if !self.linked_edit_ranges.is_empty() {
 4246                let start_anchor = snapshot.anchor_before(selection.start);
 4247
 4248                let is_word_char = text.chars().next().is_none_or(|char| {
 4249                    let classifier = snapshot
 4250                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4251                        .ignore_punctuation(true);
 4252                    classifier.is_word(char)
 4253                });
 4254
 4255                if is_word_char {
 4256                    if let Some(ranges) = self
 4257                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4258                    {
 4259                        for (buffer, edits) in ranges {
 4260                            linked_edits
 4261                                .entry(buffer.clone())
 4262                                .or_default()
 4263                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4264                        }
 4265                    }
 4266                } else {
 4267                    clear_linked_edit_ranges = true;
 4268                }
 4269            }
 4270
 4271            new_selections.push((selection.map(|_| anchor), 0));
 4272            edits.push((selection.start..selection.end, text.clone()));
 4273        }
 4274
 4275        drop(snapshot);
 4276
 4277        self.transact(window, cx, |this, window, cx| {
 4278            if clear_linked_edit_ranges {
 4279                this.linked_edit_ranges.clear();
 4280            }
 4281            let initial_buffer_versions =
 4282                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4283
 4284            this.buffer.update(cx, |buffer, cx| {
 4285                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4286            });
 4287            for (buffer, edits) in linked_edits {
 4288                buffer.update(cx, |buffer, cx| {
 4289                    let snapshot = buffer.snapshot();
 4290                    let edits = edits
 4291                        .into_iter()
 4292                        .map(|(range, text)| {
 4293                            use text::ToPoint as TP;
 4294                            let end_point = TP::to_point(&range.end, &snapshot);
 4295                            let start_point = TP::to_point(&range.start, &snapshot);
 4296                            (start_point..end_point, text)
 4297                        })
 4298                        .sorted_by_key(|(range, _)| range.start);
 4299                    buffer.edit(edits, None, cx);
 4300                })
 4301            }
 4302            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4303            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4304            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4305            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4306                .zip(new_selection_deltas)
 4307                .map(|(selection, delta)| Selection {
 4308                    id: selection.id,
 4309                    start: selection.start + delta,
 4310                    end: selection.end + delta,
 4311                    reversed: selection.reversed,
 4312                    goal: SelectionGoal::None,
 4313                })
 4314                .collect::<Vec<_>>();
 4315
 4316            let mut i = 0;
 4317            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4318                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4319                let start = map.buffer_snapshot.anchor_before(position);
 4320                let end = map.buffer_snapshot.anchor_after(position);
 4321                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4322                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4323                        Ordering::Less => i += 1,
 4324                        Ordering::Greater => break,
 4325                        Ordering::Equal => {
 4326                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4327                                Ordering::Less => i += 1,
 4328                                Ordering::Equal => break,
 4329                                Ordering::Greater => break,
 4330                            }
 4331                        }
 4332                    }
 4333                }
 4334                this.autoclose_regions.insert(
 4335                    i,
 4336                    AutocloseRegion {
 4337                        selection_id,
 4338                        range: start..end,
 4339                        pair,
 4340                    },
 4341                );
 4342            }
 4343
 4344            let had_active_edit_prediction = this.has_active_edit_prediction();
 4345            this.change_selections(
 4346                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4347                window,
 4348                cx,
 4349                |s| s.select(new_selections),
 4350            );
 4351
 4352            if !bracket_inserted
 4353                && let Some(on_type_format_task) =
 4354                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4355            {
 4356                on_type_format_task.detach_and_log_err(cx);
 4357            }
 4358
 4359            let editor_settings = EditorSettings::get_global(cx);
 4360            if bracket_inserted
 4361                && (editor_settings.auto_signature_help
 4362                    || editor_settings.show_signature_help_after_edits)
 4363            {
 4364                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4365            }
 4366
 4367            let trigger_in_words =
 4368                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4369            if this.hard_wrap.is_some() {
 4370                let latest: Range<Point> = this.selections.newest(cx).range();
 4371                if latest.is_empty()
 4372                    && this
 4373                        .buffer()
 4374                        .read(cx)
 4375                        .snapshot(cx)
 4376                        .line_len(MultiBufferRow(latest.start.row))
 4377                        == latest.start.column
 4378                {
 4379                    this.rewrap_impl(
 4380                        RewrapOptions {
 4381                            override_language_settings: true,
 4382                            preserve_existing_whitespace: true,
 4383                        },
 4384                        cx,
 4385                    )
 4386                }
 4387            }
 4388            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4389            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4390            this.refresh_edit_prediction(true, false, window, cx);
 4391            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4392        });
 4393    }
 4394
 4395    fn find_possible_emoji_shortcode_at_position(
 4396        snapshot: &MultiBufferSnapshot,
 4397        position: Point,
 4398    ) -> Option<String> {
 4399        let mut chars = Vec::new();
 4400        let mut found_colon = false;
 4401        for char in snapshot.reversed_chars_at(position).take(100) {
 4402            // Found a possible emoji shortcode in the middle of the buffer
 4403            if found_colon {
 4404                if char.is_whitespace() {
 4405                    chars.reverse();
 4406                    return Some(chars.iter().collect());
 4407                }
 4408                // If the previous character is not a whitespace, we are in the middle of a word
 4409                // and we only want to complete the shortcode if the word is made up of other emojis
 4410                let mut containing_word = String::new();
 4411                for ch in snapshot
 4412                    .reversed_chars_at(position)
 4413                    .skip(chars.len() + 1)
 4414                    .take(100)
 4415                {
 4416                    if ch.is_whitespace() {
 4417                        break;
 4418                    }
 4419                    containing_word.push(ch);
 4420                }
 4421                let containing_word = containing_word.chars().rev().collect::<String>();
 4422                if util::word_consists_of_emojis(containing_word.as_str()) {
 4423                    chars.reverse();
 4424                    return Some(chars.iter().collect());
 4425                }
 4426            }
 4427
 4428            if char.is_whitespace() || !char.is_ascii() {
 4429                return None;
 4430            }
 4431            if char == ':' {
 4432                found_colon = true;
 4433            } else {
 4434                chars.push(char);
 4435            }
 4436        }
 4437        // Found a possible emoji shortcode at the beginning of the buffer
 4438        chars.reverse();
 4439        Some(chars.iter().collect())
 4440    }
 4441
 4442    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4443        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4444        self.transact(window, cx, |this, window, cx| {
 4445            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4446                let selections = this.selections.all::<usize>(cx);
 4447                let multi_buffer = this.buffer.read(cx);
 4448                let buffer = multi_buffer.snapshot(cx);
 4449                selections
 4450                    .iter()
 4451                    .map(|selection| {
 4452                        let start_point = selection.start.to_point(&buffer);
 4453                        let mut existing_indent =
 4454                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4455                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4456                        let start = selection.start;
 4457                        let end = selection.end;
 4458                        let selection_is_empty = start == end;
 4459                        let language_scope = buffer.language_scope_at(start);
 4460                        let (
 4461                            comment_delimiter,
 4462                            doc_delimiter,
 4463                            insert_extra_newline,
 4464                            indent_on_newline,
 4465                            indent_on_extra_newline,
 4466                        ) = if let Some(language) = &language_scope {
 4467                            let mut insert_extra_newline =
 4468                                insert_extra_newline_brackets(&buffer, start..end, language)
 4469                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4470
 4471                            // Comment extension on newline is allowed only for cursor selections
 4472                            let comment_delimiter = maybe!({
 4473                                if !selection_is_empty {
 4474                                    return None;
 4475                                }
 4476
 4477                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4478                                    return None;
 4479                                }
 4480
 4481                                let delimiters = language.line_comment_prefixes();
 4482                                let max_len_of_delimiter =
 4483                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4484                                let (snapshot, range) =
 4485                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4486
 4487                                let num_of_whitespaces = snapshot
 4488                                    .chars_for_range(range.clone())
 4489                                    .take_while(|c| c.is_whitespace())
 4490                                    .count();
 4491                                let comment_candidate = snapshot
 4492                                    .chars_for_range(range.clone())
 4493                                    .skip(num_of_whitespaces)
 4494                                    .take(max_len_of_delimiter)
 4495                                    .collect::<String>();
 4496                                let (delimiter, trimmed_len) = delimiters
 4497                                    .iter()
 4498                                    .filter_map(|delimiter| {
 4499                                        let prefix = delimiter.trim_end();
 4500                                        if comment_candidate.starts_with(prefix) {
 4501                                            Some((delimiter, prefix.len()))
 4502                                        } else {
 4503                                            None
 4504                                        }
 4505                                    })
 4506                                    .max_by_key(|(_, len)| *len)?;
 4507
 4508                                if let Some(BlockCommentConfig {
 4509                                    start: block_start, ..
 4510                                }) = language.block_comment()
 4511                                {
 4512                                    let block_start_trimmed = block_start.trim_end();
 4513                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4514                                        let line_content = snapshot
 4515                                            .chars_for_range(range)
 4516                                            .skip(num_of_whitespaces)
 4517                                            .take(block_start_trimmed.len())
 4518                                            .collect::<String>();
 4519
 4520                                        if line_content.starts_with(block_start_trimmed) {
 4521                                            return None;
 4522                                        }
 4523                                    }
 4524                                }
 4525
 4526                                let cursor_is_placed_after_comment_marker =
 4527                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4528                                if cursor_is_placed_after_comment_marker {
 4529                                    Some(delimiter.clone())
 4530                                } else {
 4531                                    None
 4532                                }
 4533                            });
 4534
 4535                            let mut indent_on_newline = IndentSize::spaces(0);
 4536                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4537
 4538                            let doc_delimiter = maybe!({
 4539                                if !selection_is_empty {
 4540                                    return None;
 4541                                }
 4542
 4543                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4544                                    return None;
 4545                                }
 4546
 4547                                let BlockCommentConfig {
 4548                                    start: start_tag,
 4549                                    end: end_tag,
 4550                                    prefix: delimiter,
 4551                                    tab_size: len,
 4552                                } = language.documentation_comment()?;
 4553                                let is_within_block_comment = buffer
 4554                                    .language_scope_at(start_point)
 4555                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4556                                if !is_within_block_comment {
 4557                                    return None;
 4558                                }
 4559
 4560                                let (snapshot, range) =
 4561                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4562
 4563                                let num_of_whitespaces = snapshot
 4564                                    .chars_for_range(range.clone())
 4565                                    .take_while(|c| c.is_whitespace())
 4566                                    .count();
 4567
 4568                                // 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.
 4569                                let column = start_point.column;
 4570                                let cursor_is_after_start_tag = {
 4571                                    let start_tag_len = start_tag.len();
 4572                                    let start_tag_line = snapshot
 4573                                        .chars_for_range(range.clone())
 4574                                        .skip(num_of_whitespaces)
 4575                                        .take(start_tag_len)
 4576                                        .collect::<String>();
 4577                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4578                                        num_of_whitespaces + start_tag_len <= column as usize
 4579                                    } else {
 4580                                        false
 4581                                    }
 4582                                };
 4583
 4584                                let cursor_is_after_delimiter = {
 4585                                    let delimiter_trim = delimiter.trim_end();
 4586                                    let delimiter_line = snapshot
 4587                                        .chars_for_range(range.clone())
 4588                                        .skip(num_of_whitespaces)
 4589                                        .take(delimiter_trim.len())
 4590                                        .collect::<String>();
 4591                                    if delimiter_line.starts_with(delimiter_trim) {
 4592                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4593                                    } else {
 4594                                        false
 4595                                    }
 4596                                };
 4597
 4598                                let cursor_is_before_end_tag_if_exists = {
 4599                                    let mut char_position = 0u32;
 4600                                    let mut end_tag_offset = None;
 4601
 4602                                    'outer: for chunk in snapshot.text_for_range(range) {
 4603                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4604                                            let chars_before_match =
 4605                                                chunk[..byte_pos].chars().count() as u32;
 4606                                            end_tag_offset =
 4607                                                Some(char_position + chars_before_match);
 4608                                            break 'outer;
 4609                                        }
 4610                                        char_position += chunk.chars().count() as u32;
 4611                                    }
 4612
 4613                                    if let Some(end_tag_offset) = end_tag_offset {
 4614                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4615                                        if cursor_is_after_start_tag {
 4616                                            if cursor_is_before_end_tag {
 4617                                                insert_extra_newline = true;
 4618                                            }
 4619                                            let cursor_is_at_start_of_end_tag =
 4620                                                column == end_tag_offset;
 4621                                            if cursor_is_at_start_of_end_tag {
 4622                                                indent_on_extra_newline.len = *len;
 4623                                            }
 4624                                        }
 4625                                        cursor_is_before_end_tag
 4626                                    } else {
 4627                                        true
 4628                                    }
 4629                                };
 4630
 4631                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4632                                    && cursor_is_before_end_tag_if_exists
 4633                                {
 4634                                    if cursor_is_after_start_tag {
 4635                                        indent_on_newline.len = *len;
 4636                                    }
 4637                                    Some(delimiter.clone())
 4638                                } else {
 4639                                    None
 4640                                }
 4641                            });
 4642
 4643                            (
 4644                                comment_delimiter,
 4645                                doc_delimiter,
 4646                                insert_extra_newline,
 4647                                indent_on_newline,
 4648                                indent_on_extra_newline,
 4649                            )
 4650                        } else {
 4651                            (
 4652                                None,
 4653                                None,
 4654                                false,
 4655                                IndentSize::default(),
 4656                                IndentSize::default(),
 4657                            )
 4658                        };
 4659
 4660                        let prevent_auto_indent = doc_delimiter.is_some();
 4661                        let delimiter = comment_delimiter.or(doc_delimiter);
 4662
 4663                        let capacity_for_delimiter =
 4664                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4665                        let mut new_text = String::with_capacity(
 4666                            1 + capacity_for_delimiter
 4667                                + existing_indent.len as usize
 4668                                + indent_on_newline.len as usize
 4669                                + indent_on_extra_newline.len as usize,
 4670                        );
 4671                        new_text.push('\n');
 4672                        new_text.extend(existing_indent.chars());
 4673                        new_text.extend(indent_on_newline.chars());
 4674
 4675                        if let Some(delimiter) = &delimiter {
 4676                            new_text.push_str(delimiter);
 4677                        }
 4678
 4679                        if insert_extra_newline {
 4680                            new_text.push('\n');
 4681                            new_text.extend(existing_indent.chars());
 4682                            new_text.extend(indent_on_extra_newline.chars());
 4683                        }
 4684
 4685                        let anchor = buffer.anchor_after(end);
 4686                        let new_selection = selection.map(|_| anchor);
 4687                        (
 4688                            ((start..end, new_text), prevent_auto_indent),
 4689                            (insert_extra_newline, new_selection),
 4690                        )
 4691                    })
 4692                    .unzip()
 4693            };
 4694
 4695            let mut auto_indent_edits = Vec::new();
 4696            let mut edits = Vec::new();
 4697            for (edit, prevent_auto_indent) in edits_with_flags {
 4698                if prevent_auto_indent {
 4699                    edits.push(edit);
 4700                } else {
 4701                    auto_indent_edits.push(edit);
 4702                }
 4703            }
 4704            if !edits.is_empty() {
 4705                this.edit(edits, cx);
 4706            }
 4707            if !auto_indent_edits.is_empty() {
 4708                this.edit_with_autoindent(auto_indent_edits, cx);
 4709            }
 4710
 4711            let buffer = this.buffer.read(cx).snapshot(cx);
 4712            let new_selections = selection_info
 4713                .into_iter()
 4714                .map(|(extra_newline_inserted, new_selection)| {
 4715                    let mut cursor = new_selection.end.to_point(&buffer);
 4716                    if extra_newline_inserted {
 4717                        cursor.row -= 1;
 4718                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4719                    }
 4720                    new_selection.map(|_| cursor)
 4721                })
 4722                .collect();
 4723
 4724            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4725            this.refresh_edit_prediction(true, false, window, cx);
 4726        });
 4727    }
 4728
 4729    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4731
 4732        let buffer = self.buffer.read(cx);
 4733        let snapshot = buffer.snapshot(cx);
 4734
 4735        let mut edits = Vec::new();
 4736        let mut rows = Vec::new();
 4737
 4738        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4739            let cursor = selection.head();
 4740            let row = cursor.row;
 4741
 4742            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4743
 4744            let newline = "\n".to_string();
 4745            edits.push((start_of_line..start_of_line, newline));
 4746
 4747            rows.push(row + rows_inserted as u32);
 4748        }
 4749
 4750        self.transact(window, cx, |editor, window, cx| {
 4751            editor.edit(edits, cx);
 4752
 4753            editor.change_selections(Default::default(), window, cx, |s| {
 4754                let mut index = 0;
 4755                s.move_cursors_with(|map, _, _| {
 4756                    let row = rows[index];
 4757                    index += 1;
 4758
 4759                    let point = Point::new(row, 0);
 4760                    let boundary = map.next_line_boundary(point).1;
 4761                    let clipped = map.clip_point(boundary, Bias::Left);
 4762
 4763                    (clipped, SelectionGoal::None)
 4764                });
 4765            });
 4766
 4767            let mut indent_edits = Vec::new();
 4768            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4769            for row in rows {
 4770                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4771                for (row, indent) in indents {
 4772                    if indent.len == 0 {
 4773                        continue;
 4774                    }
 4775
 4776                    let text = match indent.kind {
 4777                        IndentKind::Space => " ".repeat(indent.len as usize),
 4778                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4779                    };
 4780                    let point = Point::new(row.0, 0);
 4781                    indent_edits.push((point..point, text));
 4782                }
 4783            }
 4784            editor.edit(indent_edits, cx);
 4785        });
 4786    }
 4787
 4788    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4789        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4790
 4791        let buffer = self.buffer.read(cx);
 4792        let snapshot = buffer.snapshot(cx);
 4793
 4794        let mut edits = Vec::new();
 4795        let mut rows = Vec::new();
 4796        let mut rows_inserted = 0;
 4797
 4798        for selection in self.selections.all_adjusted(cx) {
 4799            let cursor = selection.head();
 4800            let row = cursor.row;
 4801
 4802            let point = Point::new(row + 1, 0);
 4803            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4804
 4805            let newline = "\n".to_string();
 4806            edits.push((start_of_line..start_of_line, newline));
 4807
 4808            rows_inserted += 1;
 4809            rows.push(row + rows_inserted);
 4810        }
 4811
 4812        self.transact(window, cx, |editor, window, cx| {
 4813            editor.edit(edits, cx);
 4814
 4815            editor.change_selections(Default::default(), window, cx, |s| {
 4816                let mut index = 0;
 4817                s.move_cursors_with(|map, _, _| {
 4818                    let row = rows[index];
 4819                    index += 1;
 4820
 4821                    let point = Point::new(row, 0);
 4822                    let boundary = map.next_line_boundary(point).1;
 4823                    let clipped = map.clip_point(boundary, Bias::Left);
 4824
 4825                    (clipped, SelectionGoal::None)
 4826                });
 4827            });
 4828
 4829            let mut indent_edits = Vec::new();
 4830            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4831            for row in rows {
 4832                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4833                for (row, indent) in indents {
 4834                    if indent.len == 0 {
 4835                        continue;
 4836                    }
 4837
 4838                    let text = match indent.kind {
 4839                        IndentKind::Space => " ".repeat(indent.len as usize),
 4840                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4841                    };
 4842                    let point = Point::new(row.0, 0);
 4843                    indent_edits.push((point..point, text));
 4844                }
 4845            }
 4846            editor.edit(indent_edits, cx);
 4847        });
 4848    }
 4849
 4850    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4851        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4852            original_indent_columns: Vec::new(),
 4853        });
 4854        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4855    }
 4856
 4857    fn insert_with_autoindent_mode(
 4858        &mut self,
 4859        text: &str,
 4860        autoindent_mode: Option<AutoindentMode>,
 4861        window: &mut Window,
 4862        cx: &mut Context<Self>,
 4863    ) {
 4864        if self.read_only(cx) {
 4865            return;
 4866        }
 4867
 4868        let text: Arc<str> = text.into();
 4869        self.transact(window, cx, |this, window, cx| {
 4870            let old_selections = this.selections.all_adjusted(cx);
 4871            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4872                let anchors = {
 4873                    let snapshot = buffer.read(cx);
 4874                    old_selections
 4875                        .iter()
 4876                        .map(|s| {
 4877                            let anchor = snapshot.anchor_after(s.head());
 4878                            s.map(|_| anchor)
 4879                        })
 4880                        .collect::<Vec<_>>()
 4881                };
 4882                buffer.edit(
 4883                    old_selections
 4884                        .iter()
 4885                        .map(|s| (s.start..s.end, text.clone())),
 4886                    autoindent_mode,
 4887                    cx,
 4888                );
 4889                anchors
 4890            });
 4891
 4892            this.change_selections(Default::default(), window, cx, |s| {
 4893                s.select_anchors(selection_anchors);
 4894            });
 4895
 4896            cx.notify();
 4897        });
 4898    }
 4899
 4900    fn trigger_completion_on_input(
 4901        &mut self,
 4902        text: &str,
 4903        trigger_in_words: bool,
 4904        window: &mut Window,
 4905        cx: &mut Context<Self>,
 4906    ) {
 4907        let completions_source = self
 4908            .context_menu
 4909            .borrow()
 4910            .as_ref()
 4911            .and_then(|menu| match menu {
 4912                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4913                CodeContextMenu::CodeActions(_) => None,
 4914            });
 4915
 4916        match completions_source {
 4917            Some(CompletionsMenuSource::Words { .. }) => {
 4918                self.open_or_update_completions_menu(
 4919                    Some(CompletionsMenuSource::Words {
 4920                        ignore_threshold: false,
 4921                    }),
 4922                    None,
 4923                    window,
 4924                    cx,
 4925                );
 4926            }
 4927            Some(CompletionsMenuSource::Normal)
 4928            | Some(CompletionsMenuSource::SnippetChoices)
 4929            | None
 4930                if self.is_completion_trigger(
 4931                    text,
 4932                    trigger_in_words,
 4933                    completions_source.is_some(),
 4934                    cx,
 4935                ) =>
 4936            {
 4937                self.show_completions(
 4938                    &ShowCompletions {
 4939                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4940                    },
 4941                    window,
 4942                    cx,
 4943                )
 4944            }
 4945            _ => {
 4946                self.hide_context_menu(window, cx);
 4947            }
 4948        }
 4949    }
 4950
 4951    fn is_completion_trigger(
 4952        &self,
 4953        text: &str,
 4954        trigger_in_words: bool,
 4955        menu_is_open: bool,
 4956        cx: &mut Context<Self>,
 4957    ) -> bool {
 4958        let position = self.selections.newest_anchor().head();
 4959        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4960            return false;
 4961        };
 4962
 4963        if let Some(completion_provider) = &self.completion_provider {
 4964            completion_provider.is_completion_trigger(
 4965                &buffer,
 4966                position.text_anchor,
 4967                text,
 4968                trigger_in_words,
 4969                menu_is_open,
 4970                cx,
 4971            )
 4972        } else {
 4973            false
 4974        }
 4975    }
 4976
 4977    /// If any empty selections is touching the start of its innermost containing autoclose
 4978    /// region, expand it to select the brackets.
 4979    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4980        let selections = self.selections.all::<usize>(cx);
 4981        let buffer = self.buffer.read(cx).read(cx);
 4982        let new_selections = self
 4983            .selections_with_autoclose_regions(selections, &buffer)
 4984            .map(|(mut selection, region)| {
 4985                if !selection.is_empty() {
 4986                    return selection;
 4987                }
 4988
 4989                if let Some(region) = region {
 4990                    let mut range = region.range.to_offset(&buffer);
 4991                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4992                        range.start -= region.pair.start.len();
 4993                        if buffer.contains_str_at(range.start, &region.pair.start)
 4994                            && buffer.contains_str_at(range.end, &region.pair.end)
 4995                        {
 4996                            range.end += region.pair.end.len();
 4997                            selection.start = range.start;
 4998                            selection.end = range.end;
 4999
 5000                            return selection;
 5001                        }
 5002                    }
 5003                }
 5004
 5005                let always_treat_brackets_as_autoclosed = buffer
 5006                    .language_settings_at(selection.start, cx)
 5007                    .always_treat_brackets_as_autoclosed;
 5008
 5009                if !always_treat_brackets_as_autoclosed {
 5010                    return selection;
 5011                }
 5012
 5013                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5014                    for (pair, enabled) in scope.brackets() {
 5015                        if !enabled || !pair.close {
 5016                            continue;
 5017                        }
 5018
 5019                        if buffer.contains_str_at(selection.start, &pair.end) {
 5020                            let pair_start_len = pair.start.len();
 5021                            if buffer.contains_str_at(
 5022                                selection.start.saturating_sub(pair_start_len),
 5023                                &pair.start,
 5024                            ) {
 5025                                selection.start -= pair_start_len;
 5026                                selection.end += pair.end.len();
 5027
 5028                                return selection;
 5029                            }
 5030                        }
 5031                    }
 5032                }
 5033
 5034                selection
 5035            })
 5036            .collect();
 5037
 5038        drop(buffer);
 5039        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5040            selections.select(new_selections)
 5041        });
 5042    }
 5043
 5044    /// Iterate the given selections, and for each one, find the smallest surrounding
 5045    /// autoclose region. This uses the ordering of the selections and the autoclose
 5046    /// regions to avoid repeated comparisons.
 5047    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5048        &'a self,
 5049        selections: impl IntoIterator<Item = Selection<D>>,
 5050        buffer: &'a MultiBufferSnapshot,
 5051    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5052        let mut i = 0;
 5053        let mut regions = self.autoclose_regions.as_slice();
 5054        selections.into_iter().map(move |selection| {
 5055            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5056
 5057            let mut enclosing = None;
 5058            while let Some(pair_state) = regions.get(i) {
 5059                if pair_state.range.end.to_offset(buffer) < range.start {
 5060                    regions = &regions[i + 1..];
 5061                    i = 0;
 5062                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5063                    break;
 5064                } else {
 5065                    if pair_state.selection_id == selection.id {
 5066                        enclosing = Some(pair_state);
 5067                    }
 5068                    i += 1;
 5069                }
 5070            }
 5071
 5072            (selection, enclosing)
 5073        })
 5074    }
 5075
 5076    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5077    fn invalidate_autoclose_regions(
 5078        &mut self,
 5079        mut selections: &[Selection<Anchor>],
 5080        buffer: &MultiBufferSnapshot,
 5081    ) {
 5082        self.autoclose_regions.retain(|state| {
 5083            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5084                return false;
 5085            }
 5086
 5087            let mut i = 0;
 5088            while let Some(selection) = selections.get(i) {
 5089                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5090                    selections = &selections[1..];
 5091                    continue;
 5092                }
 5093                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5094                    break;
 5095                }
 5096                if selection.id == state.selection_id {
 5097                    return true;
 5098                } else {
 5099                    i += 1;
 5100                }
 5101            }
 5102            false
 5103        });
 5104    }
 5105
 5106    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5107        let offset = position.to_offset(buffer);
 5108        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5109        if offset > word_range.start && kind == Some(CharKind::Word) {
 5110            Some(
 5111                buffer
 5112                    .text_for_range(word_range.start..offset)
 5113                    .collect::<String>(),
 5114            )
 5115        } else {
 5116            None
 5117        }
 5118    }
 5119
 5120    pub fn toggle_inline_values(
 5121        &mut self,
 5122        _: &ToggleInlineValues,
 5123        _: &mut Window,
 5124        cx: &mut Context<Self>,
 5125    ) {
 5126        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5127
 5128        self.refresh_inline_values(cx);
 5129    }
 5130
 5131    pub fn toggle_inlay_hints(
 5132        &mut self,
 5133        _: &ToggleInlayHints,
 5134        _: &mut Window,
 5135        cx: &mut Context<Self>,
 5136    ) {
 5137        self.refresh_inlay_hints(
 5138            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5139            cx,
 5140        );
 5141    }
 5142
 5143    pub fn inlay_hints_enabled(&self) -> bool {
 5144        self.inlay_hint_cache.enabled
 5145    }
 5146
 5147    pub fn inline_values_enabled(&self) -> bool {
 5148        self.inline_value_cache.enabled
 5149    }
 5150
 5151    #[cfg(any(test, feature = "test-support"))]
 5152    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5153        self.display_map
 5154            .read(cx)
 5155            .current_inlays()
 5156            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5157            .cloned()
 5158            .collect()
 5159    }
 5160
 5161    #[cfg(any(test, feature = "test-support"))]
 5162    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5163        self.display_map
 5164            .read(cx)
 5165            .current_inlays()
 5166            .cloned()
 5167            .collect()
 5168    }
 5169
 5170    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5171        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5172            return;
 5173        }
 5174
 5175        let reason_description = reason.description();
 5176        let ignore_debounce = matches!(
 5177            reason,
 5178            InlayHintRefreshReason::SettingsChange(_)
 5179                | InlayHintRefreshReason::Toggle(_)
 5180                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5181                | InlayHintRefreshReason::ModifiersChanged(_)
 5182        );
 5183        let (invalidate_cache, required_languages) = match reason {
 5184            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5185                match self.inlay_hint_cache.modifiers_override(enabled) {
 5186                    Some(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                    }
 5202                    None => return,
 5203                }
 5204            }
 5205            InlayHintRefreshReason::Toggle(enabled) => {
 5206                if self.inlay_hint_cache.toggle(enabled) {
 5207                    if enabled {
 5208                        (InvalidationStrategy::RefreshRequested, None)
 5209                    } else {
 5210                        self.splice_inlays(
 5211                            &self
 5212                                .visible_inlay_hints(cx)
 5213                                .iter()
 5214                                .map(|inlay| inlay.id)
 5215                                .collect::<Vec<InlayId>>(),
 5216                            Vec::new(),
 5217                            cx,
 5218                        );
 5219                        return;
 5220                    }
 5221                } else {
 5222                    return;
 5223                }
 5224            }
 5225            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5226                match self.inlay_hint_cache.update_settings(
 5227                    &self.buffer,
 5228                    new_settings,
 5229                    self.visible_inlay_hints(cx),
 5230                    cx,
 5231                ) {
 5232                    ControlFlow::Break(Some(InlaySplice {
 5233                        to_remove,
 5234                        to_insert,
 5235                    })) => {
 5236                        self.splice_inlays(&to_remove, to_insert, cx);
 5237                        return;
 5238                    }
 5239                    ControlFlow::Break(None) => return,
 5240                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5241                }
 5242            }
 5243            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5244                if let Some(InlaySplice {
 5245                    to_remove,
 5246                    to_insert,
 5247                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5248                {
 5249                    self.splice_inlays(&to_remove, to_insert, cx);
 5250                }
 5251                self.display_map.update(cx, |display_map, _| {
 5252                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5253                });
 5254                return;
 5255            }
 5256            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5257            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5258                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5259            }
 5260            InlayHintRefreshReason::RefreshRequested => {
 5261                (InvalidationStrategy::RefreshRequested, None)
 5262            }
 5263        };
 5264
 5265        if let Some(InlaySplice {
 5266            to_remove,
 5267            to_insert,
 5268        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5269            reason_description,
 5270            self.visible_excerpts(required_languages.as_ref(), cx),
 5271            invalidate_cache,
 5272            ignore_debounce,
 5273            cx,
 5274        ) {
 5275            self.splice_inlays(&to_remove, to_insert, cx);
 5276        }
 5277    }
 5278
 5279    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5280        self.display_map
 5281            .read(cx)
 5282            .current_inlays()
 5283            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5284            .cloned()
 5285            .collect()
 5286    }
 5287
 5288    pub fn visible_excerpts(
 5289        &self,
 5290        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5291        cx: &mut Context<Editor>,
 5292    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5293        let Some(project) = self.project() else {
 5294            return HashMap::default();
 5295        };
 5296        let project = project.read(cx);
 5297        let multi_buffer = self.buffer().read(cx);
 5298        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5299        let multi_buffer_visible_start = self
 5300            .scroll_manager
 5301            .anchor()
 5302            .anchor
 5303            .to_point(&multi_buffer_snapshot);
 5304        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5305            multi_buffer_visible_start
 5306                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5307            Bias::Left,
 5308        );
 5309        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5310        multi_buffer_snapshot
 5311            .range_to_buffer_ranges(multi_buffer_visible_range)
 5312            .into_iter()
 5313            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5314            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5315                let buffer_file = project::File::from_dyn(buffer.file())?;
 5316                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5317                let worktree_entry = buffer_worktree
 5318                    .read(cx)
 5319                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5320                if worktree_entry.is_ignored {
 5321                    return None;
 5322                }
 5323
 5324                let language = buffer.language()?;
 5325                if let Some(restrict_to_languages) = restrict_to_languages
 5326                    && !restrict_to_languages.contains(language)
 5327                {
 5328                    return None;
 5329                }
 5330                Some((
 5331                    excerpt_id,
 5332                    (
 5333                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5334                        buffer.version().clone(),
 5335                        excerpt_visible_range,
 5336                    ),
 5337                ))
 5338            })
 5339            .collect()
 5340    }
 5341
 5342    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5343        TextLayoutDetails {
 5344            text_system: window.text_system().clone(),
 5345            editor_style: self.style.clone().unwrap(),
 5346            rem_size: window.rem_size(),
 5347            scroll_anchor: self.scroll_manager.anchor(),
 5348            visible_rows: self.visible_line_count(),
 5349            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5350        }
 5351    }
 5352
 5353    pub fn splice_inlays(
 5354        &self,
 5355        to_remove: &[InlayId],
 5356        to_insert: Vec<Inlay>,
 5357        cx: &mut Context<Self>,
 5358    ) {
 5359        self.display_map.update(cx, |display_map, cx| {
 5360            display_map.splice_inlays(to_remove, to_insert, cx)
 5361        });
 5362        cx.notify();
 5363    }
 5364
 5365    fn trigger_on_type_formatting(
 5366        &self,
 5367        input: String,
 5368        window: &mut Window,
 5369        cx: &mut Context<Self>,
 5370    ) -> Option<Task<Result<()>>> {
 5371        if input.len() != 1 {
 5372            return None;
 5373        }
 5374
 5375        let project = self.project()?;
 5376        let position = self.selections.newest_anchor().head();
 5377        let (buffer, buffer_position) = self
 5378            .buffer
 5379            .read(cx)
 5380            .text_anchor_for_position(position, cx)?;
 5381
 5382        let settings = language_settings::language_settings(
 5383            buffer
 5384                .read(cx)
 5385                .language_at(buffer_position)
 5386                .map(|l| l.name()),
 5387            buffer.read(cx).file(),
 5388            cx,
 5389        );
 5390        if !settings.use_on_type_format {
 5391            return None;
 5392        }
 5393
 5394        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5395        // hence we do LSP request & edit on host side only — add formats to host's history.
 5396        let push_to_lsp_host_history = true;
 5397        // If this is not the host, append its history with new edits.
 5398        let push_to_client_history = project.read(cx).is_via_collab();
 5399
 5400        let on_type_formatting = project.update(cx, |project, cx| {
 5401            project.on_type_format(
 5402                buffer.clone(),
 5403                buffer_position,
 5404                input,
 5405                push_to_lsp_host_history,
 5406                cx,
 5407            )
 5408        });
 5409        Some(cx.spawn_in(window, async move |editor, cx| {
 5410            if let Some(transaction) = on_type_formatting.await? {
 5411                if push_to_client_history {
 5412                    buffer
 5413                        .update(cx, |buffer, _| {
 5414                            buffer.push_transaction(transaction, Instant::now());
 5415                            buffer.finalize_last_transaction();
 5416                        })
 5417                        .ok();
 5418                }
 5419                editor.update(cx, |editor, cx| {
 5420                    editor.refresh_document_highlights(cx);
 5421                })?;
 5422            }
 5423            Ok(())
 5424        }))
 5425    }
 5426
 5427    pub fn show_word_completions(
 5428        &mut self,
 5429        _: &ShowWordCompletions,
 5430        window: &mut Window,
 5431        cx: &mut Context<Self>,
 5432    ) {
 5433        self.open_or_update_completions_menu(
 5434            Some(CompletionsMenuSource::Words {
 5435                ignore_threshold: true,
 5436            }),
 5437            None,
 5438            window,
 5439            cx,
 5440        );
 5441    }
 5442
 5443    pub fn show_completions(
 5444        &mut self,
 5445        options: &ShowCompletions,
 5446        window: &mut Window,
 5447        cx: &mut Context<Self>,
 5448    ) {
 5449        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5450    }
 5451
 5452    fn open_or_update_completions_menu(
 5453        &mut self,
 5454        requested_source: Option<CompletionsMenuSource>,
 5455        trigger: Option<&str>,
 5456        window: &mut Window,
 5457        cx: &mut Context<Self>,
 5458    ) {
 5459        if self.pending_rename.is_some() {
 5460            return;
 5461        }
 5462
 5463        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5464
 5465        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5466        // inserted and selected. To handle that case, the start of the selection is used so that
 5467        // the menu starts with all choices.
 5468        let position = self
 5469            .selections
 5470            .newest_anchor()
 5471            .start
 5472            .bias_right(&multibuffer_snapshot);
 5473        if position.diff_base_anchor.is_some() {
 5474            return;
 5475        }
 5476        let (buffer, buffer_position) =
 5477            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5478                output
 5479            } else {
 5480                return;
 5481            };
 5482        let buffer_snapshot = buffer.read(cx).snapshot();
 5483
 5484        let query: Option<Arc<String>> =
 5485            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5486
 5487        drop(multibuffer_snapshot);
 5488
 5489        let mut ignore_word_threshold = false;
 5490        let provider = match requested_source {
 5491            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5492            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5493                ignore_word_threshold = ignore_threshold;
 5494                None
 5495            }
 5496            Some(CompletionsMenuSource::SnippetChoices) => {
 5497                log::error!("bug: SnippetChoices requested_source is not handled");
 5498                None
 5499            }
 5500        };
 5501
 5502        let sort_completions = provider
 5503            .as_ref()
 5504            .is_some_and(|provider| provider.sort_completions());
 5505
 5506        let filter_completions = provider
 5507            .as_ref()
 5508            .is_none_or(|provider| provider.filter_completions());
 5509
 5510        let trigger_kind = match trigger {
 5511            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5512                CompletionTriggerKind::TRIGGER_CHARACTER
 5513            }
 5514            _ => CompletionTriggerKind::INVOKED,
 5515        };
 5516        let completion_context = CompletionContext {
 5517            trigger_character: trigger.and_then(|trigger| {
 5518                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5519                    Some(String::from(trigger))
 5520                } else {
 5521                    None
 5522                }
 5523            }),
 5524            trigger_kind,
 5525        };
 5526
 5527        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5528        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5529        // involve trigger chars, so this is skipped in that case.
 5530        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5531        {
 5532            let menu_is_open = matches!(
 5533                self.context_menu.borrow().as_ref(),
 5534                Some(CodeContextMenu::Completions(_))
 5535            );
 5536            if menu_is_open {
 5537                self.hide_context_menu(window, cx);
 5538            }
 5539        }
 5540
 5541        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5542            if filter_completions {
 5543                menu.filter(query.clone(), provider.clone(), window, cx);
 5544            }
 5545            // When `is_incomplete` is false, no need to re-query completions when the current query
 5546            // is a suffix of the initial query.
 5547            if !menu.is_incomplete {
 5548                // If the new query is a suffix of the old query (typing more characters) and
 5549                // the previous result was complete, the existing completions can be filtered.
 5550                //
 5551                // Note that this is always true for snippet completions.
 5552                let query_matches = match (&menu.initial_query, &query) {
 5553                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5554                    (None, _) => true,
 5555                    _ => false,
 5556                };
 5557                if query_matches {
 5558                    let position_matches = if menu.initial_position == position {
 5559                        true
 5560                    } else {
 5561                        let snapshot = self.buffer.read(cx).read(cx);
 5562                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5563                    };
 5564                    if position_matches {
 5565                        return;
 5566                    }
 5567                }
 5568            }
 5569        };
 5570
 5571        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5572            buffer_snapshot.surrounding_word(buffer_position, false)
 5573        {
 5574            let word_to_exclude = buffer_snapshot
 5575                .text_for_range(word_range.clone())
 5576                .collect::<String>();
 5577            (
 5578                buffer_snapshot.anchor_before(word_range.start)
 5579                    ..buffer_snapshot.anchor_after(buffer_position),
 5580                Some(word_to_exclude),
 5581            )
 5582        } else {
 5583            (buffer_position..buffer_position, None)
 5584        };
 5585
 5586        let language = buffer_snapshot
 5587            .language_at(buffer_position)
 5588            .map(|language| language.name());
 5589
 5590        let completion_settings =
 5591            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5592
 5593        let show_completion_documentation = buffer_snapshot
 5594            .settings_at(buffer_position, cx)
 5595            .show_completion_documentation;
 5596
 5597        // The document can be large, so stay in reasonable bounds when searching for words,
 5598        // otherwise completion pop-up might be slow to appear.
 5599        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5600        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5601        let min_word_search = buffer_snapshot.clip_point(
 5602            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5603            Bias::Left,
 5604        );
 5605        let max_word_search = buffer_snapshot.clip_point(
 5606            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5607            Bias::Right,
 5608        );
 5609        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5610            ..buffer_snapshot.point_to_offset(max_word_search);
 5611
 5612        let skip_digits = query
 5613            .as_ref()
 5614            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5615
 5616        let omit_word_completions = !self.word_completions_enabled
 5617            || (!ignore_word_threshold
 5618                && match &query {
 5619                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5620                    None => completion_settings.words_min_length != 0,
 5621                });
 5622
 5623        let (mut words, provider_responses) = match &provider {
 5624            Some(provider) => {
 5625                let provider_responses = provider.completions(
 5626                    position.excerpt_id,
 5627                    &buffer,
 5628                    buffer_position,
 5629                    completion_context,
 5630                    window,
 5631                    cx,
 5632                );
 5633
 5634                let words = match (omit_word_completions, completion_settings.words) {
 5635                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5636                        Task::ready(BTreeMap::default())
 5637                    }
 5638                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5639                        .background_spawn(async move {
 5640                            buffer_snapshot.words_in_range(WordsQuery {
 5641                                fuzzy_contents: None,
 5642                                range: word_search_range,
 5643                                skip_digits,
 5644                            })
 5645                        }),
 5646                };
 5647
 5648                (words, provider_responses)
 5649            }
 5650            None => {
 5651                let words = if omit_word_completions {
 5652                    Task::ready(BTreeMap::default())
 5653                } else {
 5654                    cx.background_spawn(async move {
 5655                        buffer_snapshot.words_in_range(WordsQuery {
 5656                            fuzzy_contents: None,
 5657                            range: word_search_range,
 5658                            skip_digits,
 5659                        })
 5660                    })
 5661                };
 5662                (words, Task::ready(Ok(Vec::new())))
 5663            }
 5664        };
 5665
 5666        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5667
 5668        let id = post_inc(&mut self.next_completion_id);
 5669        let task = cx.spawn_in(window, async move |editor, cx| {
 5670            let Ok(()) = editor.update(cx, |this, _| {
 5671                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5672            }) else {
 5673                return;
 5674            };
 5675
 5676            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5677            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5678            let mut completions = Vec::new();
 5679            let mut is_incomplete = false;
 5680            let mut display_options: Option<CompletionDisplayOptions> = None;
 5681            if let Some(provider_responses) = provider_responses.await.log_err()
 5682                && !provider_responses.is_empty()
 5683            {
 5684                for response in provider_responses {
 5685                    completions.extend(response.completions);
 5686                    is_incomplete = is_incomplete || response.is_incomplete;
 5687                    match display_options.as_mut() {
 5688                        None => {
 5689                            display_options = Some(response.display_options);
 5690                        }
 5691                        Some(options) => options.merge(&response.display_options),
 5692                    }
 5693                }
 5694                if completion_settings.words == WordsCompletionMode::Fallback {
 5695                    words = Task::ready(BTreeMap::default());
 5696                }
 5697            }
 5698            let display_options = display_options.unwrap_or_default();
 5699
 5700            let mut words = words.await;
 5701            if let Some(word_to_exclude) = &word_to_exclude {
 5702                words.remove(word_to_exclude);
 5703            }
 5704            for lsp_completion in &completions {
 5705                words.remove(&lsp_completion.new_text);
 5706            }
 5707            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5708                replace_range: word_replace_range.clone(),
 5709                new_text: word.clone(),
 5710                label: CodeLabel::plain(word, None),
 5711                icon_path: None,
 5712                documentation: None,
 5713                source: CompletionSource::BufferWord {
 5714                    word_range,
 5715                    resolved: false,
 5716                },
 5717                insert_text_mode: Some(InsertTextMode::AS_IS),
 5718                confirm: None,
 5719            }));
 5720
 5721            let menu = if completions.is_empty() {
 5722                None
 5723            } else {
 5724                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5725                    let languages = editor
 5726                        .workspace
 5727                        .as_ref()
 5728                        .and_then(|(workspace, _)| workspace.upgrade())
 5729                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5730                    let menu = CompletionsMenu::new(
 5731                        id,
 5732                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5733                        sort_completions,
 5734                        show_completion_documentation,
 5735                        position,
 5736                        query.clone(),
 5737                        is_incomplete,
 5738                        buffer.clone(),
 5739                        completions.into(),
 5740                        display_options,
 5741                        snippet_sort_order,
 5742                        languages,
 5743                        language,
 5744                        cx,
 5745                    );
 5746
 5747                    let query = if filter_completions { query } else { None };
 5748                    let matches_task = if let Some(query) = query {
 5749                        menu.do_async_filtering(query, cx)
 5750                    } else {
 5751                        Task::ready(menu.unfiltered_matches())
 5752                    };
 5753                    (menu, matches_task)
 5754                }) else {
 5755                    return;
 5756                };
 5757
 5758                let matches = matches_task.await;
 5759
 5760                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5761                    // Newer menu already set, so exit.
 5762                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5763                        editor.context_menu.borrow().as_ref()
 5764                        && prev_menu.id > id
 5765                    {
 5766                        return;
 5767                    };
 5768
 5769                    // Only valid to take prev_menu because it the new menu is immediately set
 5770                    // below, or the menu is hidden.
 5771                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5772                        editor.context_menu.borrow_mut().take()
 5773                    {
 5774                        let position_matches =
 5775                            if prev_menu.initial_position == menu.initial_position {
 5776                                true
 5777                            } else {
 5778                                let snapshot = editor.buffer.read(cx).read(cx);
 5779                                prev_menu.initial_position.to_offset(&snapshot)
 5780                                    == menu.initial_position.to_offset(&snapshot)
 5781                            };
 5782                        if position_matches {
 5783                            // Preserve markdown cache before `set_filter_results` because it will
 5784                            // try to populate the documentation cache.
 5785                            menu.preserve_markdown_cache(prev_menu);
 5786                        }
 5787                    };
 5788
 5789                    menu.set_filter_results(matches, provider, window, cx);
 5790                }) else {
 5791                    return;
 5792                };
 5793
 5794                menu.visible().then_some(menu)
 5795            };
 5796
 5797            editor
 5798                .update_in(cx, |editor, window, cx| {
 5799                    if editor.focus_handle.is_focused(window)
 5800                        && let Some(menu) = menu
 5801                    {
 5802                        *editor.context_menu.borrow_mut() =
 5803                            Some(CodeContextMenu::Completions(menu));
 5804
 5805                        crate::hover_popover::hide_hover(editor, cx);
 5806                        if editor.show_edit_predictions_in_menu() {
 5807                            editor.update_visible_edit_prediction(window, cx);
 5808                        } else {
 5809                            editor.discard_edit_prediction(false, cx);
 5810                        }
 5811
 5812                        cx.notify();
 5813                        return;
 5814                    }
 5815
 5816                    if editor.completion_tasks.len() <= 1 {
 5817                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5818                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5819                        // If it was already hidden and we don't show edit predictions in the menu,
 5820                        // we should also show the edit prediction when available.
 5821                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5822                            editor.update_visible_edit_prediction(window, cx);
 5823                        }
 5824                    }
 5825                })
 5826                .ok();
 5827        });
 5828
 5829        self.completion_tasks.push((id, task));
 5830    }
 5831
 5832    #[cfg(feature = "test-support")]
 5833    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5834        let menu = self.context_menu.borrow();
 5835        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5836            let completions = menu.completions.borrow();
 5837            Some(completions.to_vec())
 5838        } else {
 5839            None
 5840        }
 5841    }
 5842
 5843    pub fn with_completions_menu_matching_id<R>(
 5844        &self,
 5845        id: CompletionId,
 5846        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5847    ) -> R {
 5848        let mut context_menu = self.context_menu.borrow_mut();
 5849        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5850            return f(None);
 5851        };
 5852        if completions_menu.id != id {
 5853            return f(None);
 5854        }
 5855        f(Some(completions_menu))
 5856    }
 5857
 5858    pub fn confirm_completion(
 5859        &mut self,
 5860        action: &ConfirmCompletion,
 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(action.item_ix, CompletionIntent::Complete, window, cx)
 5866    }
 5867
 5868    pub fn confirm_completion_insert(
 5869        &mut self,
 5870        _: &ConfirmCompletionInsert,
 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(None, CompletionIntent::CompleteWithInsert, window, cx)
 5876    }
 5877
 5878    pub fn confirm_completion_replace(
 5879        &mut self,
 5880        _: &ConfirmCompletionReplace,
 5881        window: &mut Window,
 5882        cx: &mut Context<Self>,
 5883    ) -> Option<Task<Result<()>>> {
 5884        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5885        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5886    }
 5887
 5888    pub fn compose_completion(
 5889        &mut self,
 5890        action: &ComposeCompletion,
 5891        window: &mut Window,
 5892        cx: &mut Context<Self>,
 5893    ) -> Option<Task<Result<()>>> {
 5894        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5895        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5896    }
 5897
 5898    fn do_completion(
 5899        &mut self,
 5900        item_ix: Option<usize>,
 5901        intent: CompletionIntent,
 5902        window: &mut Window,
 5903        cx: &mut Context<Editor>,
 5904    ) -> Option<Task<Result<()>>> {
 5905        use language::ToOffset as _;
 5906
 5907        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5908        else {
 5909            return None;
 5910        };
 5911
 5912        let candidate_id = {
 5913            let entries = completions_menu.entries.borrow();
 5914            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5915            if self.show_edit_predictions_in_menu() {
 5916                self.discard_edit_prediction(true, cx);
 5917            }
 5918            mat.candidate_id
 5919        };
 5920
 5921        let completion = completions_menu
 5922            .completions
 5923            .borrow()
 5924            .get(candidate_id)?
 5925            .clone();
 5926        cx.stop_propagation();
 5927
 5928        let buffer_handle = completions_menu.buffer.clone();
 5929
 5930        let CompletionEdit {
 5931            new_text,
 5932            snippet,
 5933            replace_range,
 5934        } = process_completion_for_edit(
 5935            &completion,
 5936            intent,
 5937            &buffer_handle,
 5938            &completions_menu.initial_position.text_anchor,
 5939            cx,
 5940        );
 5941
 5942        let buffer = buffer_handle.read(cx);
 5943        let snapshot = self.buffer.read(cx).snapshot(cx);
 5944        let newest_anchor = self.selections.newest_anchor();
 5945        let replace_range_multibuffer = {
 5946            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5947            let multibuffer_anchor = snapshot
 5948                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5949                .unwrap()
 5950                ..snapshot
 5951                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5952                    .unwrap();
 5953            multibuffer_anchor.start.to_offset(&snapshot)
 5954                ..multibuffer_anchor.end.to_offset(&snapshot)
 5955        };
 5956        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5957            return None;
 5958        }
 5959
 5960        let old_text = buffer
 5961            .text_for_range(replace_range.clone())
 5962            .collect::<String>();
 5963        let lookbehind = newest_anchor
 5964            .start
 5965            .text_anchor
 5966            .to_offset(buffer)
 5967            .saturating_sub(replace_range.start);
 5968        let lookahead = replace_range
 5969            .end
 5970            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5971        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5972        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5973
 5974        let selections = self.selections.all::<usize>(cx);
 5975        let mut ranges = Vec::new();
 5976        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5977
 5978        for selection in &selections {
 5979            let range = if selection.id == newest_anchor.id {
 5980                replace_range_multibuffer.clone()
 5981            } else {
 5982                let mut range = selection.range();
 5983
 5984                // if prefix is present, don't duplicate it
 5985                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5986                    range.start = range.start.saturating_sub(lookbehind);
 5987
 5988                    // if suffix is also present, mimic the newest cursor and replace it
 5989                    if selection.id != newest_anchor.id
 5990                        && snapshot.contains_str_at(range.end, suffix)
 5991                    {
 5992                        range.end += lookahead;
 5993                    }
 5994                }
 5995                range
 5996            };
 5997
 5998            ranges.push(range.clone());
 5999
 6000            if !self.linked_edit_ranges.is_empty() {
 6001                let start_anchor = snapshot.anchor_before(range.start);
 6002                let end_anchor = snapshot.anchor_after(range.end);
 6003                if let Some(ranges) = self
 6004                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6005                {
 6006                    for (buffer, edits) in ranges {
 6007                        linked_edits
 6008                            .entry(buffer.clone())
 6009                            .or_default()
 6010                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6011                    }
 6012                }
 6013            }
 6014        }
 6015
 6016        let common_prefix_len = old_text
 6017            .chars()
 6018            .zip(new_text.chars())
 6019            .take_while(|(a, b)| a == b)
 6020            .map(|(a, _)| a.len_utf8())
 6021            .sum::<usize>();
 6022
 6023        cx.emit(EditorEvent::InputHandled {
 6024            utf16_range_to_replace: None,
 6025            text: new_text[common_prefix_len..].into(),
 6026        });
 6027
 6028        self.transact(window, cx, |editor, window, cx| {
 6029            if let Some(mut snippet) = snippet {
 6030                snippet.text = new_text.to_string();
 6031                editor
 6032                    .insert_snippet(&ranges, snippet, window, cx)
 6033                    .log_err();
 6034            } else {
 6035                editor.buffer.update(cx, |multi_buffer, cx| {
 6036                    let auto_indent = match completion.insert_text_mode {
 6037                        Some(InsertTextMode::AS_IS) => None,
 6038                        _ => editor.autoindent_mode.clone(),
 6039                    };
 6040                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6041                    multi_buffer.edit(edits, auto_indent, cx);
 6042                });
 6043            }
 6044            for (buffer, edits) in linked_edits {
 6045                buffer.update(cx, |buffer, cx| {
 6046                    let snapshot = buffer.snapshot();
 6047                    let edits = edits
 6048                        .into_iter()
 6049                        .map(|(range, text)| {
 6050                            use text::ToPoint as TP;
 6051                            let end_point = TP::to_point(&range.end, &snapshot);
 6052                            let start_point = TP::to_point(&range.start, &snapshot);
 6053                            (start_point..end_point, text)
 6054                        })
 6055                        .sorted_by_key(|(range, _)| range.start);
 6056                    buffer.edit(edits, None, cx);
 6057                })
 6058            }
 6059
 6060            editor.refresh_edit_prediction(true, false, window, cx);
 6061        });
 6062        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 6063
 6064        let show_new_completions_on_confirm = completion
 6065            .confirm
 6066            .as_ref()
 6067            .is_some_and(|confirm| confirm(intent, window, cx));
 6068        if show_new_completions_on_confirm {
 6069            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6070        }
 6071
 6072        let provider = self.completion_provider.as_ref()?;
 6073        drop(completion);
 6074        let apply_edits = provider.apply_additional_edits_for_completion(
 6075            buffer_handle,
 6076            completions_menu.completions.clone(),
 6077            candidate_id,
 6078            true,
 6079            cx,
 6080        );
 6081
 6082        let editor_settings = EditorSettings::get_global(cx);
 6083        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6084            // After the code completion is finished, users often want to know what signatures are needed.
 6085            // so we should automatically call signature_help
 6086            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6087        }
 6088
 6089        Some(cx.foreground_executor().spawn(async move {
 6090            apply_edits.await?;
 6091            Ok(())
 6092        }))
 6093    }
 6094
 6095    pub fn toggle_code_actions(
 6096        &mut self,
 6097        action: &ToggleCodeActions,
 6098        window: &mut Window,
 6099        cx: &mut Context<Self>,
 6100    ) {
 6101        let quick_launch = action.quick_launch;
 6102        let mut context_menu = self.context_menu.borrow_mut();
 6103        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6104            if code_actions.deployed_from == action.deployed_from {
 6105                // Toggle if we're selecting the same one
 6106                *context_menu = None;
 6107                cx.notify();
 6108                return;
 6109            } else {
 6110                // Otherwise, clear it and start a new one
 6111                *context_menu = None;
 6112                cx.notify();
 6113            }
 6114        }
 6115        drop(context_menu);
 6116        let snapshot = self.snapshot(window, cx);
 6117        let deployed_from = action.deployed_from.clone();
 6118        let action = action.clone();
 6119        self.completion_tasks.clear();
 6120        self.discard_edit_prediction(false, cx);
 6121
 6122        let multibuffer_point = match &action.deployed_from {
 6123            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6124                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6125            }
 6126            _ => self.selections.newest::<Point>(cx).head(),
 6127        };
 6128        let Some((buffer, buffer_row)) = snapshot
 6129            .buffer_snapshot
 6130            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6131            .and_then(|(buffer_snapshot, range)| {
 6132                self.buffer()
 6133                    .read(cx)
 6134                    .buffer(buffer_snapshot.remote_id())
 6135                    .map(|buffer| (buffer, range.start.row))
 6136            })
 6137        else {
 6138            return;
 6139        };
 6140        let buffer_id = buffer.read(cx).remote_id();
 6141        let tasks = self
 6142            .tasks
 6143            .get(&(buffer_id, buffer_row))
 6144            .map(|t| Arc::new(t.to_owned()));
 6145
 6146        if !self.focus_handle.is_focused(window) {
 6147            return;
 6148        }
 6149        let project = self.project.clone();
 6150
 6151        let code_actions_task = match deployed_from {
 6152            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6153            _ => self.code_actions(buffer_row, window, cx),
 6154        };
 6155
 6156        let runnable_task = match deployed_from {
 6157            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6158            _ => {
 6159                let mut task_context_task = Task::ready(None);
 6160                if let Some(tasks) = &tasks
 6161                    && let Some(project) = project
 6162                {
 6163                    task_context_task =
 6164                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6165                }
 6166
 6167                cx.spawn_in(window, {
 6168                    let buffer = buffer.clone();
 6169                    async move |editor, cx| {
 6170                        let task_context = task_context_task.await;
 6171
 6172                        let resolved_tasks =
 6173                            tasks
 6174                                .zip(task_context.clone())
 6175                                .map(|(tasks, task_context)| ResolvedTasks {
 6176                                    templates: tasks.resolve(&task_context).collect(),
 6177                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6178                                        multibuffer_point.row,
 6179                                        tasks.column,
 6180                                    )),
 6181                                });
 6182                        let debug_scenarios = editor
 6183                            .update(cx, |editor, cx| {
 6184                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6185                            })?
 6186                            .await;
 6187                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6188                    }
 6189                })
 6190            }
 6191        };
 6192
 6193        cx.spawn_in(window, async move |editor, cx| {
 6194            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6195            let code_actions = code_actions_task.await;
 6196            let spawn_straight_away = quick_launch
 6197                && resolved_tasks
 6198                    .as_ref()
 6199                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6200                && code_actions
 6201                    .as_ref()
 6202                    .is_none_or(|actions| actions.is_empty())
 6203                && debug_scenarios.is_empty();
 6204
 6205            editor.update_in(cx, |editor, window, cx| {
 6206                crate::hover_popover::hide_hover(editor, cx);
 6207                let actions = CodeActionContents::new(
 6208                    resolved_tasks,
 6209                    code_actions,
 6210                    debug_scenarios,
 6211                    task_context.unwrap_or_default(),
 6212                );
 6213
 6214                // Don't show the menu if there are no actions available
 6215                if actions.is_empty() {
 6216                    cx.notify();
 6217                    return Task::ready(Ok(()));
 6218                }
 6219
 6220                *editor.context_menu.borrow_mut() =
 6221                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6222                        buffer,
 6223                        actions,
 6224                        selected_item: Default::default(),
 6225                        scroll_handle: UniformListScrollHandle::default(),
 6226                        deployed_from,
 6227                    }));
 6228                cx.notify();
 6229                if spawn_straight_away
 6230                    && let Some(task) = editor.confirm_code_action(
 6231                        &ConfirmCodeAction { item_ix: Some(0) },
 6232                        window,
 6233                        cx,
 6234                    )
 6235                {
 6236                    return task;
 6237                }
 6238
 6239                Task::ready(Ok(()))
 6240            })
 6241        })
 6242        .detach_and_log_err(cx);
 6243    }
 6244
 6245    fn debug_scenarios(
 6246        &mut self,
 6247        resolved_tasks: &Option<ResolvedTasks>,
 6248        buffer: &Entity<Buffer>,
 6249        cx: &mut App,
 6250    ) -> Task<Vec<task::DebugScenario>> {
 6251        maybe!({
 6252            let project = self.project()?;
 6253            let dap_store = project.read(cx).dap_store();
 6254            let mut scenarios = vec![];
 6255            let resolved_tasks = resolved_tasks.as_ref()?;
 6256            let buffer = buffer.read(cx);
 6257            let language = buffer.language()?;
 6258            let file = buffer.file();
 6259            let debug_adapter = language_settings(language.name().into(), file, cx)
 6260                .debuggers
 6261                .first()
 6262                .map(SharedString::from)
 6263                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6264
 6265            dap_store.update(cx, |dap_store, cx| {
 6266                for (_, task) in &resolved_tasks.templates {
 6267                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6268                        task.original_task().clone(),
 6269                        debug_adapter.clone().into(),
 6270                        task.display_label().to_owned().into(),
 6271                        cx,
 6272                    );
 6273                    scenarios.push(maybe_scenario);
 6274                }
 6275            });
 6276            Some(cx.background_spawn(async move {
 6277                futures::future::join_all(scenarios)
 6278                    .await
 6279                    .into_iter()
 6280                    .flatten()
 6281                    .collect::<Vec<_>>()
 6282            }))
 6283        })
 6284        .unwrap_or_else(|| Task::ready(vec![]))
 6285    }
 6286
 6287    fn code_actions(
 6288        &mut self,
 6289        buffer_row: u32,
 6290        window: &mut Window,
 6291        cx: &mut Context<Self>,
 6292    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6293        let mut task = self.code_actions_task.take();
 6294        cx.spawn_in(window, async move |editor, cx| {
 6295            while let Some(prev_task) = task {
 6296                prev_task.await.log_err();
 6297                task = editor
 6298                    .update(cx, |this, _| this.code_actions_task.take())
 6299                    .ok()?;
 6300            }
 6301
 6302            editor
 6303                .update(cx, |editor, cx| {
 6304                    editor
 6305                        .available_code_actions
 6306                        .clone()
 6307                        .and_then(|(location, code_actions)| {
 6308                            let snapshot = location.buffer.read(cx).snapshot();
 6309                            let point_range = location.range.to_point(&snapshot);
 6310                            let point_range = point_range.start.row..=point_range.end.row;
 6311                            if point_range.contains(&buffer_row) {
 6312                                Some(code_actions)
 6313                            } else {
 6314                                None
 6315                            }
 6316                        })
 6317                })
 6318                .ok()
 6319                .flatten()
 6320        })
 6321    }
 6322
 6323    pub fn confirm_code_action(
 6324        &mut self,
 6325        action: &ConfirmCodeAction,
 6326        window: &mut Window,
 6327        cx: &mut Context<Self>,
 6328    ) -> Option<Task<Result<()>>> {
 6329        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6330
 6331        let actions_menu =
 6332            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6333                menu
 6334            } else {
 6335                return None;
 6336            };
 6337
 6338        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6339        let action = actions_menu.actions.get(action_ix)?;
 6340        let title = action.label();
 6341        let buffer = actions_menu.buffer;
 6342        let workspace = self.workspace()?;
 6343
 6344        match action {
 6345            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6346                workspace.update(cx, |workspace, cx| {
 6347                    workspace.schedule_resolved_task(
 6348                        task_source_kind,
 6349                        resolved_task,
 6350                        false,
 6351                        window,
 6352                        cx,
 6353                    );
 6354
 6355                    Some(Task::ready(Ok(())))
 6356                })
 6357            }
 6358            CodeActionsItem::CodeAction {
 6359                excerpt_id,
 6360                action,
 6361                provider,
 6362            } => {
 6363                let apply_code_action =
 6364                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6365                let workspace = workspace.downgrade();
 6366                Some(cx.spawn_in(window, async move |editor, cx| {
 6367                    let project_transaction = apply_code_action.await?;
 6368                    Self::open_project_transaction(
 6369                        &editor,
 6370                        workspace,
 6371                        project_transaction,
 6372                        title,
 6373                        cx,
 6374                    )
 6375                    .await
 6376                }))
 6377            }
 6378            CodeActionsItem::DebugScenario(scenario) => {
 6379                let context = actions_menu.actions.context;
 6380
 6381                workspace.update(cx, |workspace, cx| {
 6382                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6383                    workspace.start_debug_session(
 6384                        scenario,
 6385                        context,
 6386                        Some(buffer),
 6387                        None,
 6388                        window,
 6389                        cx,
 6390                    );
 6391                });
 6392                Some(Task::ready(Ok(())))
 6393            }
 6394        }
 6395    }
 6396
 6397    pub async fn open_project_transaction(
 6398        editor: &WeakEntity<Editor>,
 6399        workspace: WeakEntity<Workspace>,
 6400        transaction: ProjectTransaction,
 6401        title: String,
 6402        cx: &mut AsyncWindowContext,
 6403    ) -> Result<()> {
 6404        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6405        cx.update(|_, cx| {
 6406            entries.sort_unstable_by_key(|(buffer, _)| {
 6407                buffer.read(cx).file().map(|f| f.path().clone())
 6408            });
 6409        })?;
 6410
 6411        // If the project transaction's edits are all contained within this editor, then
 6412        // avoid opening a new editor to display them.
 6413
 6414        if let Some((buffer, transaction)) = entries.first() {
 6415            if entries.len() == 1 {
 6416                let excerpt = editor.update(cx, |editor, cx| {
 6417                    editor
 6418                        .buffer()
 6419                        .read(cx)
 6420                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6421                })?;
 6422                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6423                    && excerpted_buffer == *buffer
 6424                {
 6425                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6426                        let excerpt_range = excerpt_range.to_offset(buffer);
 6427                        buffer
 6428                            .edited_ranges_for_transaction::<usize>(transaction)
 6429                            .all(|range| {
 6430                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6431                            })
 6432                    })?;
 6433
 6434                    if all_edits_within_excerpt {
 6435                        return Ok(());
 6436                    }
 6437                }
 6438            }
 6439        } else {
 6440            return Ok(());
 6441        }
 6442
 6443        let mut ranges_to_highlight = Vec::new();
 6444        let excerpt_buffer = cx.new(|cx| {
 6445            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6446            for (buffer_handle, transaction) in &entries {
 6447                let edited_ranges = buffer_handle
 6448                    .read(cx)
 6449                    .edited_ranges_for_transaction::<Point>(transaction)
 6450                    .collect::<Vec<_>>();
 6451                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6452                    PathKey::for_buffer(buffer_handle, cx),
 6453                    buffer_handle.clone(),
 6454                    edited_ranges,
 6455                    multibuffer_context_lines(cx),
 6456                    cx,
 6457                );
 6458
 6459                ranges_to_highlight.extend(ranges);
 6460            }
 6461            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6462            multibuffer
 6463        })?;
 6464
 6465        workspace.update_in(cx, |workspace, window, cx| {
 6466            let project = workspace.project().clone();
 6467            let editor =
 6468                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6469            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6470            editor.update(cx, |editor, cx| {
 6471                editor.highlight_background::<Self>(
 6472                    &ranges_to_highlight,
 6473                    |theme| theme.colors().editor_highlighted_line_background,
 6474                    cx,
 6475                );
 6476            });
 6477        })?;
 6478
 6479        Ok(())
 6480    }
 6481
 6482    pub fn clear_code_action_providers(&mut self) {
 6483        self.code_action_providers.clear();
 6484        self.available_code_actions.take();
 6485    }
 6486
 6487    pub fn add_code_action_provider(
 6488        &mut self,
 6489        provider: Rc<dyn CodeActionProvider>,
 6490        window: &mut Window,
 6491        cx: &mut Context<Self>,
 6492    ) {
 6493        if self
 6494            .code_action_providers
 6495            .iter()
 6496            .any(|existing_provider| existing_provider.id() == provider.id())
 6497        {
 6498            return;
 6499        }
 6500
 6501        self.code_action_providers.push(provider);
 6502        self.refresh_code_actions(window, cx);
 6503    }
 6504
 6505    pub fn remove_code_action_provider(
 6506        &mut self,
 6507        id: Arc<str>,
 6508        window: &mut Window,
 6509        cx: &mut Context<Self>,
 6510    ) {
 6511        self.code_action_providers
 6512            .retain(|provider| provider.id() != id);
 6513        self.refresh_code_actions(window, cx);
 6514    }
 6515
 6516    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6517        !self.code_action_providers.is_empty()
 6518            && EditorSettings::get_global(cx).toolbar.code_actions
 6519    }
 6520
 6521    pub fn has_available_code_actions(&self) -> bool {
 6522        self.available_code_actions
 6523            .as_ref()
 6524            .is_some_and(|(_, actions)| !actions.is_empty())
 6525    }
 6526
 6527    fn render_inline_code_actions(
 6528        &self,
 6529        icon_size: ui::IconSize,
 6530        display_row: DisplayRow,
 6531        is_active: bool,
 6532        cx: &mut Context<Self>,
 6533    ) -> AnyElement {
 6534        let show_tooltip = !self.context_menu_visible();
 6535        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6536            .icon_size(icon_size)
 6537            .shape(ui::IconButtonShape::Square)
 6538            .icon_color(ui::Color::Hidden)
 6539            .toggle_state(is_active)
 6540            .when(show_tooltip, |this| {
 6541                this.tooltip({
 6542                    let focus_handle = self.focus_handle.clone();
 6543                    move |window, cx| {
 6544                        Tooltip::for_action_in(
 6545                            "Toggle Code Actions",
 6546                            &ToggleCodeActions {
 6547                                deployed_from: None,
 6548                                quick_launch: false,
 6549                            },
 6550                            &focus_handle,
 6551                            window,
 6552                            cx,
 6553                        )
 6554                    }
 6555                })
 6556            })
 6557            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6558                window.focus(&editor.focus_handle(cx));
 6559                editor.toggle_code_actions(
 6560                    &crate::actions::ToggleCodeActions {
 6561                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6562                            display_row,
 6563                        )),
 6564                        quick_launch: false,
 6565                    },
 6566                    window,
 6567                    cx,
 6568                );
 6569            }))
 6570            .into_any_element()
 6571    }
 6572
 6573    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6574        &self.context_menu
 6575    }
 6576
 6577    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6578        let newest_selection = self.selections.newest_anchor().clone();
 6579        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6580        let buffer = self.buffer.read(cx);
 6581        if newest_selection.head().diff_base_anchor.is_some() {
 6582            return None;
 6583        }
 6584        let (start_buffer, start) =
 6585            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6586        let (end_buffer, end) =
 6587            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6588        if start_buffer != end_buffer {
 6589            return None;
 6590        }
 6591
 6592        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6593            cx.background_executor()
 6594                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6595                .await;
 6596
 6597            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6598                let providers = this.code_action_providers.clone();
 6599                let tasks = this
 6600                    .code_action_providers
 6601                    .iter()
 6602                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6603                    .collect::<Vec<_>>();
 6604                (providers, tasks)
 6605            })?;
 6606
 6607            let mut actions = Vec::new();
 6608            for (provider, provider_actions) in
 6609                providers.into_iter().zip(future::join_all(tasks).await)
 6610            {
 6611                if let Some(provider_actions) = provider_actions.log_err() {
 6612                    actions.extend(provider_actions.into_iter().map(|action| {
 6613                        AvailableCodeAction {
 6614                            excerpt_id: newest_selection.start.excerpt_id,
 6615                            action,
 6616                            provider: provider.clone(),
 6617                        }
 6618                    }));
 6619                }
 6620            }
 6621
 6622            this.update(cx, |this, cx| {
 6623                this.available_code_actions = if actions.is_empty() {
 6624                    None
 6625                } else {
 6626                    Some((
 6627                        Location {
 6628                            buffer: start_buffer,
 6629                            range: start..end,
 6630                        },
 6631                        actions.into(),
 6632                    ))
 6633                };
 6634                cx.notify();
 6635            })
 6636        }));
 6637        None
 6638    }
 6639
 6640    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6641        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6642            self.show_git_blame_inline = false;
 6643
 6644            self.show_git_blame_inline_delay_task =
 6645                Some(cx.spawn_in(window, async move |this, cx| {
 6646                    cx.background_executor().timer(delay).await;
 6647
 6648                    this.update(cx, |this, cx| {
 6649                        this.show_git_blame_inline = true;
 6650                        cx.notify();
 6651                    })
 6652                    .log_err();
 6653                }));
 6654        }
 6655    }
 6656
 6657    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6658        let snapshot = self.snapshot(window, cx);
 6659        let cursor = self.selections.newest::<Point>(cx).head();
 6660        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6661        else {
 6662            return;
 6663        };
 6664
 6665        let Some(blame) = self.blame.as_ref() else {
 6666            return;
 6667        };
 6668
 6669        let row_info = RowInfo {
 6670            buffer_id: Some(buffer.remote_id()),
 6671            buffer_row: Some(point.row),
 6672            ..Default::default()
 6673        };
 6674        let Some((buffer, blame_entry)) = blame
 6675            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6676            .flatten()
 6677        else {
 6678            return;
 6679        };
 6680
 6681        let anchor = self.selections.newest_anchor().head();
 6682        let position = self.to_pixel_point(anchor, &snapshot, window);
 6683        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6684            self.show_blame_popover(
 6685                buffer,
 6686                &blame_entry,
 6687                position + last_bounds.origin,
 6688                true,
 6689                cx,
 6690            );
 6691        };
 6692    }
 6693
 6694    fn show_blame_popover(
 6695        &mut self,
 6696        buffer: BufferId,
 6697        blame_entry: &BlameEntry,
 6698        position: gpui::Point<Pixels>,
 6699        ignore_timeout: bool,
 6700        cx: &mut Context<Self>,
 6701    ) {
 6702        if let Some(state) = &mut self.inline_blame_popover {
 6703            state.hide_task.take();
 6704        } else {
 6705            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6706            let blame_entry = blame_entry.clone();
 6707            let show_task = cx.spawn(async move |editor, cx| {
 6708                if !ignore_timeout {
 6709                    cx.background_executor()
 6710                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6711                        .await;
 6712                }
 6713                editor
 6714                    .update(cx, |editor, cx| {
 6715                        editor.inline_blame_popover_show_task.take();
 6716                        let Some(blame) = editor.blame.as_ref() else {
 6717                            return;
 6718                        };
 6719                        let blame = blame.read(cx);
 6720                        let details = blame.details_for_entry(buffer, &blame_entry);
 6721                        let markdown = cx.new(|cx| {
 6722                            Markdown::new(
 6723                                details
 6724                                    .as_ref()
 6725                                    .map(|message| message.message.clone())
 6726                                    .unwrap_or_default(),
 6727                                None,
 6728                                None,
 6729                                cx,
 6730                            )
 6731                        });
 6732                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6733                            position,
 6734                            hide_task: None,
 6735                            popover_bounds: None,
 6736                            popover_state: InlineBlamePopoverState {
 6737                                scroll_handle: ScrollHandle::new(),
 6738                                commit_message: details,
 6739                                markdown,
 6740                            },
 6741                            keyboard_grace: ignore_timeout,
 6742                        });
 6743                        cx.notify();
 6744                    })
 6745                    .ok();
 6746            });
 6747            self.inline_blame_popover_show_task = Some(show_task);
 6748        }
 6749    }
 6750
 6751    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6752        self.inline_blame_popover_show_task.take();
 6753        if let Some(state) = &mut self.inline_blame_popover {
 6754            let hide_task = cx.spawn(async move |editor, cx| {
 6755                cx.background_executor()
 6756                    .timer(std::time::Duration::from_millis(100))
 6757                    .await;
 6758                editor
 6759                    .update(cx, |editor, cx| {
 6760                        editor.inline_blame_popover.take();
 6761                        cx.notify();
 6762                    })
 6763                    .ok();
 6764            });
 6765            state.hide_task = Some(hide_task);
 6766        }
 6767    }
 6768
 6769    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6770        if self.pending_rename.is_some() {
 6771            return None;
 6772        }
 6773
 6774        let provider = self.semantics_provider.clone()?;
 6775        let buffer = self.buffer.read(cx);
 6776        let newest_selection = self.selections.newest_anchor().clone();
 6777        let cursor_position = newest_selection.head();
 6778        let (cursor_buffer, cursor_buffer_position) =
 6779            buffer.text_anchor_for_position(cursor_position, cx)?;
 6780        let (tail_buffer, tail_buffer_position) =
 6781            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6782        if cursor_buffer != tail_buffer {
 6783            return None;
 6784        }
 6785
 6786        let snapshot = cursor_buffer.read(cx).snapshot();
 6787        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6788        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6789        if start_word_range != end_word_range {
 6790            self.document_highlights_task.take();
 6791            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6792            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6793            return None;
 6794        }
 6795
 6796        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6797        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6798            cx.background_executor()
 6799                .timer(Duration::from_millis(debounce))
 6800                .await;
 6801
 6802            let highlights = if let Some(highlights) = cx
 6803                .update(|cx| {
 6804                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6805                })
 6806                .ok()
 6807                .flatten()
 6808            {
 6809                highlights.await.log_err()
 6810            } else {
 6811                None
 6812            };
 6813
 6814            if let Some(highlights) = highlights {
 6815                this.update(cx, |this, cx| {
 6816                    if this.pending_rename.is_some() {
 6817                        return;
 6818                    }
 6819
 6820                    let buffer = this.buffer.read(cx);
 6821                    if buffer
 6822                        .text_anchor_for_position(cursor_position, cx)
 6823                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6824                    {
 6825                        return;
 6826                    }
 6827
 6828                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6829                    let mut write_ranges = Vec::new();
 6830                    let mut read_ranges = Vec::new();
 6831                    for highlight in highlights {
 6832                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6833                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6834                        {
 6835                            let start = highlight
 6836                                .range
 6837                                .start
 6838                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6839                            let end = highlight
 6840                                .range
 6841                                .end
 6842                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6843                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6844                                continue;
 6845                            }
 6846
 6847                            let range = Anchor {
 6848                                buffer_id: Some(buffer_id),
 6849                                excerpt_id,
 6850                                text_anchor: start,
 6851                                diff_base_anchor: None,
 6852                            }..Anchor {
 6853                                buffer_id: Some(buffer_id),
 6854                                excerpt_id,
 6855                                text_anchor: end,
 6856                                diff_base_anchor: None,
 6857                            };
 6858                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6859                                write_ranges.push(range);
 6860                            } else {
 6861                                read_ranges.push(range);
 6862                            }
 6863                        }
 6864                    }
 6865
 6866                    this.highlight_background::<DocumentHighlightRead>(
 6867                        &read_ranges,
 6868                        |theme| theme.colors().editor_document_highlight_read_background,
 6869                        cx,
 6870                    );
 6871                    this.highlight_background::<DocumentHighlightWrite>(
 6872                        &write_ranges,
 6873                        |theme| theme.colors().editor_document_highlight_write_background,
 6874                        cx,
 6875                    );
 6876                    cx.notify();
 6877                })
 6878                .log_err();
 6879            }
 6880        }));
 6881        None
 6882    }
 6883
 6884    fn prepare_highlight_query_from_selection(
 6885        &mut self,
 6886        cx: &mut Context<Editor>,
 6887    ) -> Option<(String, Range<Anchor>)> {
 6888        if matches!(self.mode, EditorMode::SingleLine) {
 6889            return None;
 6890        }
 6891        if !EditorSettings::get_global(cx).selection_highlight {
 6892            return None;
 6893        }
 6894        if self.selections.count() != 1 || self.selections.line_mode {
 6895            return None;
 6896        }
 6897        let selection = self.selections.newest::<Point>(cx);
 6898        if selection.is_empty() || selection.start.row != selection.end.row {
 6899            return None;
 6900        }
 6901        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6902        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6903        let query = multi_buffer_snapshot
 6904            .text_for_range(selection_anchor_range.clone())
 6905            .collect::<String>();
 6906        if query.trim().is_empty() {
 6907            return None;
 6908        }
 6909        Some((query, selection_anchor_range))
 6910    }
 6911
 6912    fn update_selection_occurrence_highlights(
 6913        &mut self,
 6914        query_text: String,
 6915        query_range: Range<Anchor>,
 6916        multi_buffer_range_to_query: Range<Point>,
 6917        use_debounce: bool,
 6918        window: &mut Window,
 6919        cx: &mut Context<Editor>,
 6920    ) -> Task<()> {
 6921        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6922        cx.spawn_in(window, async move |editor, cx| {
 6923            if use_debounce {
 6924                cx.background_executor()
 6925                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6926                    .await;
 6927            }
 6928            let match_task = cx.background_spawn(async move {
 6929                let buffer_ranges = multi_buffer_snapshot
 6930                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6931                    .into_iter()
 6932                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6933                let mut match_ranges = Vec::new();
 6934                let Ok(regex) = project::search::SearchQuery::text(
 6935                    query_text.clone(),
 6936                    false,
 6937                    false,
 6938                    false,
 6939                    Default::default(),
 6940                    Default::default(),
 6941                    false,
 6942                    None,
 6943                ) else {
 6944                    return Vec::default();
 6945                };
 6946                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6947                    match_ranges.extend(
 6948                        regex
 6949                            .search(buffer_snapshot, Some(search_range.clone()))
 6950                            .await
 6951                            .into_iter()
 6952                            .filter_map(|match_range| {
 6953                                let match_start = buffer_snapshot
 6954                                    .anchor_after(search_range.start + match_range.start);
 6955                                let match_end = buffer_snapshot
 6956                                    .anchor_before(search_range.start + match_range.end);
 6957                                let match_anchor_range = Anchor::range_in_buffer(
 6958                                    excerpt_id,
 6959                                    buffer_snapshot.remote_id(),
 6960                                    match_start..match_end,
 6961                                );
 6962                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6963                            }),
 6964                    );
 6965                }
 6966                match_ranges
 6967            });
 6968            let match_ranges = match_task.await;
 6969            editor
 6970                .update_in(cx, |editor, _, cx| {
 6971                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6972                    if !match_ranges.is_empty() {
 6973                        editor.highlight_background::<SelectedTextHighlight>(
 6974                            &match_ranges,
 6975                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6976                            cx,
 6977                        )
 6978                    }
 6979                })
 6980                .log_err();
 6981        })
 6982    }
 6983
 6984    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6985        struct NewlineFold;
 6986        let type_id = std::any::TypeId::of::<NewlineFold>();
 6987        if !self.mode.is_single_line() {
 6988            return;
 6989        }
 6990        let snapshot = self.snapshot(window, cx);
 6991        if snapshot.buffer_snapshot.max_point().row == 0 {
 6992            return;
 6993        }
 6994        let task = cx.background_spawn(async move {
 6995            let new_newlines = snapshot
 6996                .buffer_chars_at(0)
 6997                .filter_map(|(c, i)| {
 6998                    if c == '\n' {
 6999                        Some(
 7000                            snapshot.buffer_snapshot.anchor_after(i)
 7001                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7002                        )
 7003                    } else {
 7004                        None
 7005                    }
 7006                })
 7007                .collect::<Vec<_>>();
 7008            let existing_newlines = snapshot
 7009                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7010                .filter_map(|fold| {
 7011                    if fold.placeholder.type_tag == Some(type_id) {
 7012                        Some(fold.range.start..fold.range.end)
 7013                    } else {
 7014                        None
 7015                    }
 7016                })
 7017                .collect::<Vec<_>>();
 7018
 7019            (new_newlines, existing_newlines)
 7020        });
 7021        self.folding_newlines = cx.spawn(async move |this, cx| {
 7022            let (new_newlines, existing_newlines) = task.await;
 7023            if new_newlines == existing_newlines {
 7024                return;
 7025            }
 7026            let placeholder = FoldPlaceholder {
 7027                render: Arc::new(move |_, _, cx| {
 7028                    div()
 7029                        .bg(cx.theme().status().hint_background)
 7030                        .border_b_1()
 7031                        .size_full()
 7032                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7033                        .border_color(cx.theme().status().hint)
 7034                        .child("\\n")
 7035                        .into_any()
 7036                }),
 7037                constrain_width: false,
 7038                merge_adjacent: false,
 7039                type_tag: Some(type_id),
 7040            };
 7041            let creases = new_newlines
 7042                .into_iter()
 7043                .map(|range| Crease::simple(range, placeholder.clone()))
 7044                .collect();
 7045            this.update(cx, |this, cx| {
 7046                this.display_map.update(cx, |display_map, cx| {
 7047                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7048                    display_map.fold(creases, cx);
 7049                });
 7050            })
 7051            .ok();
 7052        });
 7053    }
 7054
 7055    fn refresh_selected_text_highlights(
 7056        &mut self,
 7057        on_buffer_edit: bool,
 7058        window: &mut Window,
 7059        cx: &mut Context<Editor>,
 7060    ) {
 7061        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7062        else {
 7063            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7064            self.quick_selection_highlight_task.take();
 7065            self.debounced_selection_highlight_task.take();
 7066            return;
 7067        };
 7068        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7069        if on_buffer_edit
 7070            || self
 7071                .quick_selection_highlight_task
 7072                .as_ref()
 7073                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7074        {
 7075            let multi_buffer_visible_start = self
 7076                .scroll_manager
 7077                .anchor()
 7078                .anchor
 7079                .to_point(&multi_buffer_snapshot);
 7080            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7081                multi_buffer_visible_start
 7082                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7083                Bias::Left,
 7084            );
 7085            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7086            self.quick_selection_highlight_task = Some((
 7087                query_range.clone(),
 7088                self.update_selection_occurrence_highlights(
 7089                    query_text.clone(),
 7090                    query_range.clone(),
 7091                    multi_buffer_visible_range,
 7092                    false,
 7093                    window,
 7094                    cx,
 7095                ),
 7096            ));
 7097        }
 7098        if on_buffer_edit
 7099            || self
 7100                .debounced_selection_highlight_task
 7101                .as_ref()
 7102                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7103        {
 7104            let multi_buffer_start = multi_buffer_snapshot
 7105                .anchor_before(0)
 7106                .to_point(&multi_buffer_snapshot);
 7107            let multi_buffer_end = multi_buffer_snapshot
 7108                .anchor_after(multi_buffer_snapshot.len())
 7109                .to_point(&multi_buffer_snapshot);
 7110            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7111            self.debounced_selection_highlight_task = Some((
 7112                query_range.clone(),
 7113                self.update_selection_occurrence_highlights(
 7114                    query_text,
 7115                    query_range,
 7116                    multi_buffer_full_range,
 7117                    true,
 7118                    window,
 7119                    cx,
 7120                ),
 7121            ));
 7122        }
 7123    }
 7124
 7125    pub fn refresh_edit_prediction(
 7126        &mut self,
 7127        debounce: bool,
 7128        user_requested: bool,
 7129        window: &mut Window,
 7130        cx: &mut Context<Self>,
 7131    ) -> Option<()> {
 7132        if DisableAiSettings::get_global(cx).disable_ai {
 7133            return None;
 7134        }
 7135
 7136        let provider = self.edit_prediction_provider()?;
 7137        let cursor = self.selections.newest_anchor().head();
 7138        let (buffer, cursor_buffer_position) =
 7139            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7140
 7141        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7142            self.discard_edit_prediction(false, cx);
 7143            return None;
 7144        }
 7145
 7146        if !user_requested
 7147            && (!self.should_show_edit_predictions()
 7148                || !self.is_focused(window)
 7149                || buffer.read(cx).is_empty())
 7150        {
 7151            self.discard_edit_prediction(false, cx);
 7152            return None;
 7153        }
 7154
 7155        self.update_visible_edit_prediction(window, cx);
 7156        provider.refresh(
 7157            self.project.clone(),
 7158            buffer,
 7159            cursor_buffer_position,
 7160            debounce,
 7161            cx,
 7162        );
 7163        Some(())
 7164    }
 7165
 7166    fn show_edit_predictions_in_menu(&self) -> bool {
 7167        match self.edit_prediction_settings {
 7168            EditPredictionSettings::Disabled => false,
 7169            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7170        }
 7171    }
 7172
 7173    pub fn edit_predictions_enabled(&self) -> bool {
 7174        match self.edit_prediction_settings {
 7175            EditPredictionSettings::Disabled => false,
 7176            EditPredictionSettings::Enabled { .. } => true,
 7177        }
 7178    }
 7179
 7180    fn edit_prediction_requires_modifier(&self) -> bool {
 7181        match self.edit_prediction_settings {
 7182            EditPredictionSettings::Disabled => false,
 7183            EditPredictionSettings::Enabled {
 7184                preview_requires_modifier,
 7185                ..
 7186            } => preview_requires_modifier,
 7187        }
 7188    }
 7189
 7190    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7191        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7192            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7193            self.discard_edit_prediction(false, cx);
 7194        } else {
 7195            let selection = self.selections.newest_anchor();
 7196            let cursor = selection.head();
 7197
 7198            if let Some((buffer, cursor_buffer_position)) =
 7199                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7200            {
 7201                self.edit_prediction_settings =
 7202                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7203            }
 7204        }
 7205    }
 7206
 7207    fn edit_prediction_settings_at_position(
 7208        &self,
 7209        buffer: &Entity<Buffer>,
 7210        buffer_position: language::Anchor,
 7211        cx: &App,
 7212    ) -> EditPredictionSettings {
 7213        if !self.mode.is_full()
 7214            || !self.show_edit_predictions_override.unwrap_or(true)
 7215            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7216        {
 7217            return EditPredictionSettings::Disabled;
 7218        }
 7219
 7220        let buffer = buffer.read(cx);
 7221
 7222        let file = buffer.file();
 7223
 7224        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7225            return EditPredictionSettings::Disabled;
 7226        };
 7227
 7228        let by_provider = matches!(
 7229            self.menu_edit_predictions_policy,
 7230            MenuEditPredictionsPolicy::ByProvider
 7231        );
 7232
 7233        let show_in_menu = by_provider
 7234            && self
 7235                .edit_prediction_provider
 7236                .as_ref()
 7237                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7238
 7239        let preview_requires_modifier =
 7240            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7241
 7242        EditPredictionSettings::Enabled {
 7243            show_in_menu,
 7244            preview_requires_modifier,
 7245        }
 7246    }
 7247
 7248    fn should_show_edit_predictions(&self) -> bool {
 7249        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7250    }
 7251
 7252    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7253        matches!(
 7254            self.edit_prediction_preview,
 7255            EditPredictionPreview::Active { .. }
 7256        )
 7257    }
 7258
 7259    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7260        let cursor = self.selections.newest_anchor().head();
 7261        if let Some((buffer, cursor_position)) =
 7262            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7263        {
 7264            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7265        } else {
 7266            false
 7267        }
 7268    }
 7269
 7270    pub fn supports_minimap(&self, cx: &App) -> bool {
 7271        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7272    }
 7273
 7274    fn edit_predictions_enabled_in_buffer(
 7275        &self,
 7276        buffer: &Entity<Buffer>,
 7277        buffer_position: language::Anchor,
 7278        cx: &App,
 7279    ) -> bool {
 7280        maybe!({
 7281            if self.read_only(cx) {
 7282                return Some(false);
 7283            }
 7284            let provider = self.edit_prediction_provider()?;
 7285            if !provider.is_enabled(buffer, buffer_position, cx) {
 7286                return Some(false);
 7287            }
 7288            let buffer = buffer.read(cx);
 7289            let Some(file) = buffer.file() else {
 7290                return Some(true);
 7291            };
 7292            let settings = all_language_settings(Some(file), cx);
 7293            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7294        })
 7295        .unwrap_or(false)
 7296    }
 7297
 7298    fn cycle_edit_prediction(
 7299        &mut self,
 7300        direction: Direction,
 7301        window: &mut Window,
 7302        cx: &mut Context<Self>,
 7303    ) -> Option<()> {
 7304        let provider = self.edit_prediction_provider()?;
 7305        let cursor = self.selections.newest_anchor().head();
 7306        let (buffer, cursor_buffer_position) =
 7307            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7308        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7309            return None;
 7310        }
 7311
 7312        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7313        self.update_visible_edit_prediction(window, cx);
 7314
 7315        Some(())
 7316    }
 7317
 7318    pub fn show_edit_prediction(
 7319        &mut self,
 7320        _: &ShowEditPrediction,
 7321        window: &mut Window,
 7322        cx: &mut Context<Self>,
 7323    ) {
 7324        if !self.has_active_edit_prediction() {
 7325            self.refresh_edit_prediction(false, true, window, cx);
 7326            return;
 7327        }
 7328
 7329        self.update_visible_edit_prediction(window, cx);
 7330    }
 7331
 7332    pub fn display_cursor_names(
 7333        &mut self,
 7334        _: &DisplayCursorNames,
 7335        window: &mut Window,
 7336        cx: &mut Context<Self>,
 7337    ) {
 7338        self.show_cursor_names(window, cx);
 7339    }
 7340
 7341    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7342        self.show_cursor_names = true;
 7343        cx.notify();
 7344        cx.spawn_in(window, async move |this, cx| {
 7345            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7346            this.update(cx, |this, cx| {
 7347                this.show_cursor_names = false;
 7348                cx.notify()
 7349            })
 7350            .ok()
 7351        })
 7352        .detach();
 7353    }
 7354
 7355    pub fn next_edit_prediction(
 7356        &mut self,
 7357        _: &NextEditPrediction,
 7358        window: &mut Window,
 7359        cx: &mut Context<Self>,
 7360    ) {
 7361        if self.has_active_edit_prediction() {
 7362            self.cycle_edit_prediction(Direction::Next, window, cx);
 7363        } else {
 7364            let is_copilot_disabled = self
 7365                .refresh_edit_prediction(false, true, window, cx)
 7366                .is_none();
 7367            if is_copilot_disabled {
 7368                cx.propagate();
 7369            }
 7370        }
 7371    }
 7372
 7373    pub fn previous_edit_prediction(
 7374        &mut self,
 7375        _: &PreviousEditPrediction,
 7376        window: &mut Window,
 7377        cx: &mut Context<Self>,
 7378    ) {
 7379        if self.has_active_edit_prediction() {
 7380            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7381        } else {
 7382            let is_copilot_disabled = self
 7383                .refresh_edit_prediction(false, true, window, cx)
 7384                .is_none();
 7385            if is_copilot_disabled {
 7386                cx.propagate();
 7387            }
 7388        }
 7389    }
 7390
 7391    pub fn accept_edit_prediction(
 7392        &mut self,
 7393        _: &AcceptEditPrediction,
 7394        window: &mut Window,
 7395        cx: &mut Context<Self>,
 7396    ) {
 7397        if self.show_edit_predictions_in_menu() {
 7398            self.hide_context_menu(window, cx);
 7399        }
 7400
 7401        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7402            return;
 7403        };
 7404
 7405        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7406
 7407        match &active_edit_prediction.completion {
 7408            EditPrediction::Move { target, .. } => {
 7409                let target = *target;
 7410
 7411                if let Some(position_map) = &self.last_position_map {
 7412                    if position_map
 7413                        .visible_row_range
 7414                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7415                        || !self.edit_prediction_requires_modifier()
 7416                    {
 7417                        self.unfold_ranges(&[target..target], true, false, cx);
 7418                        // Note that this is also done in vim's handler of the Tab action.
 7419                        self.change_selections(
 7420                            SelectionEffects::scroll(Autoscroll::newest()),
 7421                            window,
 7422                            cx,
 7423                            |selections| {
 7424                                selections.select_anchor_ranges([target..target]);
 7425                            },
 7426                        );
 7427                        self.clear_row_highlights::<EditPredictionPreview>();
 7428
 7429                        self.edit_prediction_preview
 7430                            .set_previous_scroll_position(None);
 7431                    } else {
 7432                        self.edit_prediction_preview
 7433                            .set_previous_scroll_position(Some(
 7434                                position_map.snapshot.scroll_anchor,
 7435                            ));
 7436
 7437                        self.highlight_rows::<EditPredictionPreview>(
 7438                            target..target,
 7439                            cx.theme().colors().editor_highlighted_line_background,
 7440                            RowHighlightOptions {
 7441                                autoscroll: true,
 7442                                ..Default::default()
 7443                            },
 7444                            cx,
 7445                        );
 7446                        self.request_autoscroll(Autoscroll::fit(), cx);
 7447                    }
 7448                }
 7449            }
 7450            EditPrediction::Edit { edits, .. } => {
 7451                if let Some(provider) = self.edit_prediction_provider() {
 7452                    provider.accept(cx);
 7453                }
 7454
 7455                // Store the transaction ID and selections before applying the edit
 7456                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7457
 7458                let snapshot = self.buffer.read(cx).snapshot(cx);
 7459                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7460
 7461                self.buffer.update(cx, |buffer, cx| {
 7462                    buffer.edit(edits.iter().cloned(), None, cx)
 7463                });
 7464
 7465                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7466                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7467                });
 7468
 7469                let selections = self.selections.disjoint_anchors();
 7470                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7471                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7472                    if has_new_transaction {
 7473                        self.selection_history
 7474                            .insert_transaction(transaction_id_now, selections);
 7475                    }
 7476                }
 7477
 7478                self.update_visible_edit_prediction(window, cx);
 7479                if self.active_edit_prediction.is_none() {
 7480                    self.refresh_edit_prediction(true, true, window, cx);
 7481                }
 7482
 7483                cx.notify();
 7484            }
 7485        }
 7486
 7487        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7488    }
 7489
 7490    pub fn accept_partial_edit_prediction(
 7491        &mut self,
 7492        _: &AcceptPartialEditPrediction,
 7493        window: &mut Window,
 7494        cx: &mut Context<Self>,
 7495    ) {
 7496        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7497            return;
 7498        };
 7499        if self.selections.count() != 1 {
 7500            return;
 7501        }
 7502
 7503        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7504
 7505        match &active_edit_prediction.completion {
 7506            EditPrediction::Move { target, .. } => {
 7507                let target = *target;
 7508                self.change_selections(
 7509                    SelectionEffects::scroll(Autoscroll::newest()),
 7510                    window,
 7511                    cx,
 7512                    |selections| {
 7513                        selections.select_anchor_ranges([target..target]);
 7514                    },
 7515                );
 7516            }
 7517            EditPrediction::Edit { edits, .. } => {
 7518                // Find an insertion that starts at the cursor position.
 7519                let snapshot = self.buffer.read(cx).snapshot(cx);
 7520                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7521                let insertion = edits.iter().find_map(|(range, text)| {
 7522                    let range = range.to_offset(&snapshot);
 7523                    if range.is_empty() && range.start == cursor_offset {
 7524                        Some(text)
 7525                    } else {
 7526                        None
 7527                    }
 7528                });
 7529
 7530                if let Some(text) = insertion {
 7531                    let mut partial_completion = text
 7532                        .chars()
 7533                        .by_ref()
 7534                        .take_while(|c| c.is_alphabetic())
 7535                        .collect::<String>();
 7536                    if partial_completion.is_empty() {
 7537                        partial_completion = text
 7538                            .chars()
 7539                            .by_ref()
 7540                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7541                            .collect::<String>();
 7542                    }
 7543
 7544                    cx.emit(EditorEvent::InputHandled {
 7545                        utf16_range_to_replace: None,
 7546                        text: partial_completion.clone().into(),
 7547                    });
 7548
 7549                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7550
 7551                    self.refresh_edit_prediction(true, true, window, cx);
 7552                    cx.notify();
 7553                } else {
 7554                    self.accept_edit_prediction(&Default::default(), window, cx);
 7555                }
 7556            }
 7557        }
 7558    }
 7559
 7560    fn discard_edit_prediction(
 7561        &mut self,
 7562        should_report_edit_prediction_event: bool,
 7563        cx: &mut Context<Self>,
 7564    ) -> bool {
 7565        if should_report_edit_prediction_event {
 7566            let completion_id = self
 7567                .active_edit_prediction
 7568                .as_ref()
 7569                .and_then(|active_completion| active_completion.completion_id.clone());
 7570
 7571            self.report_edit_prediction_event(completion_id, false, cx);
 7572        }
 7573
 7574        if let Some(provider) = self.edit_prediction_provider() {
 7575            provider.discard(cx);
 7576        }
 7577
 7578        self.take_active_edit_prediction(cx)
 7579    }
 7580
 7581    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7582        let Some(provider) = self.edit_prediction_provider() else {
 7583            return;
 7584        };
 7585
 7586        let Some((_, buffer, _)) = self
 7587            .buffer
 7588            .read(cx)
 7589            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7590        else {
 7591            return;
 7592        };
 7593
 7594        let extension = buffer
 7595            .read(cx)
 7596            .file()
 7597            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7598
 7599        let event_type = match accepted {
 7600            true => "Edit Prediction Accepted",
 7601            false => "Edit Prediction Discarded",
 7602        };
 7603        telemetry::event!(
 7604            event_type,
 7605            provider = provider.name(),
 7606            prediction_id = id,
 7607            suggestion_accepted = accepted,
 7608            file_extension = extension,
 7609        );
 7610    }
 7611
 7612    pub fn has_active_edit_prediction(&self) -> bool {
 7613        self.active_edit_prediction.is_some()
 7614    }
 7615
 7616    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7617        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7618            return false;
 7619        };
 7620
 7621        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7622        self.clear_highlights::<EditPredictionHighlight>(cx);
 7623        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7624        true
 7625    }
 7626
 7627    /// Returns true when we're displaying the edit prediction popover below the cursor
 7628    /// like we are not previewing and the LSP autocomplete menu is visible
 7629    /// or we are in `when_holding_modifier` mode.
 7630    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7631        if self.edit_prediction_preview_is_active()
 7632            || !self.show_edit_predictions_in_menu()
 7633            || !self.edit_predictions_enabled()
 7634        {
 7635            return false;
 7636        }
 7637
 7638        if self.has_visible_completions_menu() {
 7639            return true;
 7640        }
 7641
 7642        has_completion && self.edit_prediction_requires_modifier()
 7643    }
 7644
 7645    fn handle_modifiers_changed(
 7646        &mut self,
 7647        modifiers: Modifiers,
 7648        position_map: &PositionMap,
 7649        window: &mut Window,
 7650        cx: &mut Context<Self>,
 7651    ) {
 7652        if self.show_edit_predictions_in_menu() {
 7653            self.update_edit_prediction_preview(&modifiers, window, cx);
 7654        }
 7655
 7656        self.update_selection_mode(&modifiers, position_map, window, cx);
 7657
 7658        let mouse_position = window.mouse_position();
 7659        if !position_map.text_hitbox.is_hovered(window) {
 7660            return;
 7661        }
 7662
 7663        self.update_hovered_link(
 7664            position_map.point_for_position(mouse_position),
 7665            &position_map.snapshot,
 7666            modifiers,
 7667            window,
 7668            cx,
 7669        )
 7670    }
 7671
 7672    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7673        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7674        if invert {
 7675            match multi_cursor_setting {
 7676                MultiCursorModifier::Alt => modifiers.alt,
 7677                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7678            }
 7679        } else {
 7680            match multi_cursor_setting {
 7681                MultiCursorModifier::Alt => modifiers.secondary(),
 7682                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7683            }
 7684        }
 7685    }
 7686
 7687    fn columnar_selection_mode(
 7688        modifiers: &Modifiers,
 7689        cx: &mut Context<Self>,
 7690    ) -> Option<ColumnarMode> {
 7691        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7692            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7693                Some(ColumnarMode::FromMouse)
 7694            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7695                Some(ColumnarMode::FromSelection)
 7696            } else {
 7697                None
 7698            }
 7699        } else {
 7700            None
 7701        }
 7702    }
 7703
 7704    fn update_selection_mode(
 7705        &mut self,
 7706        modifiers: &Modifiers,
 7707        position_map: &PositionMap,
 7708        window: &mut Window,
 7709        cx: &mut Context<Self>,
 7710    ) {
 7711        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7712            return;
 7713        };
 7714        if self.selections.pending.is_none() {
 7715            return;
 7716        }
 7717
 7718        let mouse_position = window.mouse_position();
 7719        let point_for_position = position_map.point_for_position(mouse_position);
 7720        let position = point_for_position.previous_valid;
 7721
 7722        self.select(
 7723            SelectPhase::BeginColumnar {
 7724                position,
 7725                reset: false,
 7726                mode,
 7727                goal_column: point_for_position.exact_unclipped.column(),
 7728            },
 7729            window,
 7730            cx,
 7731        );
 7732    }
 7733
 7734    fn update_edit_prediction_preview(
 7735        &mut self,
 7736        modifiers: &Modifiers,
 7737        window: &mut Window,
 7738        cx: &mut Context<Self>,
 7739    ) {
 7740        let mut modifiers_held = false;
 7741        if let Some(accept_keystroke) = self
 7742            .accept_edit_prediction_keybind(false, window, cx)
 7743            .keystroke()
 7744        {
 7745            modifiers_held = modifiers_held
 7746                || (accept_keystroke.modifiers() == modifiers
 7747                    && accept_keystroke.modifiers().modified());
 7748        };
 7749        if let Some(accept_partial_keystroke) = self
 7750            .accept_edit_prediction_keybind(true, window, cx)
 7751            .keystroke()
 7752        {
 7753            modifiers_held = modifiers_held
 7754                || (accept_partial_keystroke.modifiers() == modifiers
 7755                    && accept_partial_keystroke.modifiers().modified());
 7756        }
 7757
 7758        if modifiers_held {
 7759            if matches!(
 7760                self.edit_prediction_preview,
 7761                EditPredictionPreview::Inactive { .. }
 7762            ) {
 7763                self.edit_prediction_preview = EditPredictionPreview::Active {
 7764                    previous_scroll_position: None,
 7765                    since: Instant::now(),
 7766                };
 7767
 7768                self.update_visible_edit_prediction(window, cx);
 7769                cx.notify();
 7770            }
 7771        } else if let EditPredictionPreview::Active {
 7772            previous_scroll_position,
 7773            since,
 7774        } = self.edit_prediction_preview
 7775        {
 7776            if let (Some(previous_scroll_position), Some(position_map)) =
 7777                (previous_scroll_position, self.last_position_map.as_ref())
 7778            {
 7779                self.set_scroll_position(
 7780                    previous_scroll_position
 7781                        .scroll_position(&position_map.snapshot.display_snapshot),
 7782                    window,
 7783                    cx,
 7784                );
 7785            }
 7786
 7787            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7788                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7789            };
 7790            self.clear_row_highlights::<EditPredictionPreview>();
 7791            self.update_visible_edit_prediction(window, cx);
 7792            cx.notify();
 7793        }
 7794    }
 7795
 7796    fn update_visible_edit_prediction(
 7797        &mut self,
 7798        _window: &mut Window,
 7799        cx: &mut Context<Self>,
 7800    ) -> Option<()> {
 7801        if DisableAiSettings::get_global(cx).disable_ai {
 7802            return None;
 7803        }
 7804
 7805        if self.ime_transaction.is_some() {
 7806            self.discard_edit_prediction(false, cx);
 7807            return None;
 7808        }
 7809
 7810        let selection = self.selections.newest_anchor();
 7811        let cursor = selection.head();
 7812        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7813        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7814        let excerpt_id = cursor.excerpt_id;
 7815
 7816        let show_in_menu = self.show_edit_predictions_in_menu();
 7817        let completions_menu_has_precedence = !show_in_menu
 7818            && (self.context_menu.borrow().is_some()
 7819                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7820
 7821        if completions_menu_has_precedence
 7822            || !offset_selection.is_empty()
 7823            || self
 7824                .active_edit_prediction
 7825                .as_ref()
 7826                .is_some_and(|completion| {
 7827                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7828                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7829                    !invalidation_range.contains(&offset_selection.head())
 7830                })
 7831        {
 7832            self.discard_edit_prediction(false, cx);
 7833            return None;
 7834        }
 7835
 7836        self.take_active_edit_prediction(cx);
 7837        let Some(provider) = self.edit_prediction_provider() else {
 7838            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7839            return None;
 7840        };
 7841
 7842        let (buffer, cursor_buffer_position) =
 7843            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7844
 7845        self.edit_prediction_settings =
 7846            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7847
 7848        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7849            self.discard_edit_prediction(false, cx);
 7850            return None;
 7851        };
 7852
 7853        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7854
 7855        if self.edit_prediction_indent_conflict {
 7856            let cursor_point = cursor.to_point(&multibuffer);
 7857
 7858            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7859
 7860            if let Some((_, indent)) = indents.iter().next()
 7861                && indent.len == cursor_point.column
 7862            {
 7863                self.edit_prediction_indent_conflict = false;
 7864            }
 7865        }
 7866
 7867        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7868        let edits = edit_prediction
 7869            .edits
 7870            .into_iter()
 7871            .flat_map(|(range, new_text)| {
 7872                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7873                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7874                Some((start..end, new_text))
 7875            })
 7876            .collect::<Vec<_>>();
 7877        if edits.is_empty() {
 7878            return None;
 7879        }
 7880
 7881        let first_edit_start = edits.first().unwrap().0.start;
 7882        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7883        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7884
 7885        let last_edit_end = edits.last().unwrap().0.end;
 7886        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7887        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7888
 7889        let cursor_row = cursor.to_point(&multibuffer).row;
 7890
 7891        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7892
 7893        let mut inlay_ids = Vec::new();
 7894        let invalidation_row_range;
 7895        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7896            Some(cursor_row..edit_end_row)
 7897        } else if cursor_row > edit_end_row {
 7898            Some(edit_start_row..cursor_row)
 7899        } else {
 7900            None
 7901        };
 7902        let supports_jump = self
 7903            .edit_prediction_provider
 7904            .as_ref()
 7905            .map(|provider| provider.provider.supports_jump_to_edit())
 7906            .unwrap_or(true);
 7907
 7908        let is_move = supports_jump
 7909            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7910        let completion = if is_move {
 7911            invalidation_row_range =
 7912                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7913            let target = first_edit_start;
 7914            EditPrediction::Move { target, snapshot }
 7915        } else {
 7916            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7917                && !self.edit_predictions_hidden_for_vim_mode;
 7918
 7919            if show_completions_in_buffer {
 7920                if edits
 7921                    .iter()
 7922                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7923                {
 7924                    let mut inlays = Vec::new();
 7925                    for (range, new_text) in &edits {
 7926                        let inlay = Inlay::edit_prediction(
 7927                            post_inc(&mut self.next_inlay_id),
 7928                            range.start,
 7929                            new_text.as_str(),
 7930                        );
 7931                        inlay_ids.push(inlay.id);
 7932                        inlays.push(inlay);
 7933                    }
 7934
 7935                    self.splice_inlays(&[], inlays, cx);
 7936                } else {
 7937                    let background_color = cx.theme().status().deleted_background;
 7938                    self.highlight_text::<EditPredictionHighlight>(
 7939                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7940                        HighlightStyle {
 7941                            background_color: Some(background_color),
 7942                            ..Default::default()
 7943                        },
 7944                        cx,
 7945                    );
 7946                }
 7947            }
 7948
 7949            invalidation_row_range = edit_start_row..edit_end_row;
 7950
 7951            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7952                if provider.show_tab_accept_marker() {
 7953                    EditDisplayMode::TabAccept
 7954                } else {
 7955                    EditDisplayMode::Inline
 7956                }
 7957            } else {
 7958                EditDisplayMode::DiffPopover
 7959            };
 7960
 7961            EditPrediction::Edit {
 7962                edits,
 7963                edit_preview: edit_prediction.edit_preview,
 7964                display_mode,
 7965                snapshot,
 7966            }
 7967        };
 7968
 7969        let invalidation_range = multibuffer
 7970            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7971            ..multibuffer.anchor_after(Point::new(
 7972                invalidation_row_range.end,
 7973                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7974            ));
 7975
 7976        self.stale_edit_prediction_in_menu = None;
 7977        self.active_edit_prediction = Some(EditPredictionState {
 7978            inlay_ids,
 7979            completion,
 7980            completion_id: edit_prediction.id,
 7981            invalidation_range,
 7982        });
 7983
 7984        cx.notify();
 7985
 7986        Some(())
 7987    }
 7988
 7989    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7990        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7991    }
 7992
 7993    fn clear_tasks(&mut self) {
 7994        self.tasks.clear()
 7995    }
 7996
 7997    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7998        if self.tasks.insert(key, value).is_some() {
 7999            // This case should hopefully be rare, but just in case...
 8000            log::error!(
 8001                "multiple different run targets found on a single line, only the last target will be rendered"
 8002            )
 8003        }
 8004    }
 8005
 8006    /// Get all display points of breakpoints that will be rendered within editor
 8007    ///
 8008    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8009    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8010    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8011    fn active_breakpoints(
 8012        &self,
 8013        range: Range<DisplayRow>,
 8014        window: &mut Window,
 8015        cx: &mut Context<Self>,
 8016    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8017        let mut breakpoint_display_points = HashMap::default();
 8018
 8019        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8020            return breakpoint_display_points;
 8021        };
 8022
 8023        let snapshot = self.snapshot(window, cx);
 8024
 8025        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8026        let Some(project) = self.project() else {
 8027            return breakpoint_display_points;
 8028        };
 8029
 8030        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8031            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8032
 8033        for (buffer_snapshot, range, excerpt_id) in
 8034            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8035        {
 8036            let Some(buffer) = project
 8037                .read(cx)
 8038                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8039            else {
 8040                continue;
 8041            };
 8042            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8043                &buffer,
 8044                Some(
 8045                    buffer_snapshot.anchor_before(range.start)
 8046                        ..buffer_snapshot.anchor_after(range.end),
 8047                ),
 8048                buffer_snapshot,
 8049                cx,
 8050            );
 8051            for (breakpoint, state) in breakpoints {
 8052                let multi_buffer_anchor =
 8053                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8054                let position = multi_buffer_anchor
 8055                    .to_point(multi_buffer_snapshot)
 8056                    .to_display_point(&snapshot);
 8057
 8058                breakpoint_display_points.insert(
 8059                    position.row(),
 8060                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8061                );
 8062            }
 8063        }
 8064
 8065        breakpoint_display_points
 8066    }
 8067
 8068    fn breakpoint_context_menu(
 8069        &self,
 8070        anchor: Anchor,
 8071        window: &mut Window,
 8072        cx: &mut Context<Self>,
 8073    ) -> Entity<ui::ContextMenu> {
 8074        let weak_editor = cx.weak_entity();
 8075        let focus_handle = self.focus_handle(cx);
 8076
 8077        let row = self
 8078            .buffer
 8079            .read(cx)
 8080            .snapshot(cx)
 8081            .summary_for_anchor::<Point>(&anchor)
 8082            .row;
 8083
 8084        let breakpoint = self
 8085            .breakpoint_at_row(row, window, cx)
 8086            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8087
 8088        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8089            "Edit Log Breakpoint"
 8090        } else {
 8091            "Set Log Breakpoint"
 8092        };
 8093
 8094        let condition_breakpoint_msg = if breakpoint
 8095            .as_ref()
 8096            .is_some_and(|bp| bp.1.condition.is_some())
 8097        {
 8098            "Edit Condition Breakpoint"
 8099        } else {
 8100            "Set Condition Breakpoint"
 8101        };
 8102
 8103        let hit_condition_breakpoint_msg = if breakpoint
 8104            .as_ref()
 8105            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8106        {
 8107            "Edit Hit Condition Breakpoint"
 8108        } else {
 8109            "Set Hit Condition Breakpoint"
 8110        };
 8111
 8112        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8113            "Unset Breakpoint"
 8114        } else {
 8115            "Set Breakpoint"
 8116        };
 8117
 8118        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8119
 8120        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8121            BreakpointState::Enabled => Some("Disable"),
 8122            BreakpointState::Disabled => Some("Enable"),
 8123        });
 8124
 8125        let (anchor, breakpoint) =
 8126            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8127
 8128        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8129            menu.on_blur_subscription(Subscription::new(|| {}))
 8130                .context(focus_handle)
 8131                .when(run_to_cursor, |this| {
 8132                    let weak_editor = weak_editor.clone();
 8133                    this.entry("Run to cursor", None, move |window, cx| {
 8134                        weak_editor
 8135                            .update(cx, |editor, cx| {
 8136                                editor.change_selections(
 8137                                    SelectionEffects::no_scroll(),
 8138                                    window,
 8139                                    cx,
 8140                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8141                                );
 8142                            })
 8143                            .ok();
 8144
 8145                        window.dispatch_action(Box::new(RunToCursor), cx);
 8146                    })
 8147                    .separator()
 8148                })
 8149                .when_some(toggle_state_msg, |this, msg| {
 8150                    this.entry(msg, None, {
 8151                        let weak_editor = weak_editor.clone();
 8152                        let breakpoint = breakpoint.clone();
 8153                        move |_window, cx| {
 8154                            weak_editor
 8155                                .update(cx, |this, cx| {
 8156                                    this.edit_breakpoint_at_anchor(
 8157                                        anchor,
 8158                                        breakpoint.as_ref().clone(),
 8159                                        BreakpointEditAction::InvertState,
 8160                                        cx,
 8161                                    );
 8162                                })
 8163                                .log_err();
 8164                        }
 8165                    })
 8166                })
 8167                .entry(set_breakpoint_msg, None, {
 8168                    let weak_editor = weak_editor.clone();
 8169                    let breakpoint = breakpoint.clone();
 8170                    move |_window, cx| {
 8171                        weak_editor
 8172                            .update(cx, |this, cx| {
 8173                                this.edit_breakpoint_at_anchor(
 8174                                    anchor,
 8175                                    breakpoint.as_ref().clone(),
 8176                                    BreakpointEditAction::Toggle,
 8177                                    cx,
 8178                                );
 8179                            })
 8180                            .log_err();
 8181                    }
 8182                })
 8183                .entry(log_breakpoint_msg, None, {
 8184                    let breakpoint = breakpoint.clone();
 8185                    let weak_editor = weak_editor.clone();
 8186                    move |window, cx| {
 8187                        weak_editor
 8188                            .update(cx, |this, cx| {
 8189                                this.add_edit_breakpoint_block(
 8190                                    anchor,
 8191                                    breakpoint.as_ref(),
 8192                                    BreakpointPromptEditAction::Log,
 8193                                    window,
 8194                                    cx,
 8195                                );
 8196                            })
 8197                            .log_err();
 8198                    }
 8199                })
 8200                .entry(condition_breakpoint_msg, None, {
 8201                    let breakpoint = breakpoint.clone();
 8202                    let weak_editor = weak_editor.clone();
 8203                    move |window, cx| {
 8204                        weak_editor
 8205                            .update(cx, |this, cx| {
 8206                                this.add_edit_breakpoint_block(
 8207                                    anchor,
 8208                                    breakpoint.as_ref(),
 8209                                    BreakpointPromptEditAction::Condition,
 8210                                    window,
 8211                                    cx,
 8212                                );
 8213                            })
 8214                            .log_err();
 8215                    }
 8216                })
 8217                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8218                    weak_editor
 8219                        .update(cx, |this, cx| {
 8220                            this.add_edit_breakpoint_block(
 8221                                anchor,
 8222                                breakpoint.as_ref(),
 8223                                BreakpointPromptEditAction::HitCondition,
 8224                                window,
 8225                                cx,
 8226                            );
 8227                        })
 8228                        .log_err();
 8229                })
 8230        })
 8231    }
 8232
 8233    fn render_breakpoint(
 8234        &self,
 8235        position: Anchor,
 8236        row: DisplayRow,
 8237        breakpoint: &Breakpoint,
 8238        state: Option<BreakpointSessionState>,
 8239        cx: &mut Context<Self>,
 8240    ) -> IconButton {
 8241        let is_rejected = state.is_some_and(|s| !s.verified);
 8242        // Is it a breakpoint that shows up when hovering over gutter?
 8243        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8244            (false, false),
 8245            |PhantomBreakpointIndicator {
 8246                 is_active,
 8247                 display_row,
 8248                 collides_with_existing_breakpoint,
 8249             }| {
 8250                (
 8251                    is_active && display_row == row,
 8252                    collides_with_existing_breakpoint,
 8253                )
 8254            },
 8255        );
 8256
 8257        let (color, icon) = {
 8258            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8259                (false, false) => ui::IconName::DebugBreakpoint,
 8260                (true, false) => ui::IconName::DebugLogBreakpoint,
 8261                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8262                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8263            };
 8264
 8265            let color = if is_phantom {
 8266                Color::Hint
 8267            } else if is_rejected {
 8268                Color::Disabled
 8269            } else {
 8270                Color::Debugger
 8271            };
 8272
 8273            (color, icon)
 8274        };
 8275
 8276        let breakpoint = Arc::from(breakpoint.clone());
 8277
 8278        let alt_as_text = gpui::Keystroke {
 8279            modifiers: Modifiers::secondary_key(),
 8280            ..Default::default()
 8281        };
 8282        let primary_action_text = if breakpoint.is_disabled() {
 8283            "Enable breakpoint"
 8284        } else if is_phantom && !collides_with_existing {
 8285            "Set breakpoint"
 8286        } else {
 8287            "Unset breakpoint"
 8288        };
 8289        let focus_handle = self.focus_handle.clone();
 8290
 8291        let meta = if is_rejected {
 8292            SharedString::from("No executable code is associated with this line.")
 8293        } else if collides_with_existing && !breakpoint.is_disabled() {
 8294            SharedString::from(format!(
 8295                "{alt_as_text}-click to disable,\nright-click for more options."
 8296            ))
 8297        } else {
 8298            SharedString::from("Right-click for more options.")
 8299        };
 8300        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8301            .icon_size(IconSize::XSmall)
 8302            .size(ui::ButtonSize::None)
 8303            .when(is_rejected, |this| {
 8304                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8305            })
 8306            .icon_color(color)
 8307            .style(ButtonStyle::Transparent)
 8308            .on_click(cx.listener({
 8309                move |editor, event: &ClickEvent, window, cx| {
 8310                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8311                        BreakpointEditAction::InvertState
 8312                    } else {
 8313                        BreakpointEditAction::Toggle
 8314                    };
 8315
 8316                    window.focus(&editor.focus_handle(cx));
 8317                    editor.edit_breakpoint_at_anchor(
 8318                        position,
 8319                        breakpoint.as_ref().clone(),
 8320                        edit_action,
 8321                        cx,
 8322                    );
 8323                }
 8324            }))
 8325            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8326                editor.set_breakpoint_context_menu(
 8327                    row,
 8328                    Some(position),
 8329                    event.position(),
 8330                    window,
 8331                    cx,
 8332                );
 8333            }))
 8334            .tooltip(move |window, cx| {
 8335                Tooltip::with_meta_in(
 8336                    primary_action_text,
 8337                    Some(&ToggleBreakpoint),
 8338                    meta.clone(),
 8339                    &focus_handle,
 8340                    window,
 8341                    cx,
 8342                )
 8343            })
 8344    }
 8345
 8346    fn build_tasks_context(
 8347        project: &Entity<Project>,
 8348        buffer: &Entity<Buffer>,
 8349        buffer_row: u32,
 8350        tasks: &Arc<RunnableTasks>,
 8351        cx: &mut Context<Self>,
 8352    ) -> Task<Option<task::TaskContext>> {
 8353        let position = Point::new(buffer_row, tasks.column);
 8354        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8355        let location = Location {
 8356            buffer: buffer.clone(),
 8357            range: range_start..range_start,
 8358        };
 8359        // Fill in the environmental variables from the tree-sitter captures
 8360        let mut captured_task_variables = TaskVariables::default();
 8361        for (capture_name, value) in tasks.extra_variables.clone() {
 8362            captured_task_variables.insert(
 8363                task::VariableName::Custom(capture_name.into()),
 8364                value.clone(),
 8365            );
 8366        }
 8367        project.update(cx, |project, cx| {
 8368            project.task_store().update(cx, |task_store, cx| {
 8369                task_store.task_context_for_location(captured_task_variables, location, cx)
 8370            })
 8371        })
 8372    }
 8373
 8374    pub fn spawn_nearest_task(
 8375        &mut self,
 8376        action: &SpawnNearestTask,
 8377        window: &mut Window,
 8378        cx: &mut Context<Self>,
 8379    ) {
 8380        let Some((workspace, _)) = self.workspace.clone() else {
 8381            return;
 8382        };
 8383        let Some(project) = self.project.clone() else {
 8384            return;
 8385        };
 8386
 8387        // Try to find a closest, enclosing node using tree-sitter that has a task
 8388        let Some((buffer, buffer_row, tasks)) = self
 8389            .find_enclosing_node_task(cx)
 8390            // Or find the task that's closest in row-distance.
 8391            .or_else(|| self.find_closest_task(cx))
 8392        else {
 8393            return;
 8394        };
 8395
 8396        let reveal_strategy = action.reveal;
 8397        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8398        cx.spawn_in(window, async move |_, cx| {
 8399            let context = task_context.await?;
 8400            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8401
 8402            let resolved = &mut resolved_task.resolved;
 8403            resolved.reveal = reveal_strategy;
 8404
 8405            workspace
 8406                .update_in(cx, |workspace, window, cx| {
 8407                    workspace.schedule_resolved_task(
 8408                        task_source_kind,
 8409                        resolved_task,
 8410                        false,
 8411                        window,
 8412                        cx,
 8413                    );
 8414                })
 8415                .ok()
 8416        })
 8417        .detach();
 8418    }
 8419
 8420    fn find_closest_task(
 8421        &mut self,
 8422        cx: &mut Context<Self>,
 8423    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8424        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8425
 8426        let ((buffer_id, row), tasks) = self
 8427            .tasks
 8428            .iter()
 8429            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8430
 8431        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8432        let tasks = Arc::new(tasks.to_owned());
 8433        Some((buffer, *row, tasks))
 8434    }
 8435
 8436    fn find_enclosing_node_task(
 8437        &mut self,
 8438        cx: &mut Context<Self>,
 8439    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8440        let snapshot = self.buffer.read(cx).snapshot(cx);
 8441        let offset = self.selections.newest::<usize>(cx).head();
 8442        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8443        let buffer_id = excerpt.buffer().remote_id();
 8444
 8445        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8446        let mut cursor = layer.node().walk();
 8447
 8448        while cursor.goto_first_child_for_byte(offset).is_some() {
 8449            if cursor.node().end_byte() == offset {
 8450                cursor.goto_next_sibling();
 8451            }
 8452        }
 8453
 8454        // Ascend to the smallest ancestor that contains the range and has a task.
 8455        loop {
 8456            let node = cursor.node();
 8457            let node_range = node.byte_range();
 8458            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8459
 8460            // Check if this node contains our offset
 8461            if node_range.start <= offset && node_range.end >= offset {
 8462                // If it contains offset, check for task
 8463                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8464                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8465                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8466                }
 8467            }
 8468
 8469            if !cursor.goto_parent() {
 8470                break;
 8471            }
 8472        }
 8473        None
 8474    }
 8475
 8476    fn render_run_indicator(
 8477        &self,
 8478        _style: &EditorStyle,
 8479        is_active: bool,
 8480        row: DisplayRow,
 8481        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8482        cx: &mut Context<Self>,
 8483    ) -> IconButton {
 8484        let color = Color::Muted;
 8485        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8486
 8487        IconButton::new(
 8488            ("run_indicator", row.0 as usize),
 8489            ui::IconName::PlayOutlined,
 8490        )
 8491        .shape(ui::IconButtonShape::Square)
 8492        .icon_size(IconSize::XSmall)
 8493        .icon_color(color)
 8494        .toggle_state(is_active)
 8495        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8496            let quick_launch = match e {
 8497                ClickEvent::Keyboard(_) => true,
 8498                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8499            };
 8500
 8501            window.focus(&editor.focus_handle(cx));
 8502            editor.toggle_code_actions(
 8503                &ToggleCodeActions {
 8504                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8505                    quick_launch,
 8506                },
 8507                window,
 8508                cx,
 8509            );
 8510        }))
 8511        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8512            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8513        }))
 8514    }
 8515
 8516    pub fn context_menu_visible(&self) -> bool {
 8517        !self.edit_prediction_preview_is_active()
 8518            && self
 8519                .context_menu
 8520                .borrow()
 8521                .as_ref()
 8522                .is_some_and(|menu| menu.visible())
 8523    }
 8524
 8525    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8526        self.context_menu
 8527            .borrow()
 8528            .as_ref()
 8529            .map(|menu| menu.origin())
 8530    }
 8531
 8532    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8533        self.context_menu_options = Some(options);
 8534    }
 8535
 8536    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8537    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8538
 8539    fn render_edit_prediction_popover(
 8540        &mut self,
 8541        text_bounds: &Bounds<Pixels>,
 8542        content_origin: gpui::Point<Pixels>,
 8543        right_margin: Pixels,
 8544        editor_snapshot: &EditorSnapshot,
 8545        visible_row_range: Range<DisplayRow>,
 8546        scroll_top: f32,
 8547        scroll_bottom: f32,
 8548        line_layouts: &[LineWithInvisibles],
 8549        line_height: Pixels,
 8550        scroll_pixel_position: gpui::Point<Pixels>,
 8551        newest_selection_head: Option<DisplayPoint>,
 8552        editor_width: Pixels,
 8553        style: &EditorStyle,
 8554        window: &mut Window,
 8555        cx: &mut App,
 8556    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8557        if self.mode().is_minimap() {
 8558            return None;
 8559        }
 8560        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8561
 8562        if self.edit_prediction_visible_in_cursor_popover(true) {
 8563            return None;
 8564        }
 8565
 8566        match &active_edit_prediction.completion {
 8567            EditPrediction::Move { target, .. } => {
 8568                let target_display_point = target.to_display_point(editor_snapshot);
 8569
 8570                if self.edit_prediction_requires_modifier() {
 8571                    if !self.edit_prediction_preview_is_active() {
 8572                        return None;
 8573                    }
 8574
 8575                    self.render_edit_prediction_modifier_jump_popover(
 8576                        text_bounds,
 8577                        content_origin,
 8578                        visible_row_range,
 8579                        line_layouts,
 8580                        line_height,
 8581                        scroll_pixel_position,
 8582                        newest_selection_head,
 8583                        target_display_point,
 8584                        window,
 8585                        cx,
 8586                    )
 8587                } else {
 8588                    self.render_edit_prediction_eager_jump_popover(
 8589                        text_bounds,
 8590                        content_origin,
 8591                        editor_snapshot,
 8592                        visible_row_range,
 8593                        scroll_top,
 8594                        scroll_bottom,
 8595                        line_height,
 8596                        scroll_pixel_position,
 8597                        target_display_point,
 8598                        editor_width,
 8599                        window,
 8600                        cx,
 8601                    )
 8602                }
 8603            }
 8604            EditPrediction::Edit {
 8605                display_mode: EditDisplayMode::Inline,
 8606                ..
 8607            } => None,
 8608            EditPrediction::Edit {
 8609                display_mode: EditDisplayMode::TabAccept,
 8610                edits,
 8611                ..
 8612            } => {
 8613                let range = &edits.first()?.0;
 8614                let target_display_point = range.end.to_display_point(editor_snapshot);
 8615
 8616                self.render_edit_prediction_end_of_line_popover(
 8617                    "Accept",
 8618                    editor_snapshot,
 8619                    visible_row_range,
 8620                    target_display_point,
 8621                    line_height,
 8622                    scroll_pixel_position,
 8623                    content_origin,
 8624                    editor_width,
 8625                    window,
 8626                    cx,
 8627                )
 8628            }
 8629            EditPrediction::Edit {
 8630                edits,
 8631                edit_preview,
 8632                display_mode: EditDisplayMode::DiffPopover,
 8633                snapshot,
 8634            } => self.render_edit_prediction_diff_popover(
 8635                text_bounds,
 8636                content_origin,
 8637                right_margin,
 8638                editor_snapshot,
 8639                visible_row_range,
 8640                line_layouts,
 8641                line_height,
 8642                scroll_pixel_position,
 8643                newest_selection_head,
 8644                editor_width,
 8645                style,
 8646                edits,
 8647                edit_preview,
 8648                snapshot,
 8649                window,
 8650                cx,
 8651            ),
 8652        }
 8653    }
 8654
 8655    fn render_edit_prediction_modifier_jump_popover(
 8656        &mut self,
 8657        text_bounds: &Bounds<Pixels>,
 8658        content_origin: gpui::Point<Pixels>,
 8659        visible_row_range: Range<DisplayRow>,
 8660        line_layouts: &[LineWithInvisibles],
 8661        line_height: Pixels,
 8662        scroll_pixel_position: gpui::Point<Pixels>,
 8663        newest_selection_head: Option<DisplayPoint>,
 8664        target_display_point: DisplayPoint,
 8665        window: &mut Window,
 8666        cx: &mut App,
 8667    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8668        let scrolled_content_origin =
 8669            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8670
 8671        const SCROLL_PADDING_Y: Pixels = px(12.);
 8672
 8673        if target_display_point.row() < visible_row_range.start {
 8674            return self.render_edit_prediction_scroll_popover(
 8675                |_| SCROLL_PADDING_Y,
 8676                IconName::ArrowUp,
 8677                visible_row_range,
 8678                line_layouts,
 8679                newest_selection_head,
 8680                scrolled_content_origin,
 8681                window,
 8682                cx,
 8683            );
 8684        } else if target_display_point.row() >= visible_row_range.end {
 8685            return self.render_edit_prediction_scroll_popover(
 8686                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8687                IconName::ArrowDown,
 8688                visible_row_range,
 8689                line_layouts,
 8690                newest_selection_head,
 8691                scrolled_content_origin,
 8692                window,
 8693                cx,
 8694            );
 8695        }
 8696
 8697        const POLE_WIDTH: Pixels = px(2.);
 8698
 8699        let line_layout =
 8700            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8701        let target_column = target_display_point.column() as usize;
 8702
 8703        let target_x = line_layout.x_for_index(target_column);
 8704        let target_y =
 8705            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8706
 8707        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8708
 8709        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8710        border_color.l += 0.001;
 8711
 8712        let mut element = v_flex()
 8713            .items_end()
 8714            .when(flag_on_right, |el| el.items_start())
 8715            .child(if flag_on_right {
 8716                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8717                    .rounded_bl(px(0.))
 8718                    .rounded_tl(px(0.))
 8719                    .border_l_2()
 8720                    .border_color(border_color)
 8721            } else {
 8722                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8723                    .rounded_br(px(0.))
 8724                    .rounded_tr(px(0.))
 8725                    .border_r_2()
 8726                    .border_color(border_color)
 8727            })
 8728            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8729            .into_any();
 8730
 8731        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8732
 8733        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8734            - point(
 8735                if flag_on_right {
 8736                    POLE_WIDTH
 8737                } else {
 8738                    size.width - POLE_WIDTH
 8739                },
 8740                size.height - line_height,
 8741            );
 8742
 8743        origin.x = origin.x.max(content_origin.x);
 8744
 8745        element.prepaint_at(origin, window, cx);
 8746
 8747        Some((element, origin))
 8748    }
 8749
 8750    fn render_edit_prediction_scroll_popover(
 8751        &mut self,
 8752        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8753        scroll_icon: IconName,
 8754        visible_row_range: Range<DisplayRow>,
 8755        line_layouts: &[LineWithInvisibles],
 8756        newest_selection_head: Option<DisplayPoint>,
 8757        scrolled_content_origin: gpui::Point<Pixels>,
 8758        window: &mut Window,
 8759        cx: &mut App,
 8760    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8761        let mut element = self
 8762            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8763            .into_any();
 8764
 8765        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8766
 8767        let cursor = newest_selection_head?;
 8768        let cursor_row_layout =
 8769            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8770        let cursor_column = cursor.column() as usize;
 8771
 8772        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8773
 8774        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8775
 8776        element.prepaint_at(origin, window, cx);
 8777        Some((element, origin))
 8778    }
 8779
 8780    fn render_edit_prediction_eager_jump_popover(
 8781        &mut self,
 8782        text_bounds: &Bounds<Pixels>,
 8783        content_origin: gpui::Point<Pixels>,
 8784        editor_snapshot: &EditorSnapshot,
 8785        visible_row_range: Range<DisplayRow>,
 8786        scroll_top: f32,
 8787        scroll_bottom: f32,
 8788        line_height: Pixels,
 8789        scroll_pixel_position: gpui::Point<Pixels>,
 8790        target_display_point: DisplayPoint,
 8791        editor_width: Pixels,
 8792        window: &mut Window,
 8793        cx: &mut App,
 8794    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8795        if target_display_point.row().as_f32() < scroll_top {
 8796            let mut element = self
 8797                .render_edit_prediction_line_popover(
 8798                    "Jump to Edit",
 8799                    Some(IconName::ArrowUp),
 8800                    window,
 8801                    cx,
 8802                )?
 8803                .into_any();
 8804
 8805            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8806            let offset = point(
 8807                (text_bounds.size.width - size.width) / 2.,
 8808                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8809            );
 8810
 8811            let origin = text_bounds.origin + offset;
 8812            element.prepaint_at(origin, window, cx);
 8813            Some((element, origin))
 8814        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8815            let mut element = self
 8816                .render_edit_prediction_line_popover(
 8817                    "Jump to Edit",
 8818                    Some(IconName::ArrowDown),
 8819                    window,
 8820                    cx,
 8821                )?
 8822                .into_any();
 8823
 8824            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8825            let offset = point(
 8826                (text_bounds.size.width - size.width) / 2.,
 8827                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8828            );
 8829
 8830            let origin = text_bounds.origin + offset;
 8831            element.prepaint_at(origin, window, cx);
 8832            Some((element, origin))
 8833        } else {
 8834            self.render_edit_prediction_end_of_line_popover(
 8835                "Jump to Edit",
 8836                editor_snapshot,
 8837                visible_row_range,
 8838                target_display_point,
 8839                line_height,
 8840                scroll_pixel_position,
 8841                content_origin,
 8842                editor_width,
 8843                window,
 8844                cx,
 8845            )
 8846        }
 8847    }
 8848
 8849    fn render_edit_prediction_end_of_line_popover(
 8850        self: &mut Editor,
 8851        label: &'static str,
 8852        editor_snapshot: &EditorSnapshot,
 8853        visible_row_range: Range<DisplayRow>,
 8854        target_display_point: DisplayPoint,
 8855        line_height: Pixels,
 8856        scroll_pixel_position: gpui::Point<Pixels>,
 8857        content_origin: gpui::Point<Pixels>,
 8858        editor_width: Pixels,
 8859        window: &mut Window,
 8860        cx: &mut App,
 8861    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8862        let target_line_end = DisplayPoint::new(
 8863            target_display_point.row(),
 8864            editor_snapshot.line_len(target_display_point.row()),
 8865        );
 8866
 8867        let mut element = self
 8868            .render_edit_prediction_line_popover(label, None, window, cx)?
 8869            .into_any();
 8870
 8871        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8872
 8873        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8874
 8875        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8876        let mut origin = start_point
 8877            + line_origin
 8878            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8879        origin.x = origin.x.max(content_origin.x);
 8880
 8881        let max_x = content_origin.x + editor_width - size.width;
 8882
 8883        if origin.x > max_x {
 8884            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8885
 8886            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8887                origin.y += offset;
 8888                IconName::ArrowUp
 8889            } else {
 8890                origin.y -= offset;
 8891                IconName::ArrowDown
 8892            };
 8893
 8894            element = self
 8895                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8896                .into_any();
 8897
 8898            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8899
 8900            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8901        }
 8902
 8903        element.prepaint_at(origin, window, cx);
 8904        Some((element, origin))
 8905    }
 8906
 8907    fn render_edit_prediction_diff_popover(
 8908        self: &Editor,
 8909        text_bounds: &Bounds<Pixels>,
 8910        content_origin: gpui::Point<Pixels>,
 8911        right_margin: Pixels,
 8912        editor_snapshot: &EditorSnapshot,
 8913        visible_row_range: Range<DisplayRow>,
 8914        line_layouts: &[LineWithInvisibles],
 8915        line_height: Pixels,
 8916        scroll_pixel_position: gpui::Point<Pixels>,
 8917        newest_selection_head: Option<DisplayPoint>,
 8918        editor_width: Pixels,
 8919        style: &EditorStyle,
 8920        edits: &Vec<(Range<Anchor>, String)>,
 8921        edit_preview: &Option<language::EditPreview>,
 8922        snapshot: &language::BufferSnapshot,
 8923        window: &mut Window,
 8924        cx: &mut App,
 8925    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8926        let edit_start = edits
 8927            .first()
 8928            .unwrap()
 8929            .0
 8930            .start
 8931            .to_display_point(editor_snapshot);
 8932        let edit_end = edits
 8933            .last()
 8934            .unwrap()
 8935            .0
 8936            .end
 8937            .to_display_point(editor_snapshot);
 8938
 8939        let is_visible = visible_row_range.contains(&edit_start.row())
 8940            || visible_row_range.contains(&edit_end.row());
 8941        if !is_visible {
 8942            return None;
 8943        }
 8944
 8945        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8946            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8947        } else {
 8948            // Fallback for providers without edit_preview
 8949            crate::edit_prediction_fallback_text(edits, cx)
 8950        };
 8951
 8952        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8953        let line_count = highlighted_edits.text.lines().count();
 8954
 8955        const BORDER_WIDTH: Pixels = px(1.);
 8956
 8957        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8958        let has_keybind = keybind.is_some();
 8959
 8960        let mut element = h_flex()
 8961            .items_start()
 8962            .child(
 8963                h_flex()
 8964                    .bg(cx.theme().colors().editor_background)
 8965                    .border(BORDER_WIDTH)
 8966                    .shadow_xs()
 8967                    .border_color(cx.theme().colors().border)
 8968                    .rounded_l_lg()
 8969                    .when(line_count > 1, |el| el.rounded_br_lg())
 8970                    .pr_1()
 8971                    .child(styled_text),
 8972            )
 8973            .child(
 8974                h_flex()
 8975                    .h(line_height + BORDER_WIDTH * 2.)
 8976                    .px_1p5()
 8977                    .gap_1()
 8978                    // Workaround: For some reason, there's a gap if we don't do this
 8979                    .ml(-BORDER_WIDTH)
 8980                    .shadow(vec![gpui::BoxShadow {
 8981                        color: gpui::black().opacity(0.05),
 8982                        offset: point(px(1.), px(1.)),
 8983                        blur_radius: px(2.),
 8984                        spread_radius: px(0.),
 8985                    }])
 8986                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8987                    .border(BORDER_WIDTH)
 8988                    .border_color(cx.theme().colors().border)
 8989                    .rounded_r_lg()
 8990                    .id("edit_prediction_diff_popover_keybind")
 8991                    .when(!has_keybind, |el| {
 8992                        let status_colors = cx.theme().status();
 8993
 8994                        el.bg(status_colors.error_background)
 8995                            .border_color(status_colors.error.opacity(0.6))
 8996                            .child(Icon::new(IconName::Info).color(Color::Error))
 8997                            .cursor_default()
 8998                            .hoverable_tooltip(move |_window, cx| {
 8999                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9000                            })
 9001                    })
 9002                    .children(keybind),
 9003            )
 9004            .into_any();
 9005
 9006        let longest_row =
 9007            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9008        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9009            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9010        } else {
 9011            layout_line(
 9012                longest_row,
 9013                editor_snapshot,
 9014                style,
 9015                editor_width,
 9016                |_| false,
 9017                window,
 9018                cx,
 9019            )
 9020            .width
 9021        };
 9022
 9023        let viewport_bounds =
 9024            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9025                right: -right_margin,
 9026                ..Default::default()
 9027            });
 9028
 9029        let x_after_longest =
 9030            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9031                - scroll_pixel_position.x;
 9032
 9033        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9034
 9035        // Fully visible if it can be displayed within the window (allow overlapping other
 9036        // panes). However, this is only allowed if the popover starts within text_bounds.
 9037        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9038            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9039
 9040        let mut origin = if can_position_to_the_right {
 9041            point(
 9042                x_after_longest,
 9043                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9044                    - scroll_pixel_position.y,
 9045            )
 9046        } else {
 9047            let cursor_row = newest_selection_head.map(|head| head.row());
 9048            let above_edit = edit_start
 9049                .row()
 9050                .0
 9051                .checked_sub(line_count as u32)
 9052                .map(DisplayRow);
 9053            let below_edit = Some(edit_end.row() + 1);
 9054            let above_cursor =
 9055                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9056            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9057
 9058            // Place the edit popover adjacent to the edit if there is a location
 9059            // available that is onscreen and does not obscure the cursor. Otherwise,
 9060            // place it adjacent to the cursor.
 9061            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9062                .into_iter()
 9063                .flatten()
 9064                .find(|&start_row| {
 9065                    let end_row = start_row + line_count as u32;
 9066                    visible_row_range.contains(&start_row)
 9067                        && visible_row_range.contains(&end_row)
 9068                        && cursor_row
 9069                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9070                })?;
 9071
 9072            content_origin
 9073                + point(
 9074                    -scroll_pixel_position.x,
 9075                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9076                )
 9077        };
 9078
 9079        origin.x -= BORDER_WIDTH;
 9080
 9081        window.defer_draw(element, origin, 1);
 9082
 9083        // Do not return an element, since it will already be drawn due to defer_draw.
 9084        None
 9085    }
 9086
 9087    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9088        px(30.)
 9089    }
 9090
 9091    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9092        if self.read_only(cx) {
 9093            cx.theme().players().read_only()
 9094        } else {
 9095            self.style.as_ref().unwrap().local_player
 9096        }
 9097    }
 9098
 9099    fn render_edit_prediction_accept_keybind(
 9100        &self,
 9101        window: &mut Window,
 9102        cx: &App,
 9103    ) -> Option<AnyElement> {
 9104        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9105        let accept_keystroke = accept_binding.keystroke()?;
 9106
 9107        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9108
 9109        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9110            Color::Accent
 9111        } else {
 9112            Color::Muted
 9113        };
 9114
 9115        h_flex()
 9116            .px_0p5()
 9117            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9118            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9119            .text_size(TextSize::XSmall.rems(cx))
 9120            .child(h_flex().children(ui::render_modifiers(
 9121                accept_keystroke.modifiers(),
 9122                PlatformStyle::platform(),
 9123                Some(modifiers_color),
 9124                Some(IconSize::XSmall.rems().into()),
 9125                true,
 9126            )))
 9127            .when(is_platform_style_mac, |parent| {
 9128                parent.child(accept_keystroke.key().to_string())
 9129            })
 9130            .when(!is_platform_style_mac, |parent| {
 9131                parent.child(
 9132                    Key::new(
 9133                        util::capitalize(accept_keystroke.key()),
 9134                        Some(Color::Default),
 9135                    )
 9136                    .size(Some(IconSize::XSmall.rems().into())),
 9137                )
 9138            })
 9139            .into_any()
 9140            .into()
 9141    }
 9142
 9143    fn render_edit_prediction_line_popover(
 9144        &self,
 9145        label: impl Into<SharedString>,
 9146        icon: Option<IconName>,
 9147        window: &mut Window,
 9148        cx: &App,
 9149    ) -> Option<Stateful<Div>> {
 9150        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9151
 9152        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9153        let has_keybind = keybind.is_some();
 9154
 9155        let result = h_flex()
 9156            .id("ep-line-popover")
 9157            .py_0p5()
 9158            .pl_1()
 9159            .pr(padding_right)
 9160            .gap_1()
 9161            .rounded_md()
 9162            .border_1()
 9163            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9164            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9165            .shadow_xs()
 9166            .when(!has_keybind, |el| {
 9167                let status_colors = cx.theme().status();
 9168
 9169                el.bg(status_colors.error_background)
 9170                    .border_color(status_colors.error.opacity(0.6))
 9171                    .pl_2()
 9172                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9173                    .cursor_default()
 9174                    .hoverable_tooltip(move |_window, cx| {
 9175                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9176                    })
 9177            })
 9178            .children(keybind)
 9179            .child(
 9180                Label::new(label)
 9181                    .size(LabelSize::Small)
 9182                    .when(!has_keybind, |el| {
 9183                        el.color(cx.theme().status().error.into()).strikethrough()
 9184                    }),
 9185            )
 9186            .when(!has_keybind, |el| {
 9187                el.child(
 9188                    h_flex().ml_1().child(
 9189                        Icon::new(IconName::Info)
 9190                            .size(IconSize::Small)
 9191                            .color(cx.theme().status().error.into()),
 9192                    ),
 9193                )
 9194            })
 9195            .when_some(icon, |element, icon| {
 9196                element.child(
 9197                    div()
 9198                        .mt(px(1.5))
 9199                        .child(Icon::new(icon).size(IconSize::Small)),
 9200                )
 9201            });
 9202
 9203        Some(result)
 9204    }
 9205
 9206    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9207        let accent_color = cx.theme().colors().text_accent;
 9208        let editor_bg_color = cx.theme().colors().editor_background;
 9209        editor_bg_color.blend(accent_color.opacity(0.1))
 9210    }
 9211
 9212    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9213        let accent_color = cx.theme().colors().text_accent;
 9214        let editor_bg_color = cx.theme().colors().editor_background;
 9215        editor_bg_color.blend(accent_color.opacity(0.6))
 9216    }
 9217    fn get_prediction_provider_icon_name(
 9218        provider: &Option<RegisteredEditPredictionProvider>,
 9219    ) -> IconName {
 9220        match provider {
 9221            Some(provider) => match provider.provider.name() {
 9222                "copilot" => IconName::Copilot,
 9223                "supermaven" => IconName::Supermaven,
 9224                _ => IconName::ZedPredict,
 9225            },
 9226            None => IconName::ZedPredict,
 9227        }
 9228    }
 9229
 9230    fn render_edit_prediction_cursor_popover(
 9231        &self,
 9232        min_width: Pixels,
 9233        max_width: Pixels,
 9234        cursor_point: Point,
 9235        style: &EditorStyle,
 9236        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9237        _window: &Window,
 9238        cx: &mut Context<Editor>,
 9239    ) -> Option<AnyElement> {
 9240        let provider = self.edit_prediction_provider.as_ref()?;
 9241        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9242
 9243        let is_refreshing = provider.provider.is_refreshing(cx);
 9244
 9245        fn pending_completion_container(icon: IconName) -> Div {
 9246            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9247        }
 9248
 9249        let completion = match &self.active_edit_prediction {
 9250            Some(prediction) => {
 9251                if !self.has_visible_completions_menu() {
 9252                    const RADIUS: Pixels = px(6.);
 9253                    const BORDER_WIDTH: Pixels = px(1.);
 9254
 9255                    return Some(
 9256                        h_flex()
 9257                            .elevation_2(cx)
 9258                            .border(BORDER_WIDTH)
 9259                            .border_color(cx.theme().colors().border)
 9260                            .when(accept_keystroke.is_none(), |el| {
 9261                                el.border_color(cx.theme().status().error)
 9262                            })
 9263                            .rounded(RADIUS)
 9264                            .rounded_tl(px(0.))
 9265                            .overflow_hidden()
 9266                            .child(div().px_1p5().child(match &prediction.completion {
 9267                                EditPrediction::Move { target, snapshot } => {
 9268                                    use text::ToPoint as _;
 9269                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9270                                    {
 9271                                        Icon::new(IconName::ZedPredictDown)
 9272                                    } else {
 9273                                        Icon::new(IconName::ZedPredictUp)
 9274                                    }
 9275                                }
 9276                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9277                            }))
 9278                            .child(
 9279                                h_flex()
 9280                                    .gap_1()
 9281                                    .py_1()
 9282                                    .px_2()
 9283                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9284                                    .border_l_1()
 9285                                    .border_color(cx.theme().colors().border)
 9286                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9287                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9288                                        el.child(
 9289                                            Label::new("Hold")
 9290                                                .size(LabelSize::Small)
 9291                                                .when(accept_keystroke.is_none(), |el| {
 9292                                                    el.strikethrough()
 9293                                                })
 9294                                                .line_height_style(LineHeightStyle::UiLabel),
 9295                                        )
 9296                                    })
 9297                                    .id("edit_prediction_cursor_popover_keybind")
 9298                                    .when(accept_keystroke.is_none(), |el| {
 9299                                        let status_colors = cx.theme().status();
 9300
 9301                                        el.bg(status_colors.error_background)
 9302                                            .border_color(status_colors.error.opacity(0.6))
 9303                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9304                                            .cursor_default()
 9305                                            .hoverable_tooltip(move |_window, cx| {
 9306                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9307                                                    .into()
 9308                                            })
 9309                                    })
 9310                                    .when_some(
 9311                                        accept_keystroke.as_ref(),
 9312                                        |el, accept_keystroke| {
 9313                                            el.child(h_flex().children(ui::render_modifiers(
 9314                                                accept_keystroke.modifiers(),
 9315                                                PlatformStyle::platform(),
 9316                                                Some(Color::Default),
 9317                                                Some(IconSize::XSmall.rems().into()),
 9318                                                false,
 9319                                            )))
 9320                                        },
 9321                                    ),
 9322                            )
 9323                            .into_any(),
 9324                    );
 9325                }
 9326
 9327                self.render_edit_prediction_cursor_popover_preview(
 9328                    prediction,
 9329                    cursor_point,
 9330                    style,
 9331                    cx,
 9332                )?
 9333            }
 9334
 9335            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9336                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9337                    stale_completion,
 9338                    cursor_point,
 9339                    style,
 9340                    cx,
 9341                )?,
 9342
 9343                None => pending_completion_container(provider_icon)
 9344                    .child(Label::new("...").size(LabelSize::Small)),
 9345            },
 9346
 9347            None => pending_completion_container(provider_icon)
 9348                .child(Label::new("...").size(LabelSize::Small)),
 9349        };
 9350
 9351        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9352            completion
 9353                .with_animation(
 9354                    "loading-completion",
 9355                    Animation::new(Duration::from_secs(2))
 9356                        .repeat()
 9357                        .with_easing(pulsating_between(0.4, 0.8)),
 9358                    |label, delta| label.opacity(delta),
 9359                )
 9360                .into_any_element()
 9361        } else {
 9362            completion.into_any_element()
 9363        };
 9364
 9365        let has_completion = self.active_edit_prediction.is_some();
 9366
 9367        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9368        Some(
 9369            h_flex()
 9370                .min_w(min_width)
 9371                .max_w(max_width)
 9372                .flex_1()
 9373                .elevation_2(cx)
 9374                .border_color(cx.theme().colors().border)
 9375                .child(
 9376                    div()
 9377                        .flex_1()
 9378                        .py_1()
 9379                        .px_2()
 9380                        .overflow_hidden()
 9381                        .child(completion),
 9382                )
 9383                .when_some(accept_keystroke, |el, accept_keystroke| {
 9384                    if !accept_keystroke.modifiers().modified() {
 9385                        return el;
 9386                    }
 9387
 9388                    el.child(
 9389                        h_flex()
 9390                            .h_full()
 9391                            .border_l_1()
 9392                            .rounded_r_lg()
 9393                            .border_color(cx.theme().colors().border)
 9394                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9395                            .gap_1()
 9396                            .py_1()
 9397                            .px_2()
 9398                            .child(
 9399                                h_flex()
 9400                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9401                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9402                                    .child(h_flex().children(ui::render_modifiers(
 9403                                        accept_keystroke.modifiers(),
 9404                                        PlatformStyle::platform(),
 9405                                        Some(if !has_completion {
 9406                                            Color::Muted
 9407                                        } else {
 9408                                            Color::Default
 9409                                        }),
 9410                                        None,
 9411                                        false,
 9412                                    ))),
 9413                            )
 9414                            .child(Label::new("Preview").into_any_element())
 9415                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9416                    )
 9417                })
 9418                .into_any(),
 9419        )
 9420    }
 9421
 9422    fn render_edit_prediction_cursor_popover_preview(
 9423        &self,
 9424        completion: &EditPredictionState,
 9425        cursor_point: Point,
 9426        style: &EditorStyle,
 9427        cx: &mut Context<Editor>,
 9428    ) -> Option<Div> {
 9429        use text::ToPoint as _;
 9430
 9431        fn render_relative_row_jump(
 9432            prefix: impl Into<String>,
 9433            current_row: u32,
 9434            target_row: u32,
 9435        ) -> Div {
 9436            let (row_diff, arrow) = if target_row < current_row {
 9437                (current_row - target_row, IconName::ArrowUp)
 9438            } else {
 9439                (target_row - current_row, IconName::ArrowDown)
 9440            };
 9441
 9442            h_flex()
 9443                .child(
 9444                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9445                        .color(Color::Muted)
 9446                        .size(LabelSize::Small),
 9447                )
 9448                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9449        }
 9450
 9451        let supports_jump = self
 9452            .edit_prediction_provider
 9453            .as_ref()
 9454            .map(|provider| provider.provider.supports_jump_to_edit())
 9455            .unwrap_or(true);
 9456
 9457        match &completion.completion {
 9458            EditPrediction::Move {
 9459                target, snapshot, ..
 9460            } => {
 9461                if !supports_jump {
 9462                    return None;
 9463                }
 9464
 9465                Some(
 9466                    h_flex()
 9467                        .px_2()
 9468                        .gap_2()
 9469                        .flex_1()
 9470                        .child(
 9471                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9472                                Icon::new(IconName::ZedPredictDown)
 9473                            } else {
 9474                                Icon::new(IconName::ZedPredictUp)
 9475                            },
 9476                        )
 9477                        .child(Label::new("Jump to Edit")),
 9478                )
 9479            }
 9480
 9481            EditPrediction::Edit {
 9482                edits,
 9483                edit_preview,
 9484                snapshot,
 9485                display_mode: _,
 9486            } => {
 9487                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9488
 9489                let (highlighted_edits, has_more_lines) =
 9490                    if let Some(edit_preview) = edit_preview.as_ref() {
 9491                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9492                            .first_line_preview()
 9493                    } else {
 9494                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9495                    };
 9496
 9497                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9498                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9499
 9500                let preview = h_flex()
 9501                    .gap_1()
 9502                    .min_w_16()
 9503                    .child(styled_text)
 9504                    .when(has_more_lines, |parent| parent.child(""));
 9505
 9506                let left = if supports_jump && first_edit_row != cursor_point.row {
 9507                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9508                        .into_any_element()
 9509                } else {
 9510                    let icon_name =
 9511                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9512                    Icon::new(icon_name).into_any_element()
 9513                };
 9514
 9515                Some(
 9516                    h_flex()
 9517                        .h_full()
 9518                        .flex_1()
 9519                        .gap_2()
 9520                        .pr_1()
 9521                        .overflow_x_hidden()
 9522                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9523                        .child(left)
 9524                        .child(preview),
 9525                )
 9526            }
 9527        }
 9528    }
 9529
 9530    pub fn render_context_menu(
 9531        &self,
 9532        style: &EditorStyle,
 9533        max_height_in_lines: u32,
 9534        window: &mut Window,
 9535        cx: &mut Context<Editor>,
 9536    ) -> Option<AnyElement> {
 9537        let menu = self.context_menu.borrow();
 9538        let menu = menu.as_ref()?;
 9539        if !menu.visible() {
 9540            return None;
 9541        };
 9542        Some(menu.render(style, max_height_in_lines, window, cx))
 9543    }
 9544
 9545    fn render_context_menu_aside(
 9546        &mut self,
 9547        max_size: Size<Pixels>,
 9548        window: &mut Window,
 9549        cx: &mut Context<Editor>,
 9550    ) -> Option<AnyElement> {
 9551        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9552            if menu.visible() {
 9553                menu.render_aside(max_size, window, cx)
 9554            } else {
 9555                None
 9556            }
 9557        })
 9558    }
 9559
 9560    fn hide_context_menu(
 9561        &mut self,
 9562        window: &mut Window,
 9563        cx: &mut Context<Self>,
 9564    ) -> Option<CodeContextMenu> {
 9565        cx.notify();
 9566        self.completion_tasks.clear();
 9567        let context_menu = self.context_menu.borrow_mut().take();
 9568        self.stale_edit_prediction_in_menu.take();
 9569        self.update_visible_edit_prediction(window, cx);
 9570        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9571            && let Some(completion_provider) = &self.completion_provider
 9572        {
 9573            completion_provider.selection_changed(None, window, cx);
 9574        }
 9575        context_menu
 9576    }
 9577
 9578    fn show_snippet_choices(
 9579        &mut self,
 9580        choices: &Vec<String>,
 9581        selection: Range<Anchor>,
 9582        cx: &mut Context<Self>,
 9583    ) {
 9584        let Some((_, buffer, _)) = self
 9585            .buffer()
 9586            .read(cx)
 9587            .excerpt_containing(selection.start, cx)
 9588        else {
 9589            return;
 9590        };
 9591        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9592        else {
 9593            return;
 9594        };
 9595        if buffer != end_buffer {
 9596            log::error!("expected anchor range to have matching buffer IDs");
 9597            return;
 9598        }
 9599
 9600        let id = post_inc(&mut self.next_completion_id);
 9601        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9602        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9603            CompletionsMenu::new_snippet_choices(
 9604                id,
 9605                true,
 9606                choices,
 9607                selection,
 9608                buffer,
 9609                snippet_sort_order,
 9610            ),
 9611        ));
 9612    }
 9613
 9614    pub fn insert_snippet(
 9615        &mut self,
 9616        insertion_ranges: &[Range<usize>],
 9617        snippet: Snippet,
 9618        window: &mut Window,
 9619        cx: &mut Context<Self>,
 9620    ) -> Result<()> {
 9621        struct Tabstop<T> {
 9622            is_end_tabstop: bool,
 9623            ranges: Vec<Range<T>>,
 9624            choices: Option<Vec<String>>,
 9625        }
 9626
 9627        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9628            let snippet_text: Arc<str> = snippet.text.clone().into();
 9629            let edits = insertion_ranges
 9630                .iter()
 9631                .cloned()
 9632                .map(|range| (range, snippet_text.clone()));
 9633            let autoindent_mode = AutoindentMode::Block {
 9634                original_indent_columns: Vec::new(),
 9635            };
 9636            buffer.edit(edits, Some(autoindent_mode), cx);
 9637
 9638            let snapshot = &*buffer.read(cx);
 9639            let snippet = &snippet;
 9640            snippet
 9641                .tabstops
 9642                .iter()
 9643                .map(|tabstop| {
 9644                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9645                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9646                    });
 9647                    let mut tabstop_ranges = tabstop
 9648                        .ranges
 9649                        .iter()
 9650                        .flat_map(|tabstop_range| {
 9651                            let mut delta = 0_isize;
 9652                            insertion_ranges.iter().map(move |insertion_range| {
 9653                                let insertion_start = insertion_range.start as isize + delta;
 9654                                delta +=
 9655                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9656
 9657                                let start = ((insertion_start + tabstop_range.start) as usize)
 9658                                    .min(snapshot.len());
 9659                                let end = ((insertion_start + tabstop_range.end) as usize)
 9660                                    .min(snapshot.len());
 9661                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9662                            })
 9663                        })
 9664                        .collect::<Vec<_>>();
 9665                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9666
 9667                    Tabstop {
 9668                        is_end_tabstop,
 9669                        ranges: tabstop_ranges,
 9670                        choices: tabstop.choices.clone(),
 9671                    }
 9672                })
 9673                .collect::<Vec<_>>()
 9674        });
 9675        if let Some(tabstop) = tabstops.first() {
 9676            self.change_selections(Default::default(), window, cx, |s| {
 9677                // Reverse order so that the first range is the newest created selection.
 9678                // Completions will use it and autoscroll will prioritize it.
 9679                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9680            });
 9681
 9682            if let Some(choices) = &tabstop.choices
 9683                && let Some(selection) = tabstop.ranges.first()
 9684            {
 9685                self.show_snippet_choices(choices, selection.clone(), cx)
 9686            }
 9687
 9688            // If we're already at the last tabstop and it's at the end of the snippet,
 9689            // we're done, we don't need to keep the state around.
 9690            if !tabstop.is_end_tabstop {
 9691                let choices = tabstops
 9692                    .iter()
 9693                    .map(|tabstop| tabstop.choices.clone())
 9694                    .collect();
 9695
 9696                let ranges = tabstops
 9697                    .into_iter()
 9698                    .map(|tabstop| tabstop.ranges)
 9699                    .collect::<Vec<_>>();
 9700
 9701                self.snippet_stack.push(SnippetState {
 9702                    active_index: 0,
 9703                    ranges,
 9704                    choices,
 9705                });
 9706            }
 9707
 9708            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9709            if self.autoclose_regions.is_empty() {
 9710                let snapshot = self.buffer.read(cx).snapshot(cx);
 9711                let mut all_selections = self.selections.all::<Point>(cx);
 9712                for selection in &mut all_selections {
 9713                    let selection_head = selection.head();
 9714                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9715                        continue;
 9716                    };
 9717
 9718                    let mut bracket_pair = None;
 9719                    let max_lookup_length = scope
 9720                        .brackets()
 9721                        .map(|(pair, _)| {
 9722                            pair.start
 9723                                .as_str()
 9724                                .chars()
 9725                                .count()
 9726                                .max(pair.end.as_str().chars().count())
 9727                        })
 9728                        .max();
 9729                    if let Some(max_lookup_length) = max_lookup_length {
 9730                        let next_text = snapshot
 9731                            .chars_at(selection_head)
 9732                            .take(max_lookup_length)
 9733                            .collect::<String>();
 9734                        let prev_text = snapshot
 9735                            .reversed_chars_at(selection_head)
 9736                            .take(max_lookup_length)
 9737                            .collect::<String>();
 9738
 9739                        for (pair, enabled) in scope.brackets() {
 9740                            if enabled
 9741                                && pair.close
 9742                                && prev_text.starts_with(pair.start.as_str())
 9743                                && next_text.starts_with(pair.end.as_str())
 9744                            {
 9745                                bracket_pair = Some(pair.clone());
 9746                                break;
 9747                            }
 9748                        }
 9749                    }
 9750
 9751                    if let Some(pair) = bracket_pair {
 9752                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9753                        let autoclose_enabled =
 9754                            self.use_autoclose && snapshot_settings.use_autoclose;
 9755                        if autoclose_enabled {
 9756                            let start = snapshot.anchor_after(selection_head);
 9757                            let end = snapshot.anchor_after(selection_head);
 9758                            self.autoclose_regions.push(AutocloseRegion {
 9759                                selection_id: selection.id,
 9760                                range: start..end,
 9761                                pair,
 9762                            });
 9763                        }
 9764                    }
 9765                }
 9766            }
 9767        }
 9768        Ok(())
 9769    }
 9770
 9771    pub fn move_to_next_snippet_tabstop(
 9772        &mut self,
 9773        window: &mut Window,
 9774        cx: &mut Context<Self>,
 9775    ) -> bool {
 9776        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9777    }
 9778
 9779    pub fn move_to_prev_snippet_tabstop(
 9780        &mut self,
 9781        window: &mut Window,
 9782        cx: &mut Context<Self>,
 9783    ) -> bool {
 9784        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9785    }
 9786
 9787    pub fn move_to_snippet_tabstop(
 9788        &mut self,
 9789        bias: Bias,
 9790        window: &mut Window,
 9791        cx: &mut Context<Self>,
 9792    ) -> bool {
 9793        if let Some(mut snippet) = self.snippet_stack.pop() {
 9794            match bias {
 9795                Bias::Left => {
 9796                    if snippet.active_index > 0 {
 9797                        snippet.active_index -= 1;
 9798                    } else {
 9799                        self.snippet_stack.push(snippet);
 9800                        return false;
 9801                    }
 9802                }
 9803                Bias::Right => {
 9804                    if snippet.active_index + 1 < snippet.ranges.len() {
 9805                        snippet.active_index += 1;
 9806                    } else {
 9807                        self.snippet_stack.push(snippet);
 9808                        return false;
 9809                    }
 9810                }
 9811            }
 9812            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9813                self.change_selections(Default::default(), window, cx, |s| {
 9814                    // Reverse order so that the first range is the newest created selection.
 9815                    // Completions will use it and autoscroll will prioritize it.
 9816                    s.select_ranges(current_ranges.iter().rev().cloned())
 9817                });
 9818
 9819                if let Some(choices) = &snippet.choices[snippet.active_index]
 9820                    && let Some(selection) = current_ranges.first()
 9821                {
 9822                    self.show_snippet_choices(choices, selection.clone(), cx);
 9823                }
 9824
 9825                // If snippet state is not at the last tabstop, push it back on the stack
 9826                if snippet.active_index + 1 < snippet.ranges.len() {
 9827                    self.snippet_stack.push(snippet);
 9828                }
 9829                return true;
 9830            }
 9831        }
 9832
 9833        false
 9834    }
 9835
 9836    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9837        self.transact(window, cx, |this, window, cx| {
 9838            this.select_all(&SelectAll, window, cx);
 9839            this.insert("", window, cx);
 9840        });
 9841    }
 9842
 9843    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9844        if self.read_only(cx) {
 9845            return;
 9846        }
 9847        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9848        self.transact(window, cx, |this, window, cx| {
 9849            this.select_autoclose_pair(window, cx);
 9850            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9851            if !this.linked_edit_ranges.is_empty() {
 9852                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9853                let snapshot = this.buffer.read(cx).snapshot(cx);
 9854
 9855                for selection in selections.iter() {
 9856                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9857                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9858                    if selection_start.buffer_id != selection_end.buffer_id {
 9859                        continue;
 9860                    }
 9861                    if let Some(ranges) =
 9862                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9863                    {
 9864                        for (buffer, entries) in ranges {
 9865                            linked_ranges.entry(buffer).or_default().extend(entries);
 9866                        }
 9867                    }
 9868                }
 9869            }
 9870
 9871            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9872            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9873            for selection in &mut selections {
 9874                if selection.is_empty() {
 9875                    let old_head = selection.head();
 9876                    let mut new_head =
 9877                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9878                            .to_point(&display_map);
 9879                    if let Some((buffer, line_buffer_range)) = display_map
 9880                        .buffer_snapshot
 9881                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9882                    {
 9883                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9884                        let indent_len = match indent_size.kind {
 9885                            IndentKind::Space => {
 9886                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9887                            }
 9888                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9889                        };
 9890                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9891                            let indent_len = indent_len.get();
 9892                            new_head = cmp::min(
 9893                                new_head,
 9894                                MultiBufferPoint::new(
 9895                                    old_head.row,
 9896                                    ((old_head.column - 1) / indent_len) * indent_len,
 9897                                ),
 9898                            );
 9899                        }
 9900                    }
 9901
 9902                    selection.set_head(new_head, SelectionGoal::None);
 9903                }
 9904            }
 9905
 9906            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9907            this.insert("", window, cx);
 9908            let empty_str: Arc<str> = Arc::from("");
 9909            for (buffer, edits) in linked_ranges {
 9910                let snapshot = buffer.read(cx).snapshot();
 9911                use text::ToPoint as TP;
 9912
 9913                let edits = edits
 9914                    .into_iter()
 9915                    .map(|range| {
 9916                        let end_point = TP::to_point(&range.end, &snapshot);
 9917                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9918
 9919                        if end_point == start_point {
 9920                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9921                                .saturating_sub(1);
 9922                            start_point =
 9923                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9924                        };
 9925
 9926                        (start_point..end_point, empty_str.clone())
 9927                    })
 9928                    .sorted_by_key(|(range, _)| range.start)
 9929                    .collect::<Vec<_>>();
 9930                buffer.update(cx, |this, cx| {
 9931                    this.edit(edits, None, cx);
 9932                })
 9933            }
 9934            this.refresh_edit_prediction(true, false, window, cx);
 9935            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9936        });
 9937    }
 9938
 9939    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9940        if self.read_only(cx) {
 9941            return;
 9942        }
 9943        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9944        self.transact(window, cx, |this, window, cx| {
 9945            this.change_selections(Default::default(), window, cx, |s| {
 9946                s.move_with(|map, selection| {
 9947                    if selection.is_empty() {
 9948                        let cursor = movement::right(map, selection.head());
 9949                        selection.end = cursor;
 9950                        selection.reversed = true;
 9951                        selection.goal = SelectionGoal::None;
 9952                    }
 9953                })
 9954            });
 9955            this.insert("", window, cx);
 9956            this.refresh_edit_prediction(true, false, window, cx);
 9957        });
 9958    }
 9959
 9960    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9961        if self.mode.is_single_line() {
 9962            cx.propagate();
 9963            return;
 9964        }
 9965
 9966        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9967        if self.move_to_prev_snippet_tabstop(window, cx) {
 9968            return;
 9969        }
 9970        self.outdent(&Outdent, window, cx);
 9971    }
 9972
 9973    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9974        if self.mode.is_single_line() {
 9975            cx.propagate();
 9976            return;
 9977        }
 9978
 9979        if self.move_to_next_snippet_tabstop(window, cx) {
 9980            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9981            return;
 9982        }
 9983        if self.read_only(cx) {
 9984            return;
 9985        }
 9986        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9987        let mut selections = self.selections.all_adjusted(cx);
 9988        let buffer = self.buffer.read(cx);
 9989        let snapshot = buffer.snapshot(cx);
 9990        let rows_iter = selections.iter().map(|s| s.head().row);
 9991        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9992
 9993        let has_some_cursor_in_whitespace = selections
 9994            .iter()
 9995            .filter(|selection| selection.is_empty())
 9996            .any(|selection| {
 9997                let cursor = selection.head();
 9998                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9999                cursor.column < current_indent.len
10000            });
10001
10002        let mut edits = Vec::new();
10003        let mut prev_edited_row = 0;
10004        let mut row_delta = 0;
10005        for selection in &mut selections {
10006            if selection.start.row != prev_edited_row {
10007                row_delta = 0;
10008            }
10009            prev_edited_row = selection.end.row;
10010
10011            // If the selection is non-empty, then increase the indentation of the selected lines.
10012            if !selection.is_empty() {
10013                row_delta =
10014                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10015                continue;
10016            }
10017
10018            let cursor = selection.head();
10019            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10020            if let Some(suggested_indent) =
10021                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10022            {
10023                // Don't do anything if already at suggested indent
10024                // and there is any other cursor which is not
10025                if has_some_cursor_in_whitespace
10026                    && cursor.column == current_indent.len
10027                    && current_indent.len == suggested_indent.len
10028                {
10029                    continue;
10030                }
10031
10032                // Adjust line and move cursor to suggested indent
10033                // if cursor is not at suggested indent
10034                if cursor.column < suggested_indent.len
10035                    && cursor.column <= current_indent.len
10036                    && current_indent.len <= suggested_indent.len
10037                {
10038                    selection.start = Point::new(cursor.row, suggested_indent.len);
10039                    selection.end = selection.start;
10040                    if row_delta == 0 {
10041                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10042                            cursor.row,
10043                            current_indent,
10044                            suggested_indent,
10045                        ));
10046                        row_delta = suggested_indent.len - current_indent.len;
10047                    }
10048                    continue;
10049                }
10050
10051                // If current indent is more than suggested indent
10052                // only move cursor to current indent and skip indent
10053                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10054                    selection.start = Point::new(cursor.row, current_indent.len);
10055                    selection.end = selection.start;
10056                    continue;
10057                }
10058            }
10059
10060            // Otherwise, insert a hard or soft tab.
10061            let settings = buffer.language_settings_at(cursor, cx);
10062            let tab_size = if settings.hard_tabs {
10063                IndentSize::tab()
10064            } else {
10065                let tab_size = settings.tab_size.get();
10066                let indent_remainder = snapshot
10067                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10068                    .flat_map(str::chars)
10069                    .fold(row_delta % tab_size, |counter: u32, c| {
10070                        if c == '\t' {
10071                            0
10072                        } else {
10073                            (counter + 1) % tab_size
10074                        }
10075                    });
10076
10077                let chars_to_next_tab_stop = tab_size - indent_remainder;
10078                IndentSize::spaces(chars_to_next_tab_stop)
10079            };
10080            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10081            selection.end = selection.start;
10082            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10083            row_delta += tab_size.len;
10084        }
10085
10086        self.transact(window, cx, |this, window, cx| {
10087            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10088            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10089            this.refresh_edit_prediction(true, false, window, cx);
10090        });
10091    }
10092
10093    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10094        if self.read_only(cx) {
10095            return;
10096        }
10097        if self.mode.is_single_line() {
10098            cx.propagate();
10099            return;
10100        }
10101
10102        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10103        let mut selections = self.selections.all::<Point>(cx);
10104        let mut prev_edited_row = 0;
10105        let mut row_delta = 0;
10106        let mut edits = Vec::new();
10107        let buffer = self.buffer.read(cx);
10108        let snapshot = buffer.snapshot(cx);
10109        for selection in &mut selections {
10110            if selection.start.row != prev_edited_row {
10111                row_delta = 0;
10112            }
10113            prev_edited_row = selection.end.row;
10114
10115            row_delta =
10116                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10117        }
10118
10119        self.transact(window, cx, |this, window, cx| {
10120            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10121            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10122        });
10123    }
10124
10125    fn indent_selection(
10126        buffer: &MultiBuffer,
10127        snapshot: &MultiBufferSnapshot,
10128        selection: &mut Selection<Point>,
10129        edits: &mut Vec<(Range<Point>, String)>,
10130        delta_for_start_row: u32,
10131        cx: &App,
10132    ) -> u32 {
10133        let settings = buffer.language_settings_at(selection.start, cx);
10134        let tab_size = settings.tab_size.get();
10135        let indent_kind = if settings.hard_tabs {
10136            IndentKind::Tab
10137        } else {
10138            IndentKind::Space
10139        };
10140        let mut start_row = selection.start.row;
10141        let mut end_row = selection.end.row + 1;
10142
10143        // If a selection ends at the beginning of a line, don't indent
10144        // that last line.
10145        if selection.end.column == 0 && selection.end.row > selection.start.row {
10146            end_row -= 1;
10147        }
10148
10149        // Avoid re-indenting a row that has already been indented by a
10150        // previous selection, but still update this selection's column
10151        // to reflect that indentation.
10152        if delta_for_start_row > 0 {
10153            start_row += 1;
10154            selection.start.column += delta_for_start_row;
10155            if selection.end.row == selection.start.row {
10156                selection.end.column += delta_for_start_row;
10157            }
10158        }
10159
10160        let mut delta_for_end_row = 0;
10161        let has_multiple_rows = start_row + 1 != end_row;
10162        for row in start_row..end_row {
10163            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10164            let indent_delta = match (current_indent.kind, indent_kind) {
10165                (IndentKind::Space, IndentKind::Space) => {
10166                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10167                    IndentSize::spaces(columns_to_next_tab_stop)
10168                }
10169                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10170                (_, IndentKind::Tab) => IndentSize::tab(),
10171            };
10172
10173            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10174                0
10175            } else {
10176                selection.start.column
10177            };
10178            let row_start = Point::new(row, start);
10179            edits.push((
10180                row_start..row_start,
10181                indent_delta.chars().collect::<String>(),
10182            ));
10183
10184            // Update this selection's endpoints to reflect the indentation.
10185            if row == selection.start.row {
10186                selection.start.column += indent_delta.len;
10187            }
10188            if row == selection.end.row {
10189                selection.end.column += indent_delta.len;
10190                delta_for_end_row = indent_delta.len;
10191            }
10192        }
10193
10194        if selection.start.row == selection.end.row {
10195            delta_for_start_row + delta_for_end_row
10196        } else {
10197            delta_for_end_row
10198        }
10199    }
10200
10201    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10202        if self.read_only(cx) {
10203            return;
10204        }
10205        if self.mode.is_single_line() {
10206            cx.propagate();
10207            return;
10208        }
10209
10210        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10211        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10212        let selections = self.selections.all::<Point>(cx);
10213        let mut deletion_ranges = Vec::new();
10214        let mut last_outdent = None;
10215        {
10216            let buffer = self.buffer.read(cx);
10217            let snapshot = buffer.snapshot(cx);
10218            for selection in &selections {
10219                let settings = buffer.language_settings_at(selection.start, cx);
10220                let tab_size = settings.tab_size.get();
10221                let mut rows = selection.spanned_rows(false, &display_map);
10222
10223                // Avoid re-outdenting a row that has already been outdented by a
10224                // previous selection.
10225                if let Some(last_row) = last_outdent
10226                    && last_row == rows.start
10227                {
10228                    rows.start = rows.start.next_row();
10229                }
10230                let has_multiple_rows = rows.len() > 1;
10231                for row in rows.iter_rows() {
10232                    let indent_size = snapshot.indent_size_for_line(row);
10233                    if indent_size.len > 0 {
10234                        let deletion_len = match indent_size.kind {
10235                            IndentKind::Space => {
10236                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10237                                if columns_to_prev_tab_stop == 0 {
10238                                    tab_size
10239                                } else {
10240                                    columns_to_prev_tab_stop
10241                                }
10242                            }
10243                            IndentKind::Tab => 1,
10244                        };
10245                        let start = if has_multiple_rows
10246                            || deletion_len > selection.start.column
10247                            || indent_size.len < selection.start.column
10248                        {
10249                            0
10250                        } else {
10251                            selection.start.column - deletion_len
10252                        };
10253                        deletion_ranges.push(
10254                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10255                        );
10256                        last_outdent = Some(row);
10257                    }
10258                }
10259            }
10260        }
10261
10262        self.transact(window, cx, |this, window, cx| {
10263            this.buffer.update(cx, |buffer, cx| {
10264                let empty_str: Arc<str> = Arc::default();
10265                buffer.edit(
10266                    deletion_ranges
10267                        .into_iter()
10268                        .map(|range| (range, empty_str.clone())),
10269                    None,
10270                    cx,
10271                );
10272            });
10273            let selections = this.selections.all::<usize>(cx);
10274            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10275        });
10276    }
10277
10278    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10279        if self.read_only(cx) {
10280            return;
10281        }
10282        if self.mode.is_single_line() {
10283            cx.propagate();
10284            return;
10285        }
10286
10287        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10288        let selections = self
10289            .selections
10290            .all::<usize>(cx)
10291            .into_iter()
10292            .map(|s| s.range());
10293
10294        self.transact(window, cx, |this, window, cx| {
10295            this.buffer.update(cx, |buffer, cx| {
10296                buffer.autoindent_ranges(selections, cx);
10297            });
10298            let selections = this.selections.all::<usize>(cx);
10299            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10300        });
10301    }
10302
10303    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10304        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10305        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10306        let selections = self.selections.all::<Point>(cx);
10307
10308        let mut new_cursors = Vec::new();
10309        let mut edit_ranges = Vec::new();
10310        let mut selections = selections.iter().peekable();
10311        while let Some(selection) = selections.next() {
10312            let mut rows = selection.spanned_rows(false, &display_map);
10313            let goal_display_column = selection.head().to_display_point(&display_map).column();
10314
10315            // Accumulate contiguous regions of rows that we want to delete.
10316            while let Some(next_selection) = selections.peek() {
10317                let next_rows = next_selection.spanned_rows(false, &display_map);
10318                if next_rows.start <= rows.end {
10319                    rows.end = next_rows.end;
10320                    selections.next().unwrap();
10321                } else {
10322                    break;
10323                }
10324            }
10325
10326            let buffer = &display_map.buffer_snapshot;
10327            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10328            let edit_end;
10329            let cursor_buffer_row;
10330            if buffer.max_point().row >= rows.end.0 {
10331                // If there's a line after the range, delete the \n from the end of the row range
10332                // and position the cursor on the next line.
10333                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10334                cursor_buffer_row = rows.end;
10335            } else {
10336                // If there isn't a line after the range, delete the \n from the line before the
10337                // start of the row range and position the cursor there.
10338                edit_start = edit_start.saturating_sub(1);
10339                edit_end = buffer.len();
10340                cursor_buffer_row = rows.start.previous_row();
10341            }
10342
10343            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10344            *cursor.column_mut() =
10345                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10346
10347            new_cursors.push((
10348                selection.id,
10349                buffer.anchor_after(cursor.to_point(&display_map)),
10350            ));
10351            edit_ranges.push(edit_start..edit_end);
10352        }
10353
10354        self.transact(window, cx, |this, window, cx| {
10355            let buffer = this.buffer.update(cx, |buffer, cx| {
10356                let empty_str: Arc<str> = Arc::default();
10357                buffer.edit(
10358                    edit_ranges
10359                        .into_iter()
10360                        .map(|range| (range, empty_str.clone())),
10361                    None,
10362                    cx,
10363                );
10364                buffer.snapshot(cx)
10365            });
10366            let new_selections = new_cursors
10367                .into_iter()
10368                .map(|(id, cursor)| {
10369                    let cursor = cursor.to_point(&buffer);
10370                    Selection {
10371                        id,
10372                        start: cursor,
10373                        end: cursor,
10374                        reversed: false,
10375                        goal: SelectionGoal::None,
10376                    }
10377                })
10378                .collect();
10379
10380            this.change_selections(Default::default(), window, cx, |s| {
10381                s.select(new_selections);
10382            });
10383        });
10384    }
10385
10386    pub fn join_lines_impl(
10387        &mut self,
10388        insert_whitespace: bool,
10389        window: &mut Window,
10390        cx: &mut Context<Self>,
10391    ) {
10392        if self.read_only(cx) {
10393            return;
10394        }
10395        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10396        for selection in self.selections.all::<Point>(cx) {
10397            let start = MultiBufferRow(selection.start.row);
10398            // Treat single line selections as if they include the next line. Otherwise this action
10399            // would do nothing for single line selections individual cursors.
10400            let end = if selection.start.row == selection.end.row {
10401                MultiBufferRow(selection.start.row + 1)
10402            } else {
10403                MultiBufferRow(selection.end.row)
10404            };
10405
10406            if let Some(last_row_range) = row_ranges.last_mut()
10407                && start <= last_row_range.end
10408            {
10409                last_row_range.end = end;
10410                continue;
10411            }
10412            row_ranges.push(start..end);
10413        }
10414
10415        let snapshot = self.buffer.read(cx).snapshot(cx);
10416        let mut cursor_positions = Vec::new();
10417        for row_range in &row_ranges {
10418            let anchor = snapshot.anchor_before(Point::new(
10419                row_range.end.previous_row().0,
10420                snapshot.line_len(row_range.end.previous_row()),
10421            ));
10422            cursor_positions.push(anchor..anchor);
10423        }
10424
10425        self.transact(window, cx, |this, window, cx| {
10426            for row_range in row_ranges.into_iter().rev() {
10427                for row in row_range.iter_rows().rev() {
10428                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10429                    let next_line_row = row.next_row();
10430                    let indent = snapshot.indent_size_for_line(next_line_row);
10431                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10432
10433                    let replace =
10434                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10435                            " "
10436                        } else {
10437                            ""
10438                        };
10439
10440                    this.buffer.update(cx, |buffer, cx| {
10441                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10442                    });
10443                }
10444            }
10445
10446            this.change_selections(Default::default(), window, cx, |s| {
10447                s.select_anchor_ranges(cursor_positions)
10448            });
10449        });
10450    }
10451
10452    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10453        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10454        self.join_lines_impl(true, window, cx);
10455    }
10456
10457    pub fn sort_lines_case_sensitive(
10458        &mut self,
10459        _: &SortLinesCaseSensitive,
10460        window: &mut Window,
10461        cx: &mut Context<Self>,
10462    ) {
10463        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10464    }
10465
10466    pub fn sort_lines_by_length(
10467        &mut self,
10468        _: &SortLinesByLength,
10469        window: &mut Window,
10470        cx: &mut Context<Self>,
10471    ) {
10472        self.manipulate_immutable_lines(window, cx, |lines| {
10473            lines.sort_by_key(|&line| line.chars().count())
10474        })
10475    }
10476
10477    pub fn sort_lines_case_insensitive(
10478        &mut self,
10479        _: &SortLinesCaseInsensitive,
10480        window: &mut Window,
10481        cx: &mut Context<Self>,
10482    ) {
10483        self.manipulate_immutable_lines(window, cx, |lines| {
10484            lines.sort_by_key(|line| line.to_lowercase())
10485        })
10486    }
10487
10488    pub fn unique_lines_case_insensitive(
10489        &mut self,
10490        _: &UniqueLinesCaseInsensitive,
10491        window: &mut Window,
10492        cx: &mut Context<Self>,
10493    ) {
10494        self.manipulate_immutable_lines(window, cx, |lines| {
10495            let mut seen = HashSet::default();
10496            lines.retain(|line| seen.insert(line.to_lowercase()));
10497        })
10498    }
10499
10500    pub fn unique_lines_case_sensitive(
10501        &mut self,
10502        _: &UniqueLinesCaseSensitive,
10503        window: &mut Window,
10504        cx: &mut Context<Self>,
10505    ) {
10506        self.manipulate_immutable_lines(window, cx, |lines| {
10507            let mut seen = HashSet::default();
10508            lines.retain(|line| seen.insert(*line));
10509        })
10510    }
10511
10512    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10513        let snapshot = self.buffer.read(cx).snapshot(cx);
10514        for selection in self.selections.disjoint_anchors().iter() {
10515            if snapshot
10516                .language_at(selection.start)
10517                .and_then(|lang| lang.config().wrap_characters.as_ref())
10518                .is_some()
10519            {
10520                return true;
10521            }
10522        }
10523        false
10524    }
10525
10526    fn wrap_selections_in_tag(
10527        &mut self,
10528        _: &WrapSelectionsInTag,
10529        window: &mut Window,
10530        cx: &mut Context<Self>,
10531    ) {
10532        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10533
10534        let snapshot = self.buffer.read(cx).snapshot(cx);
10535
10536        let mut edits = Vec::new();
10537        let mut boundaries = Vec::new();
10538
10539        for selection in self.selections.all::<Point>(cx).iter() {
10540            let Some(wrap_config) = snapshot
10541                .language_at(selection.start)
10542                .and_then(|lang| lang.config().wrap_characters.clone())
10543            else {
10544                continue;
10545            };
10546
10547            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10548            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10549
10550            let start_before = snapshot.anchor_before(selection.start);
10551            let end_after = snapshot.anchor_after(selection.end);
10552
10553            edits.push((start_before..start_before, open_tag));
10554            edits.push((end_after..end_after, close_tag));
10555
10556            boundaries.push((
10557                start_before,
10558                end_after,
10559                wrap_config.start_prefix.len(),
10560                wrap_config.end_suffix.len(),
10561            ));
10562        }
10563
10564        if edits.is_empty() {
10565            return;
10566        }
10567
10568        self.transact(window, cx, |this, window, cx| {
10569            let buffer = this.buffer.update(cx, |buffer, cx| {
10570                buffer.edit(edits, None, cx);
10571                buffer.snapshot(cx)
10572            });
10573
10574            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10575            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10576                boundaries.into_iter()
10577            {
10578                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10579                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10580                new_selections.push(open_offset..open_offset);
10581                new_selections.push(close_offset..close_offset);
10582            }
10583
10584            this.change_selections(Default::default(), window, cx, |s| {
10585                s.select_ranges(new_selections);
10586            });
10587
10588            this.request_autoscroll(Autoscroll::fit(), cx);
10589        });
10590    }
10591
10592    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10593        let Some(project) = self.project.clone() else {
10594            return;
10595        };
10596        self.reload(project, window, cx)
10597            .detach_and_notify_err(window, cx);
10598    }
10599
10600    pub fn restore_file(
10601        &mut self,
10602        _: &::git::RestoreFile,
10603        window: &mut Window,
10604        cx: &mut Context<Self>,
10605    ) {
10606        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10607        let mut buffer_ids = HashSet::default();
10608        let snapshot = self.buffer().read(cx).snapshot(cx);
10609        for selection in self.selections.all::<usize>(cx) {
10610            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10611        }
10612
10613        let buffer = self.buffer().read(cx);
10614        let ranges = buffer_ids
10615            .into_iter()
10616            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10617            .collect::<Vec<_>>();
10618
10619        self.restore_hunks_in_ranges(ranges, window, cx);
10620    }
10621
10622    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10623        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10624        let selections = self
10625            .selections
10626            .all(cx)
10627            .into_iter()
10628            .map(|s| s.range())
10629            .collect();
10630        self.restore_hunks_in_ranges(selections, window, cx);
10631    }
10632
10633    pub fn restore_hunks_in_ranges(
10634        &mut self,
10635        ranges: Vec<Range<Point>>,
10636        window: &mut Window,
10637        cx: &mut Context<Editor>,
10638    ) {
10639        let mut revert_changes = HashMap::default();
10640        let chunk_by = self
10641            .snapshot(window, cx)
10642            .hunks_for_ranges(ranges)
10643            .into_iter()
10644            .chunk_by(|hunk| hunk.buffer_id);
10645        for (buffer_id, hunks) in &chunk_by {
10646            let hunks = hunks.collect::<Vec<_>>();
10647            for hunk in &hunks {
10648                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10649            }
10650            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10651        }
10652        drop(chunk_by);
10653        if !revert_changes.is_empty() {
10654            self.transact(window, cx, |editor, window, cx| {
10655                editor.restore(revert_changes, window, cx);
10656            });
10657        }
10658    }
10659
10660    pub fn open_active_item_in_terminal(
10661        &mut self,
10662        _: &OpenInTerminal,
10663        window: &mut Window,
10664        cx: &mut Context<Self>,
10665    ) {
10666        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10667            let project_path = buffer.read(cx).project_path(cx)?;
10668            let project = self.project()?.read(cx);
10669            let entry = project.entry_for_path(&project_path, cx)?;
10670            let parent = match &entry.canonical_path {
10671                Some(canonical_path) => canonical_path.to_path_buf(),
10672                None => project.absolute_path(&project_path, cx)?,
10673            }
10674            .parent()?
10675            .to_path_buf();
10676            Some(parent)
10677        }) {
10678            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10679        }
10680    }
10681
10682    fn set_breakpoint_context_menu(
10683        &mut self,
10684        display_row: DisplayRow,
10685        position: Option<Anchor>,
10686        clicked_point: gpui::Point<Pixels>,
10687        window: &mut Window,
10688        cx: &mut Context<Self>,
10689    ) {
10690        let source = self
10691            .buffer
10692            .read(cx)
10693            .snapshot(cx)
10694            .anchor_before(Point::new(display_row.0, 0u32));
10695
10696        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10697
10698        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10699            self,
10700            source,
10701            clicked_point,
10702            context_menu,
10703            window,
10704            cx,
10705        );
10706    }
10707
10708    fn add_edit_breakpoint_block(
10709        &mut self,
10710        anchor: Anchor,
10711        breakpoint: &Breakpoint,
10712        edit_action: BreakpointPromptEditAction,
10713        window: &mut Window,
10714        cx: &mut Context<Self>,
10715    ) {
10716        let weak_editor = cx.weak_entity();
10717        let bp_prompt = cx.new(|cx| {
10718            BreakpointPromptEditor::new(
10719                weak_editor,
10720                anchor,
10721                breakpoint.clone(),
10722                edit_action,
10723                window,
10724                cx,
10725            )
10726        });
10727
10728        let height = bp_prompt.update(cx, |this, cx| {
10729            this.prompt
10730                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10731        });
10732        let cloned_prompt = bp_prompt.clone();
10733        let blocks = vec![BlockProperties {
10734            style: BlockStyle::Sticky,
10735            placement: BlockPlacement::Above(anchor),
10736            height: Some(height),
10737            render: Arc::new(move |cx| {
10738                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10739                cloned_prompt.clone().into_any_element()
10740            }),
10741            priority: 0,
10742        }];
10743
10744        let focus_handle = bp_prompt.focus_handle(cx);
10745        window.focus(&focus_handle);
10746
10747        let block_ids = self.insert_blocks(blocks, None, cx);
10748        bp_prompt.update(cx, |prompt, _| {
10749            prompt.add_block_ids(block_ids);
10750        });
10751    }
10752
10753    pub(crate) fn breakpoint_at_row(
10754        &self,
10755        row: u32,
10756        window: &mut Window,
10757        cx: &mut Context<Self>,
10758    ) -> Option<(Anchor, Breakpoint)> {
10759        let snapshot = self.snapshot(window, cx);
10760        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10761
10762        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10763    }
10764
10765    pub(crate) fn breakpoint_at_anchor(
10766        &self,
10767        breakpoint_position: Anchor,
10768        snapshot: &EditorSnapshot,
10769        cx: &mut Context<Self>,
10770    ) -> Option<(Anchor, Breakpoint)> {
10771        let buffer = self
10772            .buffer
10773            .read(cx)
10774            .buffer_for_anchor(breakpoint_position, cx)?;
10775
10776        let enclosing_excerpt = breakpoint_position.excerpt_id;
10777        let buffer_snapshot = buffer.read(cx).snapshot();
10778
10779        let row = buffer_snapshot
10780            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10781            .row;
10782
10783        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10784        let anchor_end = snapshot
10785            .buffer_snapshot
10786            .anchor_after(Point::new(row, line_len));
10787
10788        self.breakpoint_store
10789            .as_ref()?
10790            .read_with(cx, |breakpoint_store, cx| {
10791                breakpoint_store
10792                    .breakpoints(
10793                        &buffer,
10794                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10795                        &buffer_snapshot,
10796                        cx,
10797                    )
10798                    .next()
10799                    .and_then(|(bp, _)| {
10800                        let breakpoint_row = buffer_snapshot
10801                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10802                            .row;
10803
10804                        if breakpoint_row == row {
10805                            snapshot
10806                                .buffer_snapshot
10807                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10808                                .map(|position| (position, bp.bp.clone()))
10809                        } else {
10810                            None
10811                        }
10812                    })
10813            })
10814    }
10815
10816    pub fn edit_log_breakpoint(
10817        &mut self,
10818        _: &EditLogBreakpoint,
10819        window: &mut Window,
10820        cx: &mut Context<Self>,
10821    ) {
10822        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10823            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10824                message: None,
10825                state: BreakpointState::Enabled,
10826                condition: None,
10827                hit_condition: None,
10828            });
10829
10830            self.add_edit_breakpoint_block(
10831                anchor,
10832                &breakpoint,
10833                BreakpointPromptEditAction::Log,
10834                window,
10835                cx,
10836            );
10837        }
10838    }
10839
10840    fn breakpoints_at_cursors(
10841        &self,
10842        window: &mut Window,
10843        cx: &mut Context<Self>,
10844    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10845        let snapshot = self.snapshot(window, cx);
10846        let cursors = self
10847            .selections
10848            .disjoint_anchors()
10849            .iter()
10850            .map(|selection| {
10851                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10852
10853                let breakpoint_position = self
10854                    .breakpoint_at_row(cursor_position.row, window, cx)
10855                    .map(|bp| bp.0)
10856                    .unwrap_or_else(|| {
10857                        snapshot
10858                            .display_snapshot
10859                            .buffer_snapshot
10860                            .anchor_after(Point::new(cursor_position.row, 0))
10861                    });
10862
10863                let breakpoint = self
10864                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10865                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10866
10867                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10868            })
10869            // 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.
10870            .collect::<HashMap<Anchor, _>>();
10871
10872        cursors.into_iter().collect()
10873    }
10874
10875    pub fn enable_breakpoint(
10876        &mut self,
10877        _: &crate::actions::EnableBreakpoint,
10878        window: &mut Window,
10879        cx: &mut Context<Self>,
10880    ) {
10881        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10882            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10883                continue;
10884            };
10885            self.edit_breakpoint_at_anchor(
10886                anchor,
10887                breakpoint,
10888                BreakpointEditAction::InvertState,
10889                cx,
10890            );
10891        }
10892    }
10893
10894    pub fn disable_breakpoint(
10895        &mut self,
10896        _: &crate::actions::DisableBreakpoint,
10897        window: &mut Window,
10898        cx: &mut Context<Self>,
10899    ) {
10900        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10901            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10902                continue;
10903            };
10904            self.edit_breakpoint_at_anchor(
10905                anchor,
10906                breakpoint,
10907                BreakpointEditAction::InvertState,
10908                cx,
10909            );
10910        }
10911    }
10912
10913    pub fn toggle_breakpoint(
10914        &mut self,
10915        _: &crate::actions::ToggleBreakpoint,
10916        window: &mut Window,
10917        cx: &mut Context<Self>,
10918    ) {
10919        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10920            if let Some(breakpoint) = breakpoint {
10921                self.edit_breakpoint_at_anchor(
10922                    anchor,
10923                    breakpoint,
10924                    BreakpointEditAction::Toggle,
10925                    cx,
10926                );
10927            } else {
10928                self.edit_breakpoint_at_anchor(
10929                    anchor,
10930                    Breakpoint::new_standard(),
10931                    BreakpointEditAction::Toggle,
10932                    cx,
10933                );
10934            }
10935        }
10936    }
10937
10938    pub fn edit_breakpoint_at_anchor(
10939        &mut self,
10940        breakpoint_position: Anchor,
10941        breakpoint: Breakpoint,
10942        edit_action: BreakpointEditAction,
10943        cx: &mut Context<Self>,
10944    ) {
10945        let Some(breakpoint_store) = &self.breakpoint_store else {
10946            return;
10947        };
10948
10949        let Some(buffer) = self
10950            .buffer
10951            .read(cx)
10952            .buffer_for_anchor(breakpoint_position, cx)
10953        else {
10954            return;
10955        };
10956
10957        breakpoint_store.update(cx, |breakpoint_store, cx| {
10958            breakpoint_store.toggle_breakpoint(
10959                buffer,
10960                BreakpointWithPosition {
10961                    position: breakpoint_position.text_anchor,
10962                    bp: breakpoint,
10963                },
10964                edit_action,
10965                cx,
10966            );
10967        });
10968
10969        cx.notify();
10970    }
10971
10972    #[cfg(any(test, feature = "test-support"))]
10973    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10974        self.breakpoint_store.clone()
10975    }
10976
10977    pub fn prepare_restore_change(
10978        &self,
10979        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10980        hunk: &MultiBufferDiffHunk,
10981        cx: &mut App,
10982    ) -> Option<()> {
10983        if hunk.is_created_file() {
10984            return None;
10985        }
10986        let buffer = self.buffer.read(cx);
10987        let diff = buffer.diff_for(hunk.buffer_id)?;
10988        let buffer = buffer.buffer(hunk.buffer_id)?;
10989        let buffer = buffer.read(cx);
10990        let original_text = diff
10991            .read(cx)
10992            .base_text()
10993            .as_rope()
10994            .slice(hunk.diff_base_byte_range.clone());
10995        let buffer_snapshot = buffer.snapshot();
10996        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10997        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10998            probe
10999                .0
11000                .start
11001                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11002                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11003        }) {
11004            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11005            Some(())
11006        } else {
11007            None
11008        }
11009    }
11010
11011    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11012        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11013    }
11014
11015    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11016        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11017    }
11018
11019    fn manipulate_lines<M>(
11020        &mut self,
11021        window: &mut Window,
11022        cx: &mut Context<Self>,
11023        mut manipulate: M,
11024    ) where
11025        M: FnMut(&str) -> LineManipulationResult,
11026    {
11027        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11028
11029        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11030        let buffer = self.buffer.read(cx).snapshot(cx);
11031
11032        let mut edits = Vec::new();
11033
11034        let selections = self.selections.all::<Point>(cx);
11035        let mut selections = selections.iter().peekable();
11036        let mut contiguous_row_selections = Vec::new();
11037        let mut new_selections = Vec::new();
11038        let mut added_lines = 0;
11039        let mut removed_lines = 0;
11040
11041        while let Some(selection) = selections.next() {
11042            let (start_row, end_row) = consume_contiguous_rows(
11043                &mut contiguous_row_selections,
11044                selection,
11045                &display_map,
11046                &mut selections,
11047            );
11048
11049            let start_point = Point::new(start_row.0, 0);
11050            let end_point = Point::new(
11051                end_row.previous_row().0,
11052                buffer.line_len(end_row.previous_row()),
11053            );
11054            let text = buffer
11055                .text_for_range(start_point..end_point)
11056                .collect::<String>();
11057
11058            let LineManipulationResult {
11059                new_text,
11060                line_count_before,
11061                line_count_after,
11062            } = manipulate(&text);
11063
11064            edits.push((start_point..end_point, new_text));
11065
11066            // Selections must change based on added and removed line count
11067            let start_row =
11068                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11069            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11070            new_selections.push(Selection {
11071                id: selection.id,
11072                start: start_row,
11073                end: end_row,
11074                goal: SelectionGoal::None,
11075                reversed: selection.reversed,
11076            });
11077
11078            if line_count_after > line_count_before {
11079                added_lines += line_count_after - line_count_before;
11080            } else if line_count_before > line_count_after {
11081                removed_lines += line_count_before - line_count_after;
11082            }
11083        }
11084
11085        self.transact(window, cx, |this, window, cx| {
11086            let buffer = this.buffer.update(cx, |buffer, cx| {
11087                buffer.edit(edits, None, cx);
11088                buffer.snapshot(cx)
11089            });
11090
11091            // Recalculate offsets on newly edited buffer
11092            let new_selections = new_selections
11093                .iter()
11094                .map(|s| {
11095                    let start_point = Point::new(s.start.0, 0);
11096                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11097                    Selection {
11098                        id: s.id,
11099                        start: buffer.point_to_offset(start_point),
11100                        end: buffer.point_to_offset(end_point),
11101                        goal: s.goal,
11102                        reversed: s.reversed,
11103                    }
11104                })
11105                .collect();
11106
11107            this.change_selections(Default::default(), window, cx, |s| {
11108                s.select(new_selections);
11109            });
11110
11111            this.request_autoscroll(Autoscroll::fit(), cx);
11112        });
11113    }
11114
11115    fn manipulate_immutable_lines<Fn>(
11116        &mut self,
11117        window: &mut Window,
11118        cx: &mut Context<Self>,
11119        mut callback: Fn,
11120    ) where
11121        Fn: FnMut(&mut Vec<&str>),
11122    {
11123        self.manipulate_lines(window, cx, |text| {
11124            let mut lines: Vec<&str> = text.split('\n').collect();
11125            let line_count_before = lines.len();
11126
11127            callback(&mut lines);
11128
11129            LineManipulationResult {
11130                new_text: lines.join("\n"),
11131                line_count_before,
11132                line_count_after: lines.len(),
11133            }
11134        });
11135    }
11136
11137    fn manipulate_mutable_lines<Fn>(
11138        &mut self,
11139        window: &mut Window,
11140        cx: &mut Context<Self>,
11141        mut callback: Fn,
11142    ) where
11143        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11144    {
11145        self.manipulate_lines(window, cx, |text| {
11146            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11147            let line_count_before = lines.len();
11148
11149            callback(&mut lines);
11150
11151            LineManipulationResult {
11152                new_text: lines.join("\n"),
11153                line_count_before,
11154                line_count_after: lines.len(),
11155            }
11156        });
11157    }
11158
11159    pub fn convert_indentation_to_spaces(
11160        &mut self,
11161        _: &ConvertIndentationToSpaces,
11162        window: &mut Window,
11163        cx: &mut Context<Self>,
11164    ) {
11165        let settings = self.buffer.read(cx).language_settings(cx);
11166        let tab_size = settings.tab_size.get() as usize;
11167
11168        self.manipulate_mutable_lines(window, cx, |lines| {
11169            // Allocates a reasonably sized scratch buffer once for the whole loop
11170            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11171            // Avoids recomputing spaces that could be inserted many times
11172            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11173                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11174                .collect();
11175
11176            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11177                let mut chars = line.as_ref().chars();
11178                let mut col = 0;
11179                let mut changed = false;
11180
11181                for ch in chars.by_ref() {
11182                    match ch {
11183                        ' ' => {
11184                            reindented_line.push(' ');
11185                            col += 1;
11186                        }
11187                        '\t' => {
11188                            // \t are converted to spaces depending on the current column
11189                            let spaces_len = tab_size - (col % tab_size);
11190                            reindented_line.extend(&space_cache[spaces_len - 1]);
11191                            col += spaces_len;
11192                            changed = true;
11193                        }
11194                        _ => {
11195                            // If we dont append before break, the character is consumed
11196                            reindented_line.push(ch);
11197                            break;
11198                        }
11199                    }
11200                }
11201
11202                if !changed {
11203                    reindented_line.clear();
11204                    continue;
11205                }
11206                // Append the rest of the line and replace old reference with new one
11207                reindented_line.extend(chars);
11208                *line = Cow::Owned(reindented_line.clone());
11209                reindented_line.clear();
11210            }
11211        });
11212    }
11213
11214    pub fn convert_indentation_to_tabs(
11215        &mut self,
11216        _: &ConvertIndentationToTabs,
11217        window: &mut Window,
11218        cx: &mut Context<Self>,
11219    ) {
11220        let settings = self.buffer.read(cx).language_settings(cx);
11221        let tab_size = settings.tab_size.get() as usize;
11222
11223        self.manipulate_mutable_lines(window, cx, |lines| {
11224            // Allocates a reasonably sized buffer once for the whole loop
11225            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11226            // Avoids recomputing spaces that could be inserted many times
11227            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11228                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11229                .collect();
11230
11231            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11232                let mut chars = line.chars();
11233                let mut spaces_count = 0;
11234                let mut first_non_indent_char = None;
11235                let mut changed = false;
11236
11237                for ch in chars.by_ref() {
11238                    match ch {
11239                        ' ' => {
11240                            // Keep track of spaces. Append \t when we reach tab_size
11241                            spaces_count += 1;
11242                            changed = true;
11243                            if spaces_count == tab_size {
11244                                reindented_line.push('\t');
11245                                spaces_count = 0;
11246                            }
11247                        }
11248                        '\t' => {
11249                            reindented_line.push('\t');
11250                            spaces_count = 0;
11251                        }
11252                        _ => {
11253                            // Dont append it yet, we might have remaining spaces
11254                            first_non_indent_char = Some(ch);
11255                            break;
11256                        }
11257                    }
11258                }
11259
11260                if !changed {
11261                    reindented_line.clear();
11262                    continue;
11263                }
11264                // Remaining spaces that didn't make a full tab stop
11265                if spaces_count > 0 {
11266                    reindented_line.extend(&space_cache[spaces_count - 1]);
11267                }
11268                // If we consume an extra character that was not indentation, add it back
11269                if let Some(extra_char) = first_non_indent_char {
11270                    reindented_line.push(extra_char);
11271                }
11272                // Append the rest of the line and replace old reference with new one
11273                reindented_line.extend(chars);
11274                *line = Cow::Owned(reindented_line.clone());
11275                reindented_line.clear();
11276            }
11277        });
11278    }
11279
11280    pub fn convert_to_upper_case(
11281        &mut self,
11282        _: &ConvertToUpperCase,
11283        window: &mut Window,
11284        cx: &mut Context<Self>,
11285    ) {
11286        self.manipulate_text(window, cx, |text| text.to_uppercase())
11287    }
11288
11289    pub fn convert_to_lower_case(
11290        &mut self,
11291        _: &ConvertToLowerCase,
11292        window: &mut Window,
11293        cx: &mut Context<Self>,
11294    ) {
11295        self.manipulate_text(window, cx, |text| text.to_lowercase())
11296    }
11297
11298    pub fn convert_to_title_case(
11299        &mut self,
11300        _: &ConvertToTitleCase,
11301        window: &mut Window,
11302        cx: &mut Context<Self>,
11303    ) {
11304        self.manipulate_text(window, cx, |text| {
11305            text.split('\n')
11306                .map(|line| line.to_case(Case::Title))
11307                .join("\n")
11308        })
11309    }
11310
11311    pub fn convert_to_snake_case(
11312        &mut self,
11313        _: &ConvertToSnakeCase,
11314        window: &mut Window,
11315        cx: &mut Context<Self>,
11316    ) {
11317        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11318    }
11319
11320    pub fn convert_to_kebab_case(
11321        &mut self,
11322        _: &ConvertToKebabCase,
11323        window: &mut Window,
11324        cx: &mut Context<Self>,
11325    ) {
11326        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11327    }
11328
11329    pub fn convert_to_upper_camel_case(
11330        &mut self,
11331        _: &ConvertToUpperCamelCase,
11332        window: &mut Window,
11333        cx: &mut Context<Self>,
11334    ) {
11335        self.manipulate_text(window, cx, |text| {
11336            text.split('\n')
11337                .map(|line| line.to_case(Case::UpperCamel))
11338                .join("\n")
11339        })
11340    }
11341
11342    pub fn convert_to_lower_camel_case(
11343        &mut self,
11344        _: &ConvertToLowerCamelCase,
11345        window: &mut Window,
11346        cx: &mut Context<Self>,
11347    ) {
11348        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11349    }
11350
11351    pub fn convert_to_opposite_case(
11352        &mut self,
11353        _: &ConvertToOppositeCase,
11354        window: &mut Window,
11355        cx: &mut Context<Self>,
11356    ) {
11357        self.manipulate_text(window, cx, |text| {
11358            text.chars()
11359                .fold(String::with_capacity(text.len()), |mut t, c| {
11360                    if c.is_uppercase() {
11361                        t.extend(c.to_lowercase());
11362                    } else {
11363                        t.extend(c.to_uppercase());
11364                    }
11365                    t
11366                })
11367        })
11368    }
11369
11370    pub fn convert_to_sentence_case(
11371        &mut self,
11372        _: &ConvertToSentenceCase,
11373        window: &mut Window,
11374        cx: &mut Context<Self>,
11375    ) {
11376        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11377    }
11378
11379    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11380        self.manipulate_text(window, cx, |text| {
11381            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11382            if has_upper_case_characters {
11383                text.to_lowercase()
11384            } else {
11385                text.to_uppercase()
11386            }
11387        })
11388    }
11389
11390    pub fn convert_to_rot13(
11391        &mut self,
11392        _: &ConvertToRot13,
11393        window: &mut Window,
11394        cx: &mut Context<Self>,
11395    ) {
11396        self.manipulate_text(window, cx, |text| {
11397            text.chars()
11398                .map(|c| match c {
11399                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11400                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11401                    _ => c,
11402                })
11403                .collect()
11404        })
11405    }
11406
11407    pub fn convert_to_rot47(
11408        &mut self,
11409        _: &ConvertToRot47,
11410        window: &mut Window,
11411        cx: &mut Context<Self>,
11412    ) {
11413        self.manipulate_text(window, cx, |text| {
11414            text.chars()
11415                .map(|c| {
11416                    let code_point = c as u32;
11417                    if code_point >= 33 && code_point <= 126 {
11418                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11419                    }
11420                    c
11421                })
11422                .collect()
11423        })
11424    }
11425
11426    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11427    where
11428        Fn: FnMut(&str) -> String,
11429    {
11430        let buffer = self.buffer.read(cx).snapshot(cx);
11431
11432        let mut new_selections = Vec::new();
11433        let mut edits = Vec::new();
11434        let mut selection_adjustment = 0i32;
11435
11436        for selection in self.selections.all_adjusted(cx) {
11437            let selection_is_empty = selection.is_empty();
11438
11439            let (start, end) = if selection_is_empty {
11440                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11441                (word_range.start, word_range.end)
11442            } else {
11443                (
11444                    buffer.point_to_offset(selection.start),
11445                    buffer.point_to_offset(selection.end),
11446                )
11447            };
11448
11449            let text = buffer.text_for_range(start..end).collect::<String>();
11450            let old_length = text.len() as i32;
11451            let text = callback(&text);
11452
11453            new_selections.push(Selection {
11454                start: (start as i32 - selection_adjustment) as usize,
11455                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11456                goal: SelectionGoal::None,
11457                id: selection.id,
11458                reversed: selection.reversed,
11459            });
11460
11461            selection_adjustment += old_length - text.len() as i32;
11462
11463            edits.push((start..end, text));
11464        }
11465
11466        self.transact(window, cx, |this, window, cx| {
11467            this.buffer.update(cx, |buffer, cx| {
11468                buffer.edit(edits, None, cx);
11469            });
11470
11471            this.change_selections(Default::default(), window, cx, |s| {
11472                s.select(new_selections);
11473            });
11474
11475            this.request_autoscroll(Autoscroll::fit(), cx);
11476        });
11477    }
11478
11479    pub fn move_selection_on_drop(
11480        &mut self,
11481        selection: &Selection<Anchor>,
11482        target: DisplayPoint,
11483        is_cut: bool,
11484        window: &mut Window,
11485        cx: &mut Context<Self>,
11486    ) {
11487        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11488        let buffer = &display_map.buffer_snapshot;
11489        let mut edits = Vec::new();
11490        let insert_point = display_map
11491            .clip_point(target, Bias::Left)
11492            .to_point(&display_map);
11493        let text = buffer
11494            .text_for_range(selection.start..selection.end)
11495            .collect::<String>();
11496        if is_cut {
11497            edits.push(((selection.start..selection.end), String::new()));
11498        }
11499        let insert_anchor = buffer.anchor_before(insert_point);
11500        edits.push(((insert_anchor..insert_anchor), text));
11501        let last_edit_start = insert_anchor.bias_left(buffer);
11502        let last_edit_end = insert_anchor.bias_right(buffer);
11503        self.transact(window, cx, |this, window, cx| {
11504            this.buffer.update(cx, |buffer, cx| {
11505                buffer.edit(edits, None, cx);
11506            });
11507            this.change_selections(Default::default(), window, cx, |s| {
11508                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11509            });
11510        });
11511    }
11512
11513    pub fn clear_selection_drag_state(&mut self) {
11514        self.selection_drag_state = SelectionDragState::None;
11515    }
11516
11517    pub fn duplicate(
11518        &mut self,
11519        upwards: bool,
11520        whole_lines: bool,
11521        window: &mut Window,
11522        cx: &mut Context<Self>,
11523    ) {
11524        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11525
11526        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11527        let buffer = &display_map.buffer_snapshot;
11528        let selections = self.selections.all::<Point>(cx);
11529
11530        let mut edits = Vec::new();
11531        let mut selections_iter = selections.iter().peekable();
11532        while let Some(selection) = selections_iter.next() {
11533            let mut rows = selection.spanned_rows(false, &display_map);
11534            // duplicate line-wise
11535            if whole_lines || selection.start == selection.end {
11536                // Avoid duplicating the same lines twice.
11537                while let Some(next_selection) = selections_iter.peek() {
11538                    let next_rows = next_selection.spanned_rows(false, &display_map);
11539                    if next_rows.start < rows.end {
11540                        rows.end = next_rows.end;
11541                        selections_iter.next().unwrap();
11542                    } else {
11543                        break;
11544                    }
11545                }
11546
11547                // Copy the text from the selected row region and splice it either at the start
11548                // or end of the region.
11549                let start = Point::new(rows.start.0, 0);
11550                let end = Point::new(
11551                    rows.end.previous_row().0,
11552                    buffer.line_len(rows.end.previous_row()),
11553                );
11554                let text = buffer
11555                    .text_for_range(start..end)
11556                    .chain(Some("\n"))
11557                    .collect::<String>();
11558                let insert_location = if upwards {
11559                    Point::new(rows.end.0, 0)
11560                } else {
11561                    start
11562                };
11563                edits.push((insert_location..insert_location, text));
11564            } else {
11565                // duplicate character-wise
11566                let start = selection.start;
11567                let end = selection.end;
11568                let text = buffer.text_for_range(start..end).collect::<String>();
11569                edits.push((selection.end..selection.end, text));
11570            }
11571        }
11572
11573        self.transact(window, cx, |this, _, cx| {
11574            this.buffer.update(cx, |buffer, cx| {
11575                buffer.edit(edits, None, cx);
11576            });
11577
11578            this.request_autoscroll(Autoscroll::fit(), cx);
11579        });
11580    }
11581
11582    pub fn duplicate_line_up(
11583        &mut self,
11584        _: &DuplicateLineUp,
11585        window: &mut Window,
11586        cx: &mut Context<Self>,
11587    ) {
11588        self.duplicate(true, true, window, cx);
11589    }
11590
11591    pub fn duplicate_line_down(
11592        &mut self,
11593        _: &DuplicateLineDown,
11594        window: &mut Window,
11595        cx: &mut Context<Self>,
11596    ) {
11597        self.duplicate(false, true, window, cx);
11598    }
11599
11600    pub fn duplicate_selection(
11601        &mut self,
11602        _: &DuplicateSelection,
11603        window: &mut Window,
11604        cx: &mut Context<Self>,
11605    ) {
11606        self.duplicate(false, false, window, cx);
11607    }
11608
11609    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11610        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11611        if self.mode.is_single_line() {
11612            cx.propagate();
11613            return;
11614        }
11615
11616        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11617        let buffer = self.buffer.read(cx).snapshot(cx);
11618
11619        let mut edits = Vec::new();
11620        let mut unfold_ranges = Vec::new();
11621        let mut refold_creases = Vec::new();
11622
11623        let selections = self.selections.all::<Point>(cx);
11624        let mut selections = selections.iter().peekable();
11625        let mut contiguous_row_selections = Vec::new();
11626        let mut new_selections = Vec::new();
11627
11628        while let Some(selection) = selections.next() {
11629            // Find all the selections that span a contiguous row range
11630            let (start_row, end_row) = consume_contiguous_rows(
11631                &mut contiguous_row_selections,
11632                selection,
11633                &display_map,
11634                &mut selections,
11635            );
11636
11637            // Move the text spanned by the row range to be before the line preceding the row range
11638            if start_row.0 > 0 {
11639                let range_to_move = Point::new(
11640                    start_row.previous_row().0,
11641                    buffer.line_len(start_row.previous_row()),
11642                )
11643                    ..Point::new(
11644                        end_row.previous_row().0,
11645                        buffer.line_len(end_row.previous_row()),
11646                    );
11647                let insertion_point = display_map
11648                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11649                    .0;
11650
11651                // Don't move lines across excerpts
11652                if buffer
11653                    .excerpt_containing(insertion_point..range_to_move.end)
11654                    .is_some()
11655                {
11656                    let text = buffer
11657                        .text_for_range(range_to_move.clone())
11658                        .flat_map(|s| s.chars())
11659                        .skip(1)
11660                        .chain(['\n'])
11661                        .collect::<String>();
11662
11663                    edits.push((
11664                        buffer.anchor_after(range_to_move.start)
11665                            ..buffer.anchor_before(range_to_move.end),
11666                        String::new(),
11667                    ));
11668                    let insertion_anchor = buffer.anchor_after(insertion_point);
11669                    edits.push((insertion_anchor..insertion_anchor, text));
11670
11671                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11672
11673                    // Move selections up
11674                    new_selections.extend(contiguous_row_selections.drain(..).map(
11675                        |mut selection| {
11676                            selection.start.row -= row_delta;
11677                            selection.end.row -= row_delta;
11678                            selection
11679                        },
11680                    ));
11681
11682                    // Move folds up
11683                    unfold_ranges.push(range_to_move.clone());
11684                    for fold in display_map.folds_in_range(
11685                        buffer.anchor_before(range_to_move.start)
11686                            ..buffer.anchor_after(range_to_move.end),
11687                    ) {
11688                        let mut start = fold.range.start.to_point(&buffer);
11689                        let mut end = fold.range.end.to_point(&buffer);
11690                        start.row -= row_delta;
11691                        end.row -= row_delta;
11692                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11693                    }
11694                }
11695            }
11696
11697            // If we didn't move line(s), preserve the existing selections
11698            new_selections.append(&mut contiguous_row_selections);
11699        }
11700
11701        self.transact(window, cx, |this, window, cx| {
11702            this.unfold_ranges(&unfold_ranges, true, true, cx);
11703            this.buffer.update(cx, |buffer, cx| {
11704                for (range, text) in edits {
11705                    buffer.edit([(range, text)], None, cx);
11706                }
11707            });
11708            this.fold_creases(refold_creases, true, window, cx);
11709            this.change_selections(Default::default(), window, cx, |s| {
11710                s.select(new_selections);
11711            })
11712        });
11713    }
11714
11715    pub fn move_line_down(
11716        &mut self,
11717        _: &MoveLineDown,
11718        window: &mut Window,
11719        cx: &mut Context<Self>,
11720    ) {
11721        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11722        if self.mode.is_single_line() {
11723            cx.propagate();
11724            return;
11725        }
11726
11727        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11728        let buffer = self.buffer.read(cx).snapshot(cx);
11729
11730        let mut edits = Vec::new();
11731        let mut unfold_ranges = Vec::new();
11732        let mut refold_creases = Vec::new();
11733
11734        let selections = self.selections.all::<Point>(cx);
11735        let mut selections = selections.iter().peekable();
11736        let mut contiguous_row_selections = Vec::new();
11737        let mut new_selections = Vec::new();
11738
11739        while let Some(selection) = selections.next() {
11740            // Find all the selections that span a contiguous row range
11741            let (start_row, end_row) = consume_contiguous_rows(
11742                &mut contiguous_row_selections,
11743                selection,
11744                &display_map,
11745                &mut selections,
11746            );
11747
11748            // Move the text spanned by the row range to be after the last line of the row range
11749            if end_row.0 <= buffer.max_point().row {
11750                let range_to_move =
11751                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11752                let insertion_point = display_map
11753                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11754                    .0;
11755
11756                // Don't move lines across excerpt boundaries
11757                if buffer
11758                    .excerpt_containing(range_to_move.start..insertion_point)
11759                    .is_some()
11760                {
11761                    let mut text = String::from("\n");
11762                    text.extend(buffer.text_for_range(range_to_move.clone()));
11763                    text.pop(); // Drop trailing newline
11764                    edits.push((
11765                        buffer.anchor_after(range_to_move.start)
11766                            ..buffer.anchor_before(range_to_move.end),
11767                        String::new(),
11768                    ));
11769                    let insertion_anchor = buffer.anchor_after(insertion_point);
11770                    edits.push((insertion_anchor..insertion_anchor, text));
11771
11772                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11773
11774                    // Move selections down
11775                    new_selections.extend(contiguous_row_selections.drain(..).map(
11776                        |mut selection| {
11777                            selection.start.row += row_delta;
11778                            selection.end.row += row_delta;
11779                            selection
11780                        },
11781                    ));
11782
11783                    // Move folds down
11784                    unfold_ranges.push(range_to_move.clone());
11785                    for fold in display_map.folds_in_range(
11786                        buffer.anchor_before(range_to_move.start)
11787                            ..buffer.anchor_after(range_to_move.end),
11788                    ) {
11789                        let mut start = fold.range.start.to_point(&buffer);
11790                        let mut end = fold.range.end.to_point(&buffer);
11791                        start.row += row_delta;
11792                        end.row += row_delta;
11793                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11794                    }
11795                }
11796            }
11797
11798            // If we didn't move line(s), preserve the existing selections
11799            new_selections.append(&mut contiguous_row_selections);
11800        }
11801
11802        self.transact(window, cx, |this, window, cx| {
11803            this.unfold_ranges(&unfold_ranges, true, true, cx);
11804            this.buffer.update(cx, |buffer, cx| {
11805                for (range, text) in edits {
11806                    buffer.edit([(range, text)], None, cx);
11807                }
11808            });
11809            this.fold_creases(refold_creases, true, window, cx);
11810            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11811        });
11812    }
11813
11814    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11815        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11816        let text_layout_details = &self.text_layout_details(window);
11817        self.transact(window, cx, |this, window, cx| {
11818            let edits = this.change_selections(Default::default(), window, cx, |s| {
11819                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11820                s.move_with(|display_map, selection| {
11821                    if !selection.is_empty() {
11822                        return;
11823                    }
11824
11825                    let mut head = selection.head();
11826                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11827                    if head.column() == display_map.line_len(head.row()) {
11828                        transpose_offset = display_map
11829                            .buffer_snapshot
11830                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11831                    }
11832
11833                    if transpose_offset == 0 {
11834                        return;
11835                    }
11836
11837                    *head.column_mut() += 1;
11838                    head = display_map.clip_point(head, Bias::Right);
11839                    let goal = SelectionGoal::HorizontalPosition(
11840                        display_map
11841                            .x_for_display_point(head, text_layout_details)
11842                            .into(),
11843                    );
11844                    selection.collapse_to(head, goal);
11845
11846                    let transpose_start = display_map
11847                        .buffer_snapshot
11848                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11849                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11850                        let transpose_end = display_map
11851                            .buffer_snapshot
11852                            .clip_offset(transpose_offset + 1, Bias::Right);
11853                        if let Some(ch) =
11854                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11855                        {
11856                            edits.push((transpose_start..transpose_offset, String::new()));
11857                            edits.push((transpose_end..transpose_end, ch.to_string()));
11858                        }
11859                    }
11860                });
11861                edits
11862            });
11863            this.buffer
11864                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11865            let selections = this.selections.all::<usize>(cx);
11866            this.change_selections(Default::default(), window, cx, |s| {
11867                s.select(selections);
11868            });
11869        });
11870    }
11871
11872    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11873        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11874        if self.mode.is_single_line() {
11875            cx.propagate();
11876            return;
11877        }
11878
11879        self.rewrap_impl(RewrapOptions::default(), cx)
11880    }
11881
11882    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11883        let buffer = self.buffer.read(cx).snapshot(cx);
11884        let selections = self.selections.all::<Point>(cx);
11885
11886        #[derive(Clone, Debug, PartialEq)]
11887        enum CommentFormat {
11888            /// single line comment, with prefix for line
11889            Line(String),
11890            /// single line within a block comment, with prefix for line
11891            BlockLine(String),
11892            /// a single line of a block comment that includes the initial delimiter
11893            BlockCommentWithStart(BlockCommentConfig),
11894            /// a single line of a block comment that includes the ending delimiter
11895            BlockCommentWithEnd(BlockCommentConfig),
11896        }
11897
11898        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11899        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11900            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11901                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11902                .peekable();
11903
11904            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11905                row
11906            } else {
11907                return Vec::new();
11908            };
11909
11910            let language_settings = buffer.language_settings_at(selection.head(), cx);
11911            let language_scope = buffer.language_scope_at(selection.head());
11912
11913            let indent_and_prefix_for_row =
11914                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11915                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11916                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11917                        &language_scope
11918                    {
11919                        let indent_end = Point::new(row, indent.len);
11920                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11921                        let line_text_after_indent = buffer
11922                            .text_for_range(indent_end..line_end)
11923                            .collect::<String>();
11924
11925                        let is_within_comment_override = buffer
11926                            .language_scope_at(indent_end)
11927                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11928                        let comment_delimiters = if is_within_comment_override {
11929                            // we are within a comment syntax node, but we don't
11930                            // yet know what kind of comment: block, doc or line
11931                            match (
11932                                language_scope.documentation_comment(),
11933                                language_scope.block_comment(),
11934                            ) {
11935                                (Some(config), _) | (_, Some(config))
11936                                    if buffer.contains_str_at(indent_end, &config.start) =>
11937                                {
11938                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11939                                }
11940                                (Some(config), _) | (_, Some(config))
11941                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11942                                {
11943                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11944                                }
11945                                (Some(config), _) | (_, Some(config))
11946                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11947                                {
11948                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11949                                }
11950                                (_, _) => language_scope
11951                                    .line_comment_prefixes()
11952                                    .iter()
11953                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11954                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11955                            }
11956                        } else {
11957                            // we not in an overridden comment node, but we may
11958                            // be within a non-overridden line comment node
11959                            language_scope
11960                                .line_comment_prefixes()
11961                                .iter()
11962                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11963                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11964                        };
11965
11966                        let rewrap_prefix = language_scope
11967                            .rewrap_prefixes()
11968                            .iter()
11969                            .find_map(|prefix_regex| {
11970                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11971                                    if mat.start() == 0 {
11972                                        Some(mat.as_str().to_string())
11973                                    } else {
11974                                        None
11975                                    }
11976                                })
11977                            })
11978                            .flatten();
11979                        (comment_delimiters, rewrap_prefix)
11980                    } else {
11981                        (None, None)
11982                    };
11983                    (indent, comment_prefix, rewrap_prefix)
11984                };
11985
11986            let mut ranges = Vec::new();
11987            let from_empty_selection = selection.is_empty();
11988
11989            let mut current_range_start = first_row;
11990            let mut prev_row = first_row;
11991            let (
11992                mut current_range_indent,
11993                mut current_range_comment_delimiters,
11994                mut current_range_rewrap_prefix,
11995            ) = indent_and_prefix_for_row(first_row);
11996
11997            for row in non_blank_rows_iter.skip(1) {
11998                let has_paragraph_break = row > prev_row + 1;
11999
12000                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12001                    indent_and_prefix_for_row(row);
12002
12003                let has_indent_change = row_indent != current_range_indent;
12004                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12005
12006                let has_boundary_change = has_comment_change
12007                    || row_rewrap_prefix.is_some()
12008                    || (has_indent_change && current_range_comment_delimiters.is_some());
12009
12010                if has_paragraph_break || has_boundary_change {
12011                    ranges.push((
12012                        language_settings.clone(),
12013                        Point::new(current_range_start, 0)
12014                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12015                        current_range_indent,
12016                        current_range_comment_delimiters.clone(),
12017                        current_range_rewrap_prefix.clone(),
12018                        from_empty_selection,
12019                    ));
12020                    current_range_start = row;
12021                    current_range_indent = row_indent;
12022                    current_range_comment_delimiters = row_comment_delimiters;
12023                    current_range_rewrap_prefix = row_rewrap_prefix;
12024                }
12025                prev_row = row;
12026            }
12027
12028            ranges.push((
12029                language_settings.clone(),
12030                Point::new(current_range_start, 0)
12031                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12032                current_range_indent,
12033                current_range_comment_delimiters,
12034                current_range_rewrap_prefix,
12035                from_empty_selection,
12036            ));
12037
12038            ranges
12039        });
12040
12041        let mut edits = Vec::new();
12042        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12043
12044        for (
12045            language_settings,
12046            wrap_range,
12047            mut indent_size,
12048            comment_prefix,
12049            rewrap_prefix,
12050            from_empty_selection,
12051        ) in wrap_ranges
12052        {
12053            let mut start_row = wrap_range.start.row;
12054            let mut end_row = wrap_range.end.row;
12055
12056            // Skip selections that overlap with a range that has already been rewrapped.
12057            let selection_range = start_row..end_row;
12058            if rewrapped_row_ranges
12059                .iter()
12060                .any(|range| range.overlaps(&selection_range))
12061            {
12062                continue;
12063            }
12064
12065            let tab_size = language_settings.tab_size;
12066
12067            let (line_prefix, inside_comment) = match &comment_prefix {
12068                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12069                    (Some(prefix.as_str()), true)
12070                }
12071                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12072                    (Some(prefix.as_ref()), true)
12073                }
12074                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12075                    start: _,
12076                    end: _,
12077                    prefix,
12078                    tab_size,
12079                })) => {
12080                    indent_size.len += tab_size;
12081                    (Some(prefix.as_ref()), true)
12082                }
12083                None => (None, false),
12084            };
12085            let indent_prefix = indent_size.chars().collect::<String>();
12086            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12087
12088            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12089                RewrapBehavior::InComments => inside_comment,
12090                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12091                RewrapBehavior::Anywhere => true,
12092            };
12093
12094            let should_rewrap = options.override_language_settings
12095                || allow_rewrap_based_on_language
12096                || self.hard_wrap.is_some();
12097            if !should_rewrap {
12098                continue;
12099            }
12100
12101            if from_empty_selection {
12102                'expand_upwards: while start_row > 0 {
12103                    let prev_row = start_row - 1;
12104                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12105                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12106                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12107                    {
12108                        start_row = prev_row;
12109                    } else {
12110                        break 'expand_upwards;
12111                    }
12112                }
12113
12114                'expand_downwards: while end_row < buffer.max_point().row {
12115                    let next_row = end_row + 1;
12116                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12117                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12118                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12119                    {
12120                        end_row = next_row;
12121                    } else {
12122                        break 'expand_downwards;
12123                    }
12124                }
12125            }
12126
12127            let start = Point::new(start_row, 0);
12128            let start_offset = start.to_offset(&buffer);
12129            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12130            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12131            let mut first_line_delimiter = None;
12132            let mut last_line_delimiter = None;
12133            let Some(lines_without_prefixes) = selection_text
12134                .lines()
12135                .enumerate()
12136                .map(|(ix, line)| {
12137                    let line_trimmed = line.trim_start();
12138                    if rewrap_prefix.is_some() && ix > 0 {
12139                        Ok(line_trimmed)
12140                    } else if let Some(
12141                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12142                            start,
12143                            prefix,
12144                            end,
12145                            tab_size,
12146                        })
12147                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12148                            start,
12149                            prefix,
12150                            end,
12151                            tab_size,
12152                        }),
12153                    ) = &comment_prefix
12154                    {
12155                        let line_trimmed = line_trimmed
12156                            .strip_prefix(start.as_ref())
12157                            .map(|s| {
12158                                let mut indent_size = indent_size;
12159                                indent_size.len -= tab_size;
12160                                let indent_prefix: String = indent_size.chars().collect();
12161                                first_line_delimiter = Some((indent_prefix, start));
12162                                s.trim_start()
12163                            })
12164                            .unwrap_or(line_trimmed);
12165                        let line_trimmed = line_trimmed
12166                            .strip_suffix(end.as_ref())
12167                            .map(|s| {
12168                                last_line_delimiter = Some(end);
12169                                s.trim_end()
12170                            })
12171                            .unwrap_or(line_trimmed);
12172                        let line_trimmed = line_trimmed
12173                            .strip_prefix(prefix.as_ref())
12174                            .unwrap_or(line_trimmed);
12175                        Ok(line_trimmed)
12176                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12177                        line_trimmed.strip_prefix(prefix).with_context(|| {
12178                            format!("line did not start with prefix {prefix:?}: {line:?}")
12179                        })
12180                    } else {
12181                        line_trimmed
12182                            .strip_prefix(&line_prefix.trim_start())
12183                            .with_context(|| {
12184                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12185                            })
12186                    }
12187                })
12188                .collect::<Result<Vec<_>, _>>()
12189                .log_err()
12190            else {
12191                continue;
12192            };
12193
12194            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12195                buffer
12196                    .language_settings_at(Point::new(start_row, 0), cx)
12197                    .preferred_line_length as usize
12198            });
12199
12200            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12201                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12202            } else {
12203                line_prefix.clone()
12204            };
12205
12206            let wrapped_text = {
12207                let mut wrapped_text = wrap_with_prefix(
12208                    line_prefix,
12209                    subsequent_lines_prefix,
12210                    lines_without_prefixes.join("\n"),
12211                    wrap_column,
12212                    tab_size,
12213                    options.preserve_existing_whitespace,
12214                );
12215
12216                if let Some((indent, delimiter)) = first_line_delimiter {
12217                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12218                }
12219                if let Some(last_line) = last_line_delimiter {
12220                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12221                }
12222
12223                wrapped_text
12224            };
12225
12226            // TODO: should always use char-based diff while still supporting cursor behavior that
12227            // matches vim.
12228            let mut diff_options = DiffOptions::default();
12229            if options.override_language_settings {
12230                diff_options.max_word_diff_len = 0;
12231                diff_options.max_word_diff_line_count = 0;
12232            } else {
12233                diff_options.max_word_diff_len = usize::MAX;
12234                diff_options.max_word_diff_line_count = usize::MAX;
12235            }
12236
12237            for (old_range, new_text) in
12238                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12239            {
12240                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12241                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12242                edits.push((edit_start..edit_end, new_text));
12243            }
12244
12245            rewrapped_row_ranges.push(start_row..=end_row);
12246        }
12247
12248        self.buffer
12249            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12250    }
12251
12252    pub fn cut_common(
12253        &mut self,
12254        cut_no_selection_line: bool,
12255        window: &mut Window,
12256        cx: &mut Context<Self>,
12257    ) -> ClipboardItem {
12258        let mut text = String::new();
12259        let buffer = self.buffer.read(cx).snapshot(cx);
12260        let mut selections = self.selections.all::<Point>(cx);
12261        let mut clipboard_selections = Vec::with_capacity(selections.len());
12262        {
12263            let max_point = buffer.max_point();
12264            let mut is_first = true;
12265            for selection in &mut selections {
12266                let is_entire_line =
12267                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode;
12268                if is_entire_line {
12269                    selection.start = Point::new(selection.start.row, 0);
12270                    if !selection.is_empty() && selection.end.column == 0 {
12271                        selection.end = cmp::min(max_point, selection.end);
12272                    } else {
12273                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12274                    }
12275                    selection.goal = SelectionGoal::None;
12276                }
12277                if is_first {
12278                    is_first = false;
12279                } else {
12280                    text += "\n";
12281                }
12282                let mut len = 0;
12283                for chunk in buffer.text_for_range(selection.start..selection.end) {
12284                    text.push_str(chunk);
12285                    len += chunk.len();
12286                }
12287                clipboard_selections.push(ClipboardSelection {
12288                    len,
12289                    is_entire_line,
12290                    first_line_indent: buffer
12291                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12292                        .len,
12293                });
12294            }
12295        }
12296
12297        self.transact(window, cx, |this, window, cx| {
12298            this.change_selections(Default::default(), window, cx, |s| {
12299                s.select(selections);
12300            });
12301            this.insert("", window, cx);
12302        });
12303        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12304    }
12305
12306    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12307        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12308        let item = self.cut_common(true, window, cx);
12309        cx.write_to_clipboard(item);
12310    }
12311
12312    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12313        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12314        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12315            s.move_with(|snapshot, sel| {
12316                if sel.is_empty() {
12317                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12318                }
12319                if sel.is_empty() {
12320                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12321                }
12322            });
12323        });
12324        let item = self.cut_common(true, window, cx);
12325        cx.set_global(KillRing(item))
12326    }
12327
12328    pub fn kill_ring_yank(
12329        &mut self,
12330        _: &KillRingYank,
12331        window: &mut Window,
12332        cx: &mut Context<Self>,
12333    ) {
12334        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12335        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12336            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12337                (kill_ring.text().to_string(), kill_ring.metadata_json())
12338            } else {
12339                return;
12340            }
12341        } else {
12342            return;
12343        };
12344        self.do_paste(&text, metadata, false, window, cx);
12345    }
12346
12347    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12348        self.do_copy(true, cx);
12349    }
12350
12351    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12352        self.do_copy(false, cx);
12353    }
12354
12355    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12356        let selections = self.selections.all::<Point>(cx);
12357        let buffer = self.buffer.read(cx).read(cx);
12358        let mut text = String::new();
12359
12360        let mut clipboard_selections = Vec::with_capacity(selections.len());
12361        {
12362            let max_point = buffer.max_point();
12363            let mut is_first = true;
12364            for selection in &selections {
12365                let mut start = selection.start;
12366                let mut end = selection.end;
12367                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12368                if is_entire_line {
12369                    start = Point::new(start.row, 0);
12370                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12371                }
12372
12373                let mut trimmed_selections = Vec::new();
12374                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12375                    let row = MultiBufferRow(start.row);
12376                    let first_indent = buffer.indent_size_for_line(row);
12377                    if first_indent.len == 0 || start.column > first_indent.len {
12378                        trimmed_selections.push(start..end);
12379                    } else {
12380                        trimmed_selections.push(
12381                            Point::new(row.0, first_indent.len)
12382                                ..Point::new(row.0, buffer.line_len(row)),
12383                        );
12384                        for row in start.row + 1..=end.row {
12385                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12386                            if row == end.row {
12387                                line_len = end.column;
12388                            }
12389                            if line_len == 0 {
12390                                trimmed_selections
12391                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12392                                continue;
12393                            }
12394                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12395                            if row_indent_size.len >= first_indent.len {
12396                                trimmed_selections.push(
12397                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12398                                );
12399                            } else {
12400                                trimmed_selections.clear();
12401                                trimmed_selections.push(start..end);
12402                                break;
12403                            }
12404                        }
12405                    }
12406                } else {
12407                    trimmed_selections.push(start..end);
12408                }
12409
12410                for trimmed_range in trimmed_selections {
12411                    if is_first {
12412                        is_first = false;
12413                    } else {
12414                        text += "\n";
12415                    }
12416                    let mut len = 0;
12417                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12418                        text.push_str(chunk);
12419                        len += chunk.len();
12420                    }
12421                    clipboard_selections.push(ClipboardSelection {
12422                        len,
12423                        is_entire_line,
12424                        first_line_indent: buffer
12425                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12426                            .len,
12427                    });
12428                }
12429            }
12430        }
12431
12432        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12433            text,
12434            clipboard_selections,
12435        ));
12436    }
12437
12438    pub fn do_paste(
12439        &mut self,
12440        text: &String,
12441        clipboard_selections: Option<Vec<ClipboardSelection>>,
12442        handle_entire_lines: bool,
12443        window: &mut Window,
12444        cx: &mut Context<Self>,
12445    ) {
12446        if self.read_only(cx) {
12447            return;
12448        }
12449
12450        let clipboard_text = Cow::Borrowed(text);
12451
12452        self.transact(window, cx, |this, window, cx| {
12453            let had_active_edit_prediction = this.has_active_edit_prediction();
12454
12455            if let Some(mut clipboard_selections) = clipboard_selections {
12456                let old_selections = this.selections.all::<usize>(cx);
12457                let all_selections_were_entire_line =
12458                    clipboard_selections.iter().all(|s| s.is_entire_line);
12459                let first_selection_indent_column =
12460                    clipboard_selections.first().map(|s| s.first_line_indent);
12461                if clipboard_selections.len() != old_selections.len() {
12462                    clipboard_selections.drain(..);
12463                }
12464                let cursor_offset = this.selections.last::<usize>(cx).head();
12465                let mut auto_indent_on_paste = true;
12466
12467                this.buffer.update(cx, |buffer, cx| {
12468                    let snapshot = buffer.read(cx);
12469                    auto_indent_on_paste = snapshot
12470                        .language_settings_at(cursor_offset, cx)
12471                        .auto_indent_on_paste;
12472
12473                    let mut start_offset = 0;
12474                    let mut edits = Vec::new();
12475                    let mut original_indent_columns = Vec::new();
12476                    for (ix, selection) in old_selections.iter().enumerate() {
12477                        let to_insert;
12478                        let entire_line;
12479                        let original_indent_column;
12480                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12481                            let end_offset = start_offset + clipboard_selection.len;
12482                            to_insert = &clipboard_text[start_offset..end_offset];
12483                            entire_line = clipboard_selection.is_entire_line;
12484                            start_offset = end_offset + 1;
12485                            original_indent_column = Some(clipboard_selection.first_line_indent);
12486                        } else {
12487                            to_insert = clipboard_text.as_str();
12488                            entire_line = all_selections_were_entire_line;
12489                            original_indent_column = first_selection_indent_column
12490                        }
12491
12492                        // If the corresponding selection was empty when this slice of the
12493                        // clipboard text was written, then the entire line containing the
12494                        // selection was copied. If this selection is also currently empty,
12495                        // then paste the line before the current line of the buffer.
12496                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12497                            let column = selection.start.to_point(&snapshot).column as usize;
12498                            let line_start = selection.start - column;
12499                            line_start..line_start
12500                        } else {
12501                            selection.range()
12502                        };
12503
12504                        edits.push((range, to_insert));
12505                        original_indent_columns.push(original_indent_column);
12506                    }
12507                    drop(snapshot);
12508
12509                    buffer.edit(
12510                        edits,
12511                        if auto_indent_on_paste {
12512                            Some(AutoindentMode::Block {
12513                                original_indent_columns,
12514                            })
12515                        } else {
12516                            None
12517                        },
12518                        cx,
12519                    );
12520                });
12521
12522                let selections = this.selections.all::<usize>(cx);
12523                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12524            } else {
12525                this.insert(&clipboard_text, window, cx);
12526            }
12527
12528            let trigger_in_words =
12529                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12530
12531            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12532        });
12533    }
12534
12535    pub fn diff_clipboard_with_selection(
12536        &mut self,
12537        _: &DiffClipboardWithSelection,
12538        window: &mut Window,
12539        cx: &mut Context<Self>,
12540    ) {
12541        let selections = self.selections.all::<usize>(cx);
12542
12543        if selections.is_empty() {
12544            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12545            return;
12546        };
12547
12548        let clipboard_text = match cx.read_from_clipboard() {
12549            Some(item) => match item.entries().first() {
12550                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12551                _ => None,
12552            },
12553            None => None,
12554        };
12555
12556        let Some(clipboard_text) = clipboard_text else {
12557            log::warn!("Clipboard doesn't contain text.");
12558            return;
12559        };
12560
12561        window.dispatch_action(
12562            Box::new(DiffClipboardWithSelectionData {
12563                clipboard_text,
12564                editor: cx.entity(),
12565            }),
12566            cx,
12567        );
12568    }
12569
12570    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12571        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12572        if let Some(item) = cx.read_from_clipboard() {
12573            let entries = item.entries();
12574
12575            match entries.first() {
12576                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12577                // of all the pasted entries.
12578                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12579                    .do_paste(
12580                        clipboard_string.text(),
12581                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12582                        true,
12583                        window,
12584                        cx,
12585                    ),
12586                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12587            }
12588        }
12589    }
12590
12591    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12592        if self.read_only(cx) {
12593            return;
12594        }
12595
12596        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12597
12598        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12599            if let Some((selections, _)) =
12600                self.selection_history.transaction(transaction_id).cloned()
12601            {
12602                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12603                    s.select_anchors(selections.to_vec());
12604                });
12605            } else {
12606                log::error!(
12607                    "No entry in selection_history found for undo. \
12608                     This may correspond to a bug where undo does not update the selection. \
12609                     If this is occurring, please add details to \
12610                     https://github.com/zed-industries/zed/issues/22692"
12611                );
12612            }
12613            self.request_autoscroll(Autoscroll::fit(), cx);
12614            self.unmark_text(window, cx);
12615            self.refresh_edit_prediction(true, false, window, cx);
12616            cx.emit(EditorEvent::Edited { transaction_id });
12617            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12618        }
12619    }
12620
12621    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12622        if self.read_only(cx) {
12623            return;
12624        }
12625
12626        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12627
12628        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12629            if let Some((_, Some(selections))) =
12630                self.selection_history.transaction(transaction_id).cloned()
12631            {
12632                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12633                    s.select_anchors(selections.to_vec());
12634                });
12635            } else {
12636                log::error!(
12637                    "No entry in selection_history found for redo. \
12638                     This may correspond to a bug where undo does not update the selection. \
12639                     If this is occurring, please add details to \
12640                     https://github.com/zed-industries/zed/issues/22692"
12641                );
12642            }
12643            self.request_autoscroll(Autoscroll::fit(), cx);
12644            self.unmark_text(window, cx);
12645            self.refresh_edit_prediction(true, false, window, cx);
12646            cx.emit(EditorEvent::Edited { transaction_id });
12647        }
12648    }
12649
12650    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12651        self.buffer
12652            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12653    }
12654
12655    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12656        self.buffer
12657            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12658    }
12659
12660    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12662        self.change_selections(Default::default(), window, cx, |s| {
12663            s.move_with(|map, selection| {
12664                let cursor = if selection.is_empty() {
12665                    movement::left(map, selection.start)
12666                } else {
12667                    selection.start
12668                };
12669                selection.collapse_to(cursor, SelectionGoal::None);
12670            });
12671        })
12672    }
12673
12674    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12675        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12676        self.change_selections(Default::default(), window, cx, |s| {
12677            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12678        })
12679    }
12680
12681    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12683        self.change_selections(Default::default(), window, cx, |s| {
12684            s.move_with(|map, selection| {
12685                let cursor = if selection.is_empty() {
12686                    movement::right(map, selection.end)
12687                } else {
12688                    selection.end
12689                };
12690                selection.collapse_to(cursor, SelectionGoal::None)
12691            });
12692        })
12693    }
12694
12695    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12696        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12697        self.change_selections(Default::default(), window, cx, |s| {
12698            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12699        })
12700    }
12701
12702    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12703        if self.take_rename(true, window, cx).is_some() {
12704            return;
12705        }
12706
12707        if self.mode.is_single_line() {
12708            cx.propagate();
12709            return;
12710        }
12711
12712        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12713
12714        let text_layout_details = &self.text_layout_details(window);
12715        let selection_count = self.selections.count();
12716        let first_selection = self.selections.first_anchor();
12717
12718        self.change_selections(Default::default(), window, cx, |s| {
12719            s.move_with(|map, selection| {
12720                if !selection.is_empty() {
12721                    selection.goal = SelectionGoal::None;
12722                }
12723                let (cursor, goal) = movement::up(
12724                    map,
12725                    selection.start,
12726                    selection.goal,
12727                    false,
12728                    text_layout_details,
12729                );
12730                selection.collapse_to(cursor, goal);
12731            });
12732        });
12733
12734        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12735        {
12736            cx.propagate();
12737        }
12738    }
12739
12740    pub fn move_up_by_lines(
12741        &mut self,
12742        action: &MoveUpByLines,
12743        window: &mut Window,
12744        cx: &mut Context<Self>,
12745    ) {
12746        if self.take_rename(true, window, cx).is_some() {
12747            return;
12748        }
12749
12750        if self.mode.is_single_line() {
12751            cx.propagate();
12752            return;
12753        }
12754
12755        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12756
12757        let text_layout_details = &self.text_layout_details(window);
12758
12759        self.change_selections(Default::default(), window, cx, |s| {
12760            s.move_with(|map, selection| {
12761                if !selection.is_empty() {
12762                    selection.goal = SelectionGoal::None;
12763                }
12764                let (cursor, goal) = movement::up_by_rows(
12765                    map,
12766                    selection.start,
12767                    action.lines,
12768                    selection.goal,
12769                    false,
12770                    text_layout_details,
12771                );
12772                selection.collapse_to(cursor, goal);
12773            });
12774        })
12775    }
12776
12777    pub fn move_down_by_lines(
12778        &mut self,
12779        action: &MoveDownByLines,
12780        window: &mut Window,
12781        cx: &mut Context<Self>,
12782    ) {
12783        if self.take_rename(true, window, cx).is_some() {
12784            return;
12785        }
12786
12787        if self.mode.is_single_line() {
12788            cx.propagate();
12789            return;
12790        }
12791
12792        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12793
12794        let text_layout_details = &self.text_layout_details(window);
12795
12796        self.change_selections(Default::default(), window, cx, |s| {
12797            s.move_with(|map, selection| {
12798                if !selection.is_empty() {
12799                    selection.goal = SelectionGoal::None;
12800                }
12801                let (cursor, goal) = movement::down_by_rows(
12802                    map,
12803                    selection.start,
12804                    action.lines,
12805                    selection.goal,
12806                    false,
12807                    text_layout_details,
12808                );
12809                selection.collapse_to(cursor, goal);
12810            });
12811        })
12812    }
12813
12814    pub fn select_down_by_lines(
12815        &mut self,
12816        action: &SelectDownByLines,
12817        window: &mut Window,
12818        cx: &mut Context<Self>,
12819    ) {
12820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12821        let text_layout_details = &self.text_layout_details(window);
12822        self.change_selections(Default::default(), window, cx, |s| {
12823            s.move_heads_with(|map, head, goal| {
12824                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12825            })
12826        })
12827    }
12828
12829    pub fn select_up_by_lines(
12830        &mut self,
12831        action: &SelectUpByLines,
12832        window: &mut Window,
12833        cx: &mut Context<Self>,
12834    ) {
12835        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12836        let text_layout_details = &self.text_layout_details(window);
12837        self.change_selections(Default::default(), window, cx, |s| {
12838            s.move_heads_with(|map, head, goal| {
12839                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12840            })
12841        })
12842    }
12843
12844    pub fn select_page_up(
12845        &mut self,
12846        _: &SelectPageUp,
12847        window: &mut Window,
12848        cx: &mut Context<Self>,
12849    ) {
12850        let Some(row_count) = self.visible_row_count() else {
12851            return;
12852        };
12853
12854        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12855
12856        let text_layout_details = &self.text_layout_details(window);
12857
12858        self.change_selections(Default::default(), window, cx, |s| {
12859            s.move_heads_with(|map, head, goal| {
12860                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12861            })
12862        })
12863    }
12864
12865    pub fn move_page_up(
12866        &mut self,
12867        action: &MovePageUp,
12868        window: &mut Window,
12869        cx: &mut Context<Self>,
12870    ) {
12871        if self.take_rename(true, window, cx).is_some() {
12872            return;
12873        }
12874
12875        if self
12876            .context_menu
12877            .borrow_mut()
12878            .as_mut()
12879            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12880            .unwrap_or(false)
12881        {
12882            return;
12883        }
12884
12885        if matches!(self.mode, EditorMode::SingleLine) {
12886            cx.propagate();
12887            return;
12888        }
12889
12890        let Some(row_count) = self.visible_row_count() else {
12891            return;
12892        };
12893
12894        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12895
12896        let effects = if action.center_cursor {
12897            SelectionEffects::scroll(Autoscroll::center())
12898        } else {
12899            SelectionEffects::default()
12900        };
12901
12902        let text_layout_details = &self.text_layout_details(window);
12903
12904        self.change_selections(effects, window, cx, |s| {
12905            s.move_with(|map, selection| {
12906                if !selection.is_empty() {
12907                    selection.goal = SelectionGoal::None;
12908                }
12909                let (cursor, goal) = movement::up_by_rows(
12910                    map,
12911                    selection.end,
12912                    row_count,
12913                    selection.goal,
12914                    false,
12915                    text_layout_details,
12916                );
12917                selection.collapse_to(cursor, goal);
12918            });
12919        });
12920    }
12921
12922    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12923        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12924        let text_layout_details = &self.text_layout_details(window);
12925        self.change_selections(Default::default(), window, cx, |s| {
12926            s.move_heads_with(|map, head, goal| {
12927                movement::up(map, head, goal, false, text_layout_details)
12928            })
12929        })
12930    }
12931
12932    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12933        self.take_rename(true, window, cx);
12934
12935        if self.mode.is_single_line() {
12936            cx.propagate();
12937            return;
12938        }
12939
12940        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12941
12942        let text_layout_details = &self.text_layout_details(window);
12943        let selection_count = self.selections.count();
12944        let first_selection = self.selections.first_anchor();
12945
12946        self.change_selections(Default::default(), window, cx, |s| {
12947            s.move_with(|map, selection| {
12948                if !selection.is_empty() {
12949                    selection.goal = SelectionGoal::None;
12950                }
12951                let (cursor, goal) = movement::down(
12952                    map,
12953                    selection.end,
12954                    selection.goal,
12955                    false,
12956                    text_layout_details,
12957                );
12958                selection.collapse_to(cursor, goal);
12959            });
12960        });
12961
12962        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12963        {
12964            cx.propagate();
12965        }
12966    }
12967
12968    pub fn select_page_down(
12969        &mut self,
12970        _: &SelectPageDown,
12971        window: &mut Window,
12972        cx: &mut Context<Self>,
12973    ) {
12974        let Some(row_count) = self.visible_row_count() else {
12975            return;
12976        };
12977
12978        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12979
12980        let text_layout_details = &self.text_layout_details(window);
12981
12982        self.change_selections(Default::default(), window, cx, |s| {
12983            s.move_heads_with(|map, head, goal| {
12984                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12985            })
12986        })
12987    }
12988
12989    pub fn move_page_down(
12990        &mut self,
12991        action: &MovePageDown,
12992        window: &mut Window,
12993        cx: &mut Context<Self>,
12994    ) {
12995        if self.take_rename(true, window, cx).is_some() {
12996            return;
12997        }
12998
12999        if self
13000            .context_menu
13001            .borrow_mut()
13002            .as_mut()
13003            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13004            .unwrap_or(false)
13005        {
13006            return;
13007        }
13008
13009        if matches!(self.mode, EditorMode::SingleLine) {
13010            cx.propagate();
13011            return;
13012        }
13013
13014        let Some(row_count) = self.visible_row_count() else {
13015            return;
13016        };
13017
13018        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13019
13020        let effects = if action.center_cursor {
13021            SelectionEffects::scroll(Autoscroll::center())
13022        } else {
13023            SelectionEffects::default()
13024        };
13025
13026        let text_layout_details = &self.text_layout_details(window);
13027        self.change_selections(effects, window, cx, |s| {
13028            s.move_with(|map, selection| {
13029                if !selection.is_empty() {
13030                    selection.goal = SelectionGoal::None;
13031                }
13032                let (cursor, goal) = movement::down_by_rows(
13033                    map,
13034                    selection.end,
13035                    row_count,
13036                    selection.goal,
13037                    false,
13038                    text_layout_details,
13039                );
13040                selection.collapse_to(cursor, goal);
13041            });
13042        });
13043    }
13044
13045    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13046        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13047        let text_layout_details = &self.text_layout_details(window);
13048        self.change_selections(Default::default(), window, cx, |s| {
13049            s.move_heads_with(|map, head, goal| {
13050                movement::down(map, head, goal, false, text_layout_details)
13051            })
13052        });
13053    }
13054
13055    pub fn context_menu_first(
13056        &mut self,
13057        _: &ContextMenuFirst,
13058        window: &mut Window,
13059        cx: &mut Context<Self>,
13060    ) {
13061        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13062            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13063        }
13064    }
13065
13066    pub fn context_menu_prev(
13067        &mut self,
13068        _: &ContextMenuPrevious,
13069        window: &mut Window,
13070        cx: &mut Context<Self>,
13071    ) {
13072        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13073            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13074        }
13075    }
13076
13077    pub fn context_menu_next(
13078        &mut self,
13079        _: &ContextMenuNext,
13080        window: &mut Window,
13081        cx: &mut Context<Self>,
13082    ) {
13083        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13084            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13085        }
13086    }
13087
13088    pub fn context_menu_last(
13089        &mut self,
13090        _: &ContextMenuLast,
13091        window: &mut Window,
13092        cx: &mut Context<Self>,
13093    ) {
13094        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13095            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13096        }
13097    }
13098
13099    pub fn signature_help_prev(
13100        &mut self,
13101        _: &SignatureHelpPrevious,
13102        _: &mut Window,
13103        cx: &mut Context<Self>,
13104    ) {
13105        if let Some(popover) = self.signature_help_state.popover_mut() {
13106            if popover.current_signature == 0 {
13107                popover.current_signature = popover.signatures.len() - 1;
13108            } else {
13109                popover.current_signature -= 1;
13110            }
13111            cx.notify();
13112        }
13113    }
13114
13115    pub fn signature_help_next(
13116        &mut self,
13117        _: &SignatureHelpNext,
13118        _: &mut Window,
13119        cx: &mut Context<Self>,
13120    ) {
13121        if let Some(popover) = self.signature_help_state.popover_mut() {
13122            if popover.current_signature + 1 == popover.signatures.len() {
13123                popover.current_signature = 0;
13124            } else {
13125                popover.current_signature += 1;
13126            }
13127            cx.notify();
13128        }
13129    }
13130
13131    pub fn move_to_previous_word_start(
13132        &mut self,
13133        _: &MoveToPreviousWordStart,
13134        window: &mut Window,
13135        cx: &mut Context<Self>,
13136    ) {
13137        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13138        self.change_selections(Default::default(), window, cx, |s| {
13139            s.move_cursors_with(|map, head, _| {
13140                (
13141                    movement::previous_word_start(map, head),
13142                    SelectionGoal::None,
13143                )
13144            });
13145        })
13146    }
13147
13148    pub fn move_to_previous_subword_start(
13149        &mut self,
13150        _: &MoveToPreviousSubwordStart,
13151        window: &mut Window,
13152        cx: &mut Context<Self>,
13153    ) {
13154        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13155        self.change_selections(Default::default(), window, cx, |s| {
13156            s.move_cursors_with(|map, head, _| {
13157                (
13158                    movement::previous_subword_start(map, head),
13159                    SelectionGoal::None,
13160                )
13161            });
13162        })
13163    }
13164
13165    pub fn select_to_previous_word_start(
13166        &mut self,
13167        _: &SelectToPreviousWordStart,
13168        window: &mut Window,
13169        cx: &mut Context<Self>,
13170    ) {
13171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13172        self.change_selections(Default::default(), window, cx, |s| {
13173            s.move_heads_with(|map, head, _| {
13174                (
13175                    movement::previous_word_start(map, head),
13176                    SelectionGoal::None,
13177                )
13178            });
13179        })
13180    }
13181
13182    pub fn select_to_previous_subword_start(
13183        &mut self,
13184        _: &SelectToPreviousSubwordStart,
13185        window: &mut Window,
13186        cx: &mut Context<Self>,
13187    ) {
13188        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13189        self.change_selections(Default::default(), window, cx, |s| {
13190            s.move_heads_with(|map, head, _| {
13191                (
13192                    movement::previous_subword_start(map, head),
13193                    SelectionGoal::None,
13194                )
13195            });
13196        })
13197    }
13198
13199    pub fn delete_to_previous_word_start(
13200        &mut self,
13201        action: &DeleteToPreviousWordStart,
13202        window: &mut Window,
13203        cx: &mut Context<Self>,
13204    ) {
13205        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13206        self.transact(window, cx, |this, window, cx| {
13207            this.select_autoclose_pair(window, cx);
13208            this.change_selections(Default::default(), window, cx, |s| {
13209                s.move_with(|map, selection| {
13210                    if selection.is_empty() {
13211                        let mut cursor = if action.ignore_newlines {
13212                            movement::previous_word_start(map, selection.head())
13213                        } else {
13214                            movement::previous_word_start_or_newline(map, selection.head())
13215                        };
13216                        cursor = movement::adjust_greedy_deletion(
13217                            map,
13218                            selection.head(),
13219                            cursor,
13220                            action.ignore_brackets,
13221                        );
13222                        selection.set_head(cursor, SelectionGoal::None);
13223                    }
13224                });
13225            });
13226            this.insert("", window, cx);
13227        });
13228    }
13229
13230    pub fn delete_to_previous_subword_start(
13231        &mut self,
13232        _: &DeleteToPreviousSubwordStart,
13233        window: &mut Window,
13234        cx: &mut Context<Self>,
13235    ) {
13236        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13237        self.transact(window, cx, |this, window, cx| {
13238            this.select_autoclose_pair(window, cx);
13239            this.change_selections(Default::default(), window, cx, |s| {
13240                s.move_with(|map, selection| {
13241                    if selection.is_empty() {
13242                        let mut cursor = movement::previous_subword_start(map, selection.head());
13243                        cursor =
13244                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13245                        selection.set_head(cursor, SelectionGoal::None);
13246                    }
13247                });
13248            });
13249            this.insert("", window, cx);
13250        });
13251    }
13252
13253    pub fn move_to_next_word_end(
13254        &mut self,
13255        _: &MoveToNextWordEnd,
13256        window: &mut Window,
13257        cx: &mut Context<Self>,
13258    ) {
13259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13260        self.change_selections(Default::default(), window, cx, |s| {
13261            s.move_cursors_with(|map, head, _| {
13262                (movement::next_word_end(map, head), SelectionGoal::None)
13263            });
13264        })
13265    }
13266
13267    pub fn move_to_next_subword_end(
13268        &mut self,
13269        _: &MoveToNextSubwordEnd,
13270        window: &mut Window,
13271        cx: &mut Context<Self>,
13272    ) {
13273        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13274        self.change_selections(Default::default(), window, cx, |s| {
13275            s.move_cursors_with(|map, head, _| {
13276                (movement::next_subword_end(map, head), SelectionGoal::None)
13277            });
13278        })
13279    }
13280
13281    pub fn select_to_next_word_end(
13282        &mut self,
13283        _: &SelectToNextWordEnd,
13284        window: &mut Window,
13285        cx: &mut Context<Self>,
13286    ) {
13287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13288        self.change_selections(Default::default(), window, cx, |s| {
13289            s.move_heads_with(|map, head, _| {
13290                (movement::next_word_end(map, head), SelectionGoal::None)
13291            });
13292        })
13293    }
13294
13295    pub fn select_to_next_subword_end(
13296        &mut self,
13297        _: &SelectToNextSubwordEnd,
13298        window: &mut Window,
13299        cx: &mut Context<Self>,
13300    ) {
13301        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13302        self.change_selections(Default::default(), window, cx, |s| {
13303            s.move_heads_with(|map, head, _| {
13304                (movement::next_subword_end(map, head), SelectionGoal::None)
13305            });
13306        })
13307    }
13308
13309    pub fn delete_to_next_word_end(
13310        &mut self,
13311        action: &DeleteToNextWordEnd,
13312        window: &mut Window,
13313        cx: &mut Context<Self>,
13314    ) {
13315        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13316        self.transact(window, cx, |this, window, cx| {
13317            this.change_selections(Default::default(), window, cx, |s| {
13318                s.move_with(|map, selection| {
13319                    if selection.is_empty() {
13320                        let mut cursor = if action.ignore_newlines {
13321                            movement::next_word_end(map, selection.head())
13322                        } else {
13323                            movement::next_word_end_or_newline(map, selection.head())
13324                        };
13325                        cursor = movement::adjust_greedy_deletion(
13326                            map,
13327                            selection.head(),
13328                            cursor,
13329                            action.ignore_brackets,
13330                        );
13331                        selection.set_head(cursor, SelectionGoal::None);
13332                    }
13333                });
13334            });
13335            this.insert("", window, cx);
13336        });
13337    }
13338
13339    pub fn delete_to_next_subword_end(
13340        &mut self,
13341        _: &DeleteToNextSubwordEnd,
13342        window: &mut Window,
13343        cx: &mut Context<Self>,
13344    ) {
13345        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13346        self.transact(window, cx, |this, window, cx| {
13347            this.change_selections(Default::default(), window, cx, |s| {
13348                s.move_with(|map, selection| {
13349                    if selection.is_empty() {
13350                        let mut cursor = movement::next_subword_end(map, selection.head());
13351                        cursor =
13352                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13353                        selection.set_head(cursor, SelectionGoal::None);
13354                    }
13355                });
13356            });
13357            this.insert("", window, cx);
13358        });
13359    }
13360
13361    pub fn move_to_beginning_of_line(
13362        &mut self,
13363        action: &MoveToBeginningOfLine,
13364        window: &mut Window,
13365        cx: &mut Context<Self>,
13366    ) {
13367        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13368        self.change_selections(Default::default(), window, cx, |s| {
13369            s.move_cursors_with(|map, head, _| {
13370                (
13371                    movement::indented_line_beginning(
13372                        map,
13373                        head,
13374                        action.stop_at_soft_wraps,
13375                        action.stop_at_indent,
13376                    ),
13377                    SelectionGoal::None,
13378                )
13379            });
13380        })
13381    }
13382
13383    pub fn select_to_beginning_of_line(
13384        &mut self,
13385        action: &SelectToBeginningOfLine,
13386        window: &mut Window,
13387        cx: &mut Context<Self>,
13388    ) {
13389        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13390        self.change_selections(Default::default(), window, cx, |s| {
13391            s.move_heads_with(|map, head, _| {
13392                (
13393                    movement::indented_line_beginning(
13394                        map,
13395                        head,
13396                        action.stop_at_soft_wraps,
13397                        action.stop_at_indent,
13398                    ),
13399                    SelectionGoal::None,
13400                )
13401            });
13402        });
13403    }
13404
13405    pub fn delete_to_beginning_of_line(
13406        &mut self,
13407        action: &DeleteToBeginningOfLine,
13408        window: &mut Window,
13409        cx: &mut Context<Self>,
13410    ) {
13411        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13412        self.transact(window, cx, |this, window, cx| {
13413            this.change_selections(Default::default(), window, cx, |s| {
13414                s.move_with(|_, selection| {
13415                    selection.reversed = true;
13416                });
13417            });
13418
13419            this.select_to_beginning_of_line(
13420                &SelectToBeginningOfLine {
13421                    stop_at_soft_wraps: false,
13422                    stop_at_indent: action.stop_at_indent,
13423                },
13424                window,
13425                cx,
13426            );
13427            this.backspace(&Backspace, window, cx);
13428        });
13429    }
13430
13431    pub fn move_to_end_of_line(
13432        &mut self,
13433        action: &MoveToEndOfLine,
13434        window: &mut Window,
13435        cx: &mut Context<Self>,
13436    ) {
13437        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13438        self.change_selections(Default::default(), window, cx, |s| {
13439            s.move_cursors_with(|map, head, _| {
13440                (
13441                    movement::line_end(map, head, action.stop_at_soft_wraps),
13442                    SelectionGoal::None,
13443                )
13444            });
13445        })
13446    }
13447
13448    pub fn select_to_end_of_line(
13449        &mut self,
13450        action: &SelectToEndOfLine,
13451        window: &mut Window,
13452        cx: &mut Context<Self>,
13453    ) {
13454        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13455        self.change_selections(Default::default(), window, cx, |s| {
13456            s.move_heads_with(|map, head, _| {
13457                (
13458                    movement::line_end(map, head, action.stop_at_soft_wraps),
13459                    SelectionGoal::None,
13460                )
13461            });
13462        })
13463    }
13464
13465    pub fn delete_to_end_of_line(
13466        &mut self,
13467        _: &DeleteToEndOfLine,
13468        window: &mut Window,
13469        cx: &mut Context<Self>,
13470    ) {
13471        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13472        self.transact(window, cx, |this, window, cx| {
13473            this.select_to_end_of_line(
13474                &SelectToEndOfLine {
13475                    stop_at_soft_wraps: false,
13476                },
13477                window,
13478                cx,
13479            );
13480            this.delete(&Delete, window, cx);
13481        });
13482    }
13483
13484    pub fn cut_to_end_of_line(
13485        &mut self,
13486        action: &CutToEndOfLine,
13487        window: &mut Window,
13488        cx: &mut Context<Self>,
13489    ) {
13490        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13491        self.transact(window, cx, |this, window, cx| {
13492            this.select_to_end_of_line(
13493                &SelectToEndOfLine {
13494                    stop_at_soft_wraps: false,
13495                },
13496                window,
13497                cx,
13498            );
13499            if !action.stop_at_newlines {
13500                this.change_selections(Default::default(), window, cx, |s| {
13501                    s.move_with(|_, sel| {
13502                        if sel.is_empty() {
13503                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13504                        }
13505                    });
13506                });
13507            }
13508            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13509            let item = this.cut_common(false, window, cx);
13510            cx.write_to_clipboard(item);
13511        });
13512    }
13513
13514    pub fn move_to_start_of_paragraph(
13515        &mut self,
13516        _: &MoveToStartOfParagraph,
13517        window: &mut Window,
13518        cx: &mut Context<Self>,
13519    ) {
13520        if matches!(self.mode, EditorMode::SingleLine) {
13521            cx.propagate();
13522            return;
13523        }
13524        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13525        self.change_selections(Default::default(), window, cx, |s| {
13526            s.move_with(|map, selection| {
13527                selection.collapse_to(
13528                    movement::start_of_paragraph(map, selection.head(), 1),
13529                    SelectionGoal::None,
13530                )
13531            });
13532        })
13533    }
13534
13535    pub fn move_to_end_of_paragraph(
13536        &mut self,
13537        _: &MoveToEndOfParagraph,
13538        window: &mut Window,
13539        cx: &mut Context<Self>,
13540    ) {
13541        if matches!(self.mode, EditorMode::SingleLine) {
13542            cx.propagate();
13543            return;
13544        }
13545        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13546        self.change_selections(Default::default(), window, cx, |s| {
13547            s.move_with(|map, selection| {
13548                selection.collapse_to(
13549                    movement::end_of_paragraph(map, selection.head(), 1),
13550                    SelectionGoal::None,
13551                )
13552            });
13553        })
13554    }
13555
13556    pub fn select_to_start_of_paragraph(
13557        &mut self,
13558        _: &SelectToStartOfParagraph,
13559        window: &mut Window,
13560        cx: &mut Context<Self>,
13561    ) {
13562        if matches!(self.mode, EditorMode::SingleLine) {
13563            cx.propagate();
13564            return;
13565        }
13566        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13567        self.change_selections(Default::default(), window, cx, |s| {
13568            s.move_heads_with(|map, head, _| {
13569                (
13570                    movement::start_of_paragraph(map, head, 1),
13571                    SelectionGoal::None,
13572                )
13573            });
13574        })
13575    }
13576
13577    pub fn select_to_end_of_paragraph(
13578        &mut self,
13579        _: &SelectToEndOfParagraph,
13580        window: &mut Window,
13581        cx: &mut Context<Self>,
13582    ) {
13583        if matches!(self.mode, EditorMode::SingleLine) {
13584            cx.propagate();
13585            return;
13586        }
13587        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13588        self.change_selections(Default::default(), window, cx, |s| {
13589            s.move_heads_with(|map, head, _| {
13590                (
13591                    movement::end_of_paragraph(map, head, 1),
13592                    SelectionGoal::None,
13593                )
13594            });
13595        })
13596    }
13597
13598    pub fn move_to_start_of_excerpt(
13599        &mut self,
13600        _: &MoveToStartOfExcerpt,
13601        window: &mut Window,
13602        cx: &mut Context<Self>,
13603    ) {
13604        if matches!(self.mode, EditorMode::SingleLine) {
13605            cx.propagate();
13606            return;
13607        }
13608        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13609        self.change_selections(Default::default(), window, cx, |s| {
13610            s.move_with(|map, selection| {
13611                selection.collapse_to(
13612                    movement::start_of_excerpt(
13613                        map,
13614                        selection.head(),
13615                        workspace::searchable::Direction::Prev,
13616                    ),
13617                    SelectionGoal::None,
13618                )
13619            });
13620        })
13621    }
13622
13623    pub fn move_to_start_of_next_excerpt(
13624        &mut self,
13625        _: &MoveToStartOfNextExcerpt,
13626        window: &mut Window,
13627        cx: &mut Context<Self>,
13628    ) {
13629        if matches!(self.mode, EditorMode::SingleLine) {
13630            cx.propagate();
13631            return;
13632        }
13633
13634        self.change_selections(Default::default(), window, cx, |s| {
13635            s.move_with(|map, selection| {
13636                selection.collapse_to(
13637                    movement::start_of_excerpt(
13638                        map,
13639                        selection.head(),
13640                        workspace::searchable::Direction::Next,
13641                    ),
13642                    SelectionGoal::None,
13643                )
13644            });
13645        })
13646    }
13647
13648    pub fn move_to_end_of_excerpt(
13649        &mut self,
13650        _: &MoveToEndOfExcerpt,
13651        window: &mut Window,
13652        cx: &mut Context<Self>,
13653    ) {
13654        if matches!(self.mode, EditorMode::SingleLine) {
13655            cx.propagate();
13656            return;
13657        }
13658        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13659        self.change_selections(Default::default(), window, cx, |s| {
13660            s.move_with(|map, selection| {
13661                selection.collapse_to(
13662                    movement::end_of_excerpt(
13663                        map,
13664                        selection.head(),
13665                        workspace::searchable::Direction::Next,
13666                    ),
13667                    SelectionGoal::None,
13668                )
13669            });
13670        })
13671    }
13672
13673    pub fn move_to_end_of_previous_excerpt(
13674        &mut self,
13675        _: &MoveToEndOfPreviousExcerpt,
13676        window: &mut Window,
13677        cx: &mut Context<Self>,
13678    ) {
13679        if matches!(self.mode, EditorMode::SingleLine) {
13680            cx.propagate();
13681            return;
13682        }
13683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13684        self.change_selections(Default::default(), window, cx, |s| {
13685            s.move_with(|map, selection| {
13686                selection.collapse_to(
13687                    movement::end_of_excerpt(
13688                        map,
13689                        selection.head(),
13690                        workspace::searchable::Direction::Prev,
13691                    ),
13692                    SelectionGoal::None,
13693                )
13694            });
13695        })
13696    }
13697
13698    pub fn select_to_start_of_excerpt(
13699        &mut self,
13700        _: &SelectToStartOfExcerpt,
13701        window: &mut Window,
13702        cx: &mut Context<Self>,
13703    ) {
13704        if matches!(self.mode, EditorMode::SingleLine) {
13705            cx.propagate();
13706            return;
13707        }
13708        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13709        self.change_selections(Default::default(), window, cx, |s| {
13710            s.move_heads_with(|map, head, _| {
13711                (
13712                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13713                    SelectionGoal::None,
13714                )
13715            });
13716        })
13717    }
13718
13719    pub fn select_to_start_of_next_excerpt(
13720        &mut self,
13721        _: &SelectToStartOfNextExcerpt,
13722        window: &mut Window,
13723        cx: &mut Context<Self>,
13724    ) {
13725        if matches!(self.mode, EditorMode::SingleLine) {
13726            cx.propagate();
13727            return;
13728        }
13729        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13730        self.change_selections(Default::default(), window, cx, |s| {
13731            s.move_heads_with(|map, head, _| {
13732                (
13733                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13734                    SelectionGoal::None,
13735                )
13736            });
13737        })
13738    }
13739
13740    pub fn select_to_end_of_excerpt(
13741        &mut self,
13742        _: &SelectToEndOfExcerpt,
13743        window: &mut Window,
13744        cx: &mut Context<Self>,
13745    ) {
13746        if matches!(self.mode, EditorMode::SingleLine) {
13747            cx.propagate();
13748            return;
13749        }
13750        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13751        self.change_selections(Default::default(), window, cx, |s| {
13752            s.move_heads_with(|map, head, _| {
13753                (
13754                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13755                    SelectionGoal::None,
13756                )
13757            });
13758        })
13759    }
13760
13761    pub fn select_to_end_of_previous_excerpt(
13762        &mut self,
13763        _: &SelectToEndOfPreviousExcerpt,
13764        window: &mut Window,
13765        cx: &mut Context<Self>,
13766    ) {
13767        if matches!(self.mode, EditorMode::SingleLine) {
13768            cx.propagate();
13769            return;
13770        }
13771        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13772        self.change_selections(Default::default(), window, cx, |s| {
13773            s.move_heads_with(|map, head, _| {
13774                (
13775                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13776                    SelectionGoal::None,
13777                )
13778            });
13779        })
13780    }
13781
13782    pub fn move_to_beginning(
13783        &mut self,
13784        _: &MoveToBeginning,
13785        window: &mut Window,
13786        cx: &mut Context<Self>,
13787    ) {
13788        if matches!(self.mode, EditorMode::SingleLine) {
13789            cx.propagate();
13790            return;
13791        }
13792        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13793        self.change_selections(Default::default(), window, cx, |s| {
13794            s.select_ranges(vec![0..0]);
13795        });
13796    }
13797
13798    pub fn select_to_beginning(
13799        &mut self,
13800        _: &SelectToBeginning,
13801        window: &mut Window,
13802        cx: &mut Context<Self>,
13803    ) {
13804        let mut selection = self.selections.last::<Point>(cx);
13805        selection.set_head(Point::zero(), SelectionGoal::None);
13806        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13807        self.change_selections(Default::default(), window, cx, |s| {
13808            s.select(vec![selection]);
13809        });
13810    }
13811
13812    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13813        if matches!(self.mode, EditorMode::SingleLine) {
13814            cx.propagate();
13815            return;
13816        }
13817        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13818        let cursor = self.buffer.read(cx).read(cx).len();
13819        self.change_selections(Default::default(), window, cx, |s| {
13820            s.select_ranges(vec![cursor..cursor])
13821        });
13822    }
13823
13824    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13825        self.nav_history = nav_history;
13826    }
13827
13828    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13829        self.nav_history.as_ref()
13830    }
13831
13832    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13833        self.push_to_nav_history(
13834            self.selections.newest_anchor().head(),
13835            None,
13836            false,
13837            true,
13838            cx,
13839        );
13840    }
13841
13842    fn push_to_nav_history(
13843        &mut self,
13844        cursor_anchor: Anchor,
13845        new_position: Option<Point>,
13846        is_deactivate: bool,
13847        always: bool,
13848        cx: &mut Context<Self>,
13849    ) {
13850        if let Some(nav_history) = self.nav_history.as_mut() {
13851            let buffer = self.buffer.read(cx).read(cx);
13852            let cursor_position = cursor_anchor.to_point(&buffer);
13853            let scroll_state = self.scroll_manager.anchor();
13854            let scroll_top_row = scroll_state.top_row(&buffer);
13855            drop(buffer);
13856
13857            if let Some(new_position) = new_position {
13858                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13859                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13860                    return;
13861                }
13862            }
13863
13864            nav_history.push(
13865                Some(NavigationData {
13866                    cursor_anchor,
13867                    cursor_position,
13868                    scroll_anchor: scroll_state,
13869                    scroll_top_row,
13870                }),
13871                cx,
13872            );
13873            cx.emit(EditorEvent::PushedToNavHistory {
13874                anchor: cursor_anchor,
13875                is_deactivate,
13876            })
13877        }
13878    }
13879
13880    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13881        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13882        let buffer = self.buffer.read(cx).snapshot(cx);
13883        let mut selection = self.selections.first::<usize>(cx);
13884        selection.set_head(buffer.len(), SelectionGoal::None);
13885        self.change_selections(Default::default(), window, cx, |s| {
13886            s.select(vec![selection]);
13887        });
13888    }
13889
13890    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13891        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13892        let end = self.buffer.read(cx).read(cx).len();
13893        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13894            s.select_ranges(vec![0..end]);
13895        });
13896    }
13897
13898    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13899        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13900        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13901        let mut selections = self.selections.all::<Point>(cx);
13902        let max_point = display_map.buffer_snapshot.max_point();
13903        for selection in &mut selections {
13904            let rows = selection.spanned_rows(true, &display_map);
13905            selection.start = Point::new(rows.start.0, 0);
13906            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13907            selection.reversed = false;
13908        }
13909        self.change_selections(Default::default(), window, cx, |s| {
13910            s.select(selections);
13911        });
13912    }
13913
13914    pub fn split_selection_into_lines(
13915        &mut self,
13916        action: &SplitSelectionIntoLines,
13917        window: &mut Window,
13918        cx: &mut Context<Self>,
13919    ) {
13920        let selections = self
13921            .selections
13922            .all::<Point>(cx)
13923            .into_iter()
13924            .map(|selection| selection.start..selection.end)
13925            .collect::<Vec<_>>();
13926        self.unfold_ranges(&selections, true, true, cx);
13927
13928        let mut new_selection_ranges = Vec::new();
13929        {
13930            let buffer = self.buffer.read(cx).read(cx);
13931            for selection in selections {
13932                for row in selection.start.row..selection.end.row {
13933                    let line_start = Point::new(row, 0);
13934                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13935
13936                    if action.keep_selections {
13937                        // Keep the selection range for each line
13938                        let selection_start = if row == selection.start.row {
13939                            selection.start
13940                        } else {
13941                            line_start
13942                        };
13943                        new_selection_ranges.push(selection_start..line_end);
13944                    } else {
13945                        // Collapse to cursor at end of line
13946                        new_selection_ranges.push(line_end..line_end);
13947                    }
13948                }
13949
13950                let is_multiline_selection = selection.start.row != selection.end.row;
13951                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13952                // so this action feels more ergonomic when paired with other selection operations
13953                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13954                if !should_skip_last {
13955                    if action.keep_selections {
13956                        if is_multiline_selection {
13957                            let line_start = Point::new(selection.end.row, 0);
13958                            new_selection_ranges.push(line_start..selection.end);
13959                        } else {
13960                            new_selection_ranges.push(selection.start..selection.end);
13961                        }
13962                    } else {
13963                        new_selection_ranges.push(selection.end..selection.end);
13964                    }
13965                }
13966            }
13967        }
13968        self.change_selections(Default::default(), window, cx, |s| {
13969            s.select_ranges(new_selection_ranges);
13970        });
13971    }
13972
13973    pub fn add_selection_above(
13974        &mut self,
13975        _: &AddSelectionAbove,
13976        window: &mut Window,
13977        cx: &mut Context<Self>,
13978    ) {
13979        self.add_selection(true, window, cx);
13980    }
13981
13982    pub fn add_selection_below(
13983        &mut self,
13984        _: &AddSelectionBelow,
13985        window: &mut Window,
13986        cx: &mut Context<Self>,
13987    ) {
13988        self.add_selection(false, window, cx);
13989    }
13990
13991    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13992        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13993
13994        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13995        let all_selections = self.selections.all::<Point>(cx);
13996        let text_layout_details = self.text_layout_details(window);
13997
13998        let (mut columnar_selections, new_selections_to_columnarize) = {
13999            if let Some(state) = self.add_selections_state.as_ref() {
14000                let columnar_selection_ids: HashSet<_> = state
14001                    .groups
14002                    .iter()
14003                    .flat_map(|group| group.stack.iter())
14004                    .copied()
14005                    .collect();
14006
14007                all_selections
14008                    .into_iter()
14009                    .partition(|s| columnar_selection_ids.contains(&s.id))
14010            } else {
14011                (Vec::new(), all_selections)
14012            }
14013        };
14014
14015        let mut state = self
14016            .add_selections_state
14017            .take()
14018            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14019
14020        for selection in new_selections_to_columnarize {
14021            let range = selection.display_range(&display_map).sorted();
14022            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14023            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14024            let positions = start_x.min(end_x)..start_x.max(end_x);
14025            let mut stack = Vec::new();
14026            for row in range.start.row().0..=range.end.row().0 {
14027                if let Some(selection) = self.selections.build_columnar_selection(
14028                    &display_map,
14029                    DisplayRow(row),
14030                    &positions,
14031                    selection.reversed,
14032                    &text_layout_details,
14033                ) {
14034                    stack.push(selection.id);
14035                    columnar_selections.push(selection);
14036                }
14037            }
14038            if !stack.is_empty() {
14039                if above {
14040                    stack.reverse();
14041                }
14042                state.groups.push(AddSelectionsGroup { above, stack });
14043            }
14044        }
14045
14046        let mut final_selections = Vec::new();
14047        let end_row = if above {
14048            DisplayRow(0)
14049        } else {
14050            display_map.max_point().row()
14051        };
14052
14053        let mut last_added_item_per_group = HashMap::default();
14054        for group in state.groups.iter_mut() {
14055            if let Some(last_id) = group.stack.last() {
14056                last_added_item_per_group.insert(*last_id, group);
14057            }
14058        }
14059
14060        for selection in columnar_selections {
14061            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14062                if above == group.above {
14063                    let range = selection.display_range(&display_map).sorted();
14064                    debug_assert_eq!(range.start.row(), range.end.row());
14065                    let mut row = range.start.row();
14066                    let positions =
14067                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14068                            px(start)..px(end)
14069                        } else {
14070                            let start_x =
14071                                display_map.x_for_display_point(range.start, &text_layout_details);
14072                            let end_x =
14073                                display_map.x_for_display_point(range.end, &text_layout_details);
14074                            start_x.min(end_x)..start_x.max(end_x)
14075                        };
14076
14077                    let mut maybe_new_selection = None;
14078                    while row != end_row {
14079                        if above {
14080                            row.0 -= 1;
14081                        } else {
14082                            row.0 += 1;
14083                        }
14084                        if let Some(new_selection) = self.selections.build_columnar_selection(
14085                            &display_map,
14086                            row,
14087                            &positions,
14088                            selection.reversed,
14089                            &text_layout_details,
14090                        ) {
14091                            maybe_new_selection = Some(new_selection);
14092                            break;
14093                        }
14094                    }
14095
14096                    if let Some(new_selection) = maybe_new_selection {
14097                        group.stack.push(new_selection.id);
14098                        if above {
14099                            final_selections.push(new_selection);
14100                            final_selections.push(selection);
14101                        } else {
14102                            final_selections.push(selection);
14103                            final_selections.push(new_selection);
14104                        }
14105                    } else {
14106                        final_selections.push(selection);
14107                    }
14108                } else {
14109                    group.stack.pop();
14110                }
14111            } else {
14112                final_selections.push(selection);
14113            }
14114        }
14115
14116        self.change_selections(Default::default(), window, cx, |s| {
14117            s.select(final_selections);
14118        });
14119
14120        let final_selection_ids: HashSet<_> = self
14121            .selections
14122            .all::<Point>(cx)
14123            .iter()
14124            .map(|s| s.id)
14125            .collect();
14126        state.groups.retain_mut(|group| {
14127            // selections might get merged above so we remove invalid items from stacks
14128            group.stack.retain(|id| final_selection_ids.contains(id));
14129
14130            // single selection in stack can be treated as initial state
14131            group.stack.len() > 1
14132        });
14133
14134        if !state.groups.is_empty() {
14135            self.add_selections_state = Some(state);
14136        }
14137    }
14138
14139    fn select_match_ranges(
14140        &mut self,
14141        range: Range<usize>,
14142        reversed: bool,
14143        replace_newest: bool,
14144        auto_scroll: Option<Autoscroll>,
14145        window: &mut Window,
14146        cx: &mut Context<Editor>,
14147    ) {
14148        self.unfold_ranges(
14149            std::slice::from_ref(&range),
14150            false,
14151            auto_scroll.is_some(),
14152            cx,
14153        );
14154        let effects = if let Some(scroll) = auto_scroll {
14155            SelectionEffects::scroll(scroll)
14156        } else {
14157            SelectionEffects::no_scroll()
14158        };
14159        self.change_selections(effects, window, cx, |s| {
14160            if replace_newest {
14161                s.delete(s.newest_anchor().id);
14162            }
14163            if reversed {
14164                s.insert_range(range.end..range.start);
14165            } else {
14166                s.insert_range(range);
14167            }
14168        });
14169    }
14170
14171    pub fn select_next_match_internal(
14172        &mut self,
14173        display_map: &DisplaySnapshot,
14174        replace_newest: bool,
14175        autoscroll: Option<Autoscroll>,
14176        window: &mut Window,
14177        cx: &mut Context<Self>,
14178    ) -> Result<()> {
14179        let buffer = &display_map.buffer_snapshot;
14180        let mut selections = self.selections.all::<usize>(cx);
14181        if let Some(mut select_next_state) = self.select_next_state.take() {
14182            let query = &select_next_state.query;
14183            if !select_next_state.done {
14184                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14185                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14186                let mut next_selected_range = None;
14187
14188                let bytes_after_last_selection =
14189                    buffer.bytes_in_range(last_selection.end..buffer.len());
14190                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14191                let query_matches = query
14192                    .stream_find_iter(bytes_after_last_selection)
14193                    .map(|result| (last_selection.end, result))
14194                    .chain(
14195                        query
14196                            .stream_find_iter(bytes_before_first_selection)
14197                            .map(|result| (0, result)),
14198                    );
14199
14200                for (start_offset, query_match) in query_matches {
14201                    let query_match = query_match.unwrap(); // can only fail due to I/O
14202                    let offset_range =
14203                        start_offset + query_match.start()..start_offset + query_match.end();
14204
14205                    if !select_next_state.wordwise
14206                        || (!buffer.is_inside_word(offset_range.start, false)
14207                            && !buffer.is_inside_word(offset_range.end, false))
14208                    {
14209                        // TODO: This is n^2, because we might check all the selections
14210                        if !selections
14211                            .iter()
14212                            .any(|selection| selection.range().overlaps(&offset_range))
14213                        {
14214                            next_selected_range = Some(offset_range);
14215                            break;
14216                        }
14217                    }
14218                }
14219
14220                if let Some(next_selected_range) = next_selected_range {
14221                    self.select_match_ranges(
14222                        next_selected_range,
14223                        last_selection.reversed,
14224                        replace_newest,
14225                        autoscroll,
14226                        window,
14227                        cx,
14228                    );
14229                } else {
14230                    select_next_state.done = true;
14231                }
14232            }
14233
14234            self.select_next_state = Some(select_next_state);
14235        } else {
14236            let mut only_carets = true;
14237            let mut same_text_selected = true;
14238            let mut selected_text = None;
14239
14240            let mut selections_iter = selections.iter().peekable();
14241            while let Some(selection) = selections_iter.next() {
14242                if selection.start != selection.end {
14243                    only_carets = false;
14244                }
14245
14246                if same_text_selected {
14247                    if selected_text.is_none() {
14248                        selected_text =
14249                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14250                    }
14251
14252                    if let Some(next_selection) = selections_iter.peek() {
14253                        if next_selection.range().len() == selection.range().len() {
14254                            let next_selected_text = buffer
14255                                .text_for_range(next_selection.range())
14256                                .collect::<String>();
14257                            if Some(next_selected_text) != selected_text {
14258                                same_text_selected = false;
14259                                selected_text = None;
14260                            }
14261                        } else {
14262                            same_text_selected = false;
14263                            selected_text = None;
14264                        }
14265                    }
14266                }
14267            }
14268
14269            if only_carets {
14270                for selection in &mut selections {
14271                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14272                    selection.start = word_range.start;
14273                    selection.end = word_range.end;
14274                    selection.goal = SelectionGoal::None;
14275                    selection.reversed = false;
14276                    self.select_match_ranges(
14277                        selection.start..selection.end,
14278                        selection.reversed,
14279                        replace_newest,
14280                        autoscroll,
14281                        window,
14282                        cx,
14283                    );
14284                }
14285
14286                if selections.len() == 1 {
14287                    let selection = selections
14288                        .last()
14289                        .expect("ensured that there's only one selection");
14290                    let query = buffer
14291                        .text_for_range(selection.start..selection.end)
14292                        .collect::<String>();
14293                    let is_empty = query.is_empty();
14294                    let select_state = SelectNextState {
14295                        query: AhoCorasick::new(&[query])?,
14296                        wordwise: true,
14297                        done: is_empty,
14298                    };
14299                    self.select_next_state = Some(select_state);
14300                } else {
14301                    self.select_next_state = None;
14302                }
14303            } else if let Some(selected_text) = selected_text {
14304                self.select_next_state = Some(SelectNextState {
14305                    query: AhoCorasick::new(&[selected_text])?,
14306                    wordwise: false,
14307                    done: false,
14308                });
14309                self.select_next_match_internal(
14310                    display_map,
14311                    replace_newest,
14312                    autoscroll,
14313                    window,
14314                    cx,
14315                )?;
14316            }
14317        }
14318        Ok(())
14319    }
14320
14321    pub fn select_all_matches(
14322        &mut self,
14323        _action: &SelectAllMatches,
14324        window: &mut Window,
14325        cx: &mut Context<Self>,
14326    ) -> Result<()> {
14327        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14328
14329        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14330
14331        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14332        let Some(select_next_state) = self.select_next_state.as_mut() else {
14333            return Ok(());
14334        };
14335        if select_next_state.done {
14336            return Ok(());
14337        }
14338
14339        let mut new_selections = Vec::new();
14340
14341        let reversed = self.selections.oldest::<usize>(cx).reversed;
14342        let buffer = &display_map.buffer_snapshot;
14343        let query_matches = select_next_state
14344            .query
14345            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14346
14347        for query_match in query_matches.into_iter() {
14348            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14349            let offset_range = if reversed {
14350                query_match.end()..query_match.start()
14351            } else {
14352                query_match.start()..query_match.end()
14353            };
14354
14355            if !select_next_state.wordwise
14356                || (!buffer.is_inside_word(offset_range.start, false)
14357                    && !buffer.is_inside_word(offset_range.end, false))
14358            {
14359                new_selections.push(offset_range.start..offset_range.end);
14360            }
14361        }
14362
14363        select_next_state.done = true;
14364
14365        if new_selections.is_empty() {
14366            log::error!("bug: new_selections is empty in select_all_matches");
14367            return Ok(());
14368        }
14369
14370        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14371        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14372            selections.select_ranges(new_selections)
14373        });
14374
14375        Ok(())
14376    }
14377
14378    pub fn select_next(
14379        &mut self,
14380        action: &SelectNext,
14381        window: &mut Window,
14382        cx: &mut Context<Self>,
14383    ) -> Result<()> {
14384        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14385        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14386        self.select_next_match_internal(
14387            &display_map,
14388            action.replace_newest,
14389            Some(Autoscroll::newest()),
14390            window,
14391            cx,
14392        )?;
14393        Ok(())
14394    }
14395
14396    pub fn select_previous(
14397        &mut self,
14398        action: &SelectPrevious,
14399        window: &mut Window,
14400        cx: &mut Context<Self>,
14401    ) -> Result<()> {
14402        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14403        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14404        let buffer = &display_map.buffer_snapshot;
14405        let mut selections = self.selections.all::<usize>(cx);
14406        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14407            let query = &select_prev_state.query;
14408            if !select_prev_state.done {
14409                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14410                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14411                let mut next_selected_range = None;
14412                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14413                let bytes_before_last_selection =
14414                    buffer.reversed_bytes_in_range(0..last_selection.start);
14415                let bytes_after_first_selection =
14416                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14417                let query_matches = query
14418                    .stream_find_iter(bytes_before_last_selection)
14419                    .map(|result| (last_selection.start, result))
14420                    .chain(
14421                        query
14422                            .stream_find_iter(bytes_after_first_selection)
14423                            .map(|result| (buffer.len(), result)),
14424                    );
14425                for (end_offset, query_match) in query_matches {
14426                    let query_match = query_match.unwrap(); // can only fail due to I/O
14427                    let offset_range =
14428                        end_offset - query_match.end()..end_offset - query_match.start();
14429
14430                    if !select_prev_state.wordwise
14431                        || (!buffer.is_inside_word(offset_range.start, false)
14432                            && !buffer.is_inside_word(offset_range.end, false))
14433                    {
14434                        next_selected_range = Some(offset_range);
14435                        break;
14436                    }
14437                }
14438
14439                if let Some(next_selected_range) = next_selected_range {
14440                    self.select_match_ranges(
14441                        next_selected_range,
14442                        last_selection.reversed,
14443                        action.replace_newest,
14444                        Some(Autoscroll::newest()),
14445                        window,
14446                        cx,
14447                    );
14448                } else {
14449                    select_prev_state.done = true;
14450                }
14451            }
14452
14453            self.select_prev_state = Some(select_prev_state);
14454        } else {
14455            let mut only_carets = true;
14456            let mut same_text_selected = true;
14457            let mut selected_text = None;
14458
14459            let mut selections_iter = selections.iter().peekable();
14460            while let Some(selection) = selections_iter.next() {
14461                if selection.start != selection.end {
14462                    only_carets = false;
14463                }
14464
14465                if same_text_selected {
14466                    if selected_text.is_none() {
14467                        selected_text =
14468                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14469                    }
14470
14471                    if let Some(next_selection) = selections_iter.peek() {
14472                        if next_selection.range().len() == selection.range().len() {
14473                            let next_selected_text = buffer
14474                                .text_for_range(next_selection.range())
14475                                .collect::<String>();
14476                            if Some(next_selected_text) != selected_text {
14477                                same_text_selected = false;
14478                                selected_text = None;
14479                            }
14480                        } else {
14481                            same_text_selected = false;
14482                            selected_text = None;
14483                        }
14484                    }
14485                }
14486            }
14487
14488            if only_carets {
14489                for selection in &mut selections {
14490                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14491                    selection.start = word_range.start;
14492                    selection.end = word_range.end;
14493                    selection.goal = SelectionGoal::None;
14494                    selection.reversed = false;
14495                    self.select_match_ranges(
14496                        selection.start..selection.end,
14497                        selection.reversed,
14498                        action.replace_newest,
14499                        Some(Autoscroll::newest()),
14500                        window,
14501                        cx,
14502                    );
14503                }
14504                if selections.len() == 1 {
14505                    let selection = selections
14506                        .last()
14507                        .expect("ensured that there's only one selection");
14508                    let query = buffer
14509                        .text_for_range(selection.start..selection.end)
14510                        .collect::<String>();
14511                    let is_empty = query.is_empty();
14512                    let select_state = SelectNextState {
14513                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14514                        wordwise: true,
14515                        done: is_empty,
14516                    };
14517                    self.select_prev_state = Some(select_state);
14518                } else {
14519                    self.select_prev_state = None;
14520                }
14521            } else if let Some(selected_text) = selected_text {
14522                self.select_prev_state = Some(SelectNextState {
14523                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14524                    wordwise: false,
14525                    done: false,
14526                });
14527                self.select_previous(action, window, cx)?;
14528            }
14529        }
14530        Ok(())
14531    }
14532
14533    pub fn find_next_match(
14534        &mut self,
14535        _: &FindNextMatch,
14536        window: &mut Window,
14537        cx: &mut Context<Self>,
14538    ) -> Result<()> {
14539        let selections = self.selections.disjoint_anchors();
14540        match selections.first() {
14541            Some(first) if selections.len() >= 2 => {
14542                self.change_selections(Default::default(), window, cx, |s| {
14543                    s.select_ranges([first.range()]);
14544                });
14545            }
14546            _ => self.select_next(
14547                &SelectNext {
14548                    replace_newest: true,
14549                },
14550                window,
14551                cx,
14552            )?,
14553        }
14554        Ok(())
14555    }
14556
14557    pub fn find_previous_match(
14558        &mut self,
14559        _: &FindPreviousMatch,
14560        window: &mut Window,
14561        cx: &mut Context<Self>,
14562    ) -> Result<()> {
14563        let selections = self.selections.disjoint_anchors();
14564        match selections.last() {
14565            Some(last) if selections.len() >= 2 => {
14566                self.change_selections(Default::default(), window, cx, |s| {
14567                    s.select_ranges([last.range()]);
14568                });
14569            }
14570            _ => self.select_previous(
14571                &SelectPrevious {
14572                    replace_newest: true,
14573                },
14574                window,
14575                cx,
14576            )?,
14577        }
14578        Ok(())
14579    }
14580
14581    pub fn toggle_comments(
14582        &mut self,
14583        action: &ToggleComments,
14584        window: &mut Window,
14585        cx: &mut Context<Self>,
14586    ) {
14587        if self.read_only(cx) {
14588            return;
14589        }
14590        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14591        let text_layout_details = &self.text_layout_details(window);
14592        self.transact(window, cx, |this, window, cx| {
14593            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14594            let mut edits = Vec::new();
14595            let mut selection_edit_ranges = Vec::new();
14596            let mut last_toggled_row = None;
14597            let snapshot = this.buffer.read(cx).read(cx);
14598            let empty_str: Arc<str> = Arc::default();
14599            let mut suffixes_inserted = Vec::new();
14600            let ignore_indent = action.ignore_indent;
14601
14602            fn comment_prefix_range(
14603                snapshot: &MultiBufferSnapshot,
14604                row: MultiBufferRow,
14605                comment_prefix: &str,
14606                comment_prefix_whitespace: &str,
14607                ignore_indent: bool,
14608            ) -> Range<Point> {
14609                let indent_size = if ignore_indent {
14610                    0
14611                } else {
14612                    snapshot.indent_size_for_line(row).len
14613                };
14614
14615                let start = Point::new(row.0, indent_size);
14616
14617                let mut line_bytes = snapshot
14618                    .bytes_in_range(start..snapshot.max_point())
14619                    .flatten()
14620                    .copied();
14621
14622                // If this line currently begins with the line comment prefix, then record
14623                // the range containing the prefix.
14624                if line_bytes
14625                    .by_ref()
14626                    .take(comment_prefix.len())
14627                    .eq(comment_prefix.bytes())
14628                {
14629                    // Include any whitespace that matches the comment prefix.
14630                    let matching_whitespace_len = line_bytes
14631                        .zip(comment_prefix_whitespace.bytes())
14632                        .take_while(|(a, b)| a == b)
14633                        .count() as u32;
14634                    let end = Point::new(
14635                        start.row,
14636                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14637                    );
14638                    start..end
14639                } else {
14640                    start..start
14641                }
14642            }
14643
14644            fn comment_suffix_range(
14645                snapshot: &MultiBufferSnapshot,
14646                row: MultiBufferRow,
14647                comment_suffix: &str,
14648                comment_suffix_has_leading_space: bool,
14649            ) -> Range<Point> {
14650                let end = Point::new(row.0, snapshot.line_len(row));
14651                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14652
14653                let mut line_end_bytes = snapshot
14654                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14655                    .flatten()
14656                    .copied();
14657
14658                let leading_space_len = if suffix_start_column > 0
14659                    && line_end_bytes.next() == Some(b' ')
14660                    && comment_suffix_has_leading_space
14661                {
14662                    1
14663                } else {
14664                    0
14665                };
14666
14667                // If this line currently begins with the line comment prefix, then record
14668                // the range containing the prefix.
14669                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14670                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14671                    start..end
14672                } else {
14673                    end..end
14674                }
14675            }
14676
14677            // TODO: Handle selections that cross excerpts
14678            for selection in &mut selections {
14679                let start_column = snapshot
14680                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14681                    .len;
14682                let language = if let Some(language) =
14683                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14684                {
14685                    language
14686                } else {
14687                    continue;
14688                };
14689
14690                selection_edit_ranges.clear();
14691
14692                // If multiple selections contain a given row, avoid processing that
14693                // row more than once.
14694                let mut start_row = MultiBufferRow(selection.start.row);
14695                if last_toggled_row == Some(start_row) {
14696                    start_row = start_row.next_row();
14697                }
14698                let end_row =
14699                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14700                        MultiBufferRow(selection.end.row - 1)
14701                    } else {
14702                        MultiBufferRow(selection.end.row)
14703                    };
14704                last_toggled_row = Some(end_row);
14705
14706                if start_row > end_row {
14707                    continue;
14708                }
14709
14710                // If the language has line comments, toggle those.
14711                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14712
14713                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14714                if ignore_indent {
14715                    full_comment_prefixes = full_comment_prefixes
14716                        .into_iter()
14717                        .map(|s| Arc::from(s.trim_end()))
14718                        .collect();
14719                }
14720
14721                if !full_comment_prefixes.is_empty() {
14722                    let first_prefix = full_comment_prefixes
14723                        .first()
14724                        .expect("prefixes is non-empty");
14725                    let prefix_trimmed_lengths = full_comment_prefixes
14726                        .iter()
14727                        .map(|p| p.trim_end_matches(' ').len())
14728                        .collect::<SmallVec<[usize; 4]>>();
14729
14730                    let mut all_selection_lines_are_comments = true;
14731
14732                    for row in start_row.0..=end_row.0 {
14733                        let row = MultiBufferRow(row);
14734                        if start_row < end_row && snapshot.is_line_blank(row) {
14735                            continue;
14736                        }
14737
14738                        let prefix_range = full_comment_prefixes
14739                            .iter()
14740                            .zip(prefix_trimmed_lengths.iter().copied())
14741                            .map(|(prefix, trimmed_prefix_len)| {
14742                                comment_prefix_range(
14743                                    snapshot.deref(),
14744                                    row,
14745                                    &prefix[..trimmed_prefix_len],
14746                                    &prefix[trimmed_prefix_len..],
14747                                    ignore_indent,
14748                                )
14749                            })
14750                            .max_by_key(|range| range.end.column - range.start.column)
14751                            .expect("prefixes is non-empty");
14752
14753                        if prefix_range.is_empty() {
14754                            all_selection_lines_are_comments = false;
14755                        }
14756
14757                        selection_edit_ranges.push(prefix_range);
14758                    }
14759
14760                    if all_selection_lines_are_comments {
14761                        edits.extend(
14762                            selection_edit_ranges
14763                                .iter()
14764                                .cloned()
14765                                .map(|range| (range, empty_str.clone())),
14766                        );
14767                    } else {
14768                        let min_column = selection_edit_ranges
14769                            .iter()
14770                            .map(|range| range.start.column)
14771                            .min()
14772                            .unwrap_or(0);
14773                        edits.extend(selection_edit_ranges.iter().map(|range| {
14774                            let position = Point::new(range.start.row, min_column);
14775                            (position..position, first_prefix.clone())
14776                        }));
14777                    }
14778                } else if let Some(BlockCommentConfig {
14779                    start: full_comment_prefix,
14780                    end: comment_suffix,
14781                    ..
14782                }) = language.block_comment()
14783                {
14784                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14785                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14786                    let prefix_range = comment_prefix_range(
14787                        snapshot.deref(),
14788                        start_row,
14789                        comment_prefix,
14790                        comment_prefix_whitespace,
14791                        ignore_indent,
14792                    );
14793                    let suffix_range = comment_suffix_range(
14794                        snapshot.deref(),
14795                        end_row,
14796                        comment_suffix.trim_start_matches(' '),
14797                        comment_suffix.starts_with(' '),
14798                    );
14799
14800                    if prefix_range.is_empty() || suffix_range.is_empty() {
14801                        edits.push((
14802                            prefix_range.start..prefix_range.start,
14803                            full_comment_prefix.clone(),
14804                        ));
14805                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14806                        suffixes_inserted.push((end_row, comment_suffix.len()));
14807                    } else {
14808                        edits.push((prefix_range, empty_str.clone()));
14809                        edits.push((suffix_range, empty_str.clone()));
14810                    }
14811                } else {
14812                    continue;
14813                }
14814            }
14815
14816            drop(snapshot);
14817            this.buffer.update(cx, |buffer, cx| {
14818                buffer.edit(edits, None, cx);
14819            });
14820
14821            // Adjust selections so that they end before any comment suffixes that
14822            // were inserted.
14823            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14824            let mut selections = this.selections.all::<Point>(cx);
14825            let snapshot = this.buffer.read(cx).read(cx);
14826            for selection in &mut selections {
14827                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14828                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14829                        Ordering::Less => {
14830                            suffixes_inserted.next();
14831                            continue;
14832                        }
14833                        Ordering::Greater => break,
14834                        Ordering::Equal => {
14835                            if selection.end.column == snapshot.line_len(row) {
14836                                if selection.is_empty() {
14837                                    selection.start.column -= suffix_len as u32;
14838                                }
14839                                selection.end.column -= suffix_len as u32;
14840                            }
14841                            break;
14842                        }
14843                    }
14844                }
14845            }
14846
14847            drop(snapshot);
14848            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14849
14850            let selections = this.selections.all::<Point>(cx);
14851            let selections_on_single_row = selections.windows(2).all(|selections| {
14852                selections[0].start.row == selections[1].start.row
14853                    && selections[0].end.row == selections[1].end.row
14854                    && selections[0].start.row == selections[0].end.row
14855            });
14856            let selections_selecting = selections
14857                .iter()
14858                .any(|selection| selection.start != selection.end);
14859            let advance_downwards = action.advance_downwards
14860                && selections_on_single_row
14861                && !selections_selecting
14862                && !matches!(this.mode, EditorMode::SingleLine);
14863
14864            if advance_downwards {
14865                let snapshot = this.buffer.read(cx).snapshot(cx);
14866
14867                this.change_selections(Default::default(), window, cx, |s| {
14868                    s.move_cursors_with(|display_snapshot, display_point, _| {
14869                        let mut point = display_point.to_point(display_snapshot);
14870                        point.row += 1;
14871                        point = snapshot.clip_point(point, Bias::Left);
14872                        let display_point = point.to_display_point(display_snapshot);
14873                        let goal = SelectionGoal::HorizontalPosition(
14874                            display_snapshot
14875                                .x_for_display_point(display_point, text_layout_details)
14876                                .into(),
14877                        );
14878                        (display_point, goal)
14879                    })
14880                });
14881            }
14882        });
14883    }
14884
14885    pub fn select_enclosing_symbol(
14886        &mut self,
14887        _: &SelectEnclosingSymbol,
14888        window: &mut Window,
14889        cx: &mut Context<Self>,
14890    ) {
14891        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14892
14893        let buffer = self.buffer.read(cx).snapshot(cx);
14894        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14895
14896        fn update_selection(
14897            selection: &Selection<usize>,
14898            buffer_snap: &MultiBufferSnapshot,
14899        ) -> Option<Selection<usize>> {
14900            let cursor = selection.head();
14901            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14902            for symbol in symbols.iter().rev() {
14903                let start = symbol.range.start.to_offset(buffer_snap);
14904                let end = symbol.range.end.to_offset(buffer_snap);
14905                let new_range = start..end;
14906                if start < selection.start || end > selection.end {
14907                    return Some(Selection {
14908                        id: selection.id,
14909                        start: new_range.start,
14910                        end: new_range.end,
14911                        goal: SelectionGoal::None,
14912                        reversed: selection.reversed,
14913                    });
14914                }
14915            }
14916            None
14917        }
14918
14919        let mut selected_larger_symbol = false;
14920        let new_selections = old_selections
14921            .iter()
14922            .map(|selection| match update_selection(selection, &buffer) {
14923                Some(new_selection) => {
14924                    if new_selection.range() != selection.range() {
14925                        selected_larger_symbol = true;
14926                    }
14927                    new_selection
14928                }
14929                None => selection.clone(),
14930            })
14931            .collect::<Vec<_>>();
14932
14933        if selected_larger_symbol {
14934            self.change_selections(Default::default(), window, cx, |s| {
14935                s.select(new_selections);
14936            });
14937        }
14938    }
14939
14940    pub fn select_larger_syntax_node(
14941        &mut self,
14942        _: &SelectLargerSyntaxNode,
14943        window: &mut Window,
14944        cx: &mut Context<Self>,
14945    ) {
14946        let Some(visible_row_count) = self.visible_row_count() else {
14947            return;
14948        };
14949        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14950        if old_selections.is_empty() {
14951            return;
14952        }
14953
14954        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14955
14956        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14957        let buffer = self.buffer.read(cx).snapshot(cx);
14958
14959        let mut selected_larger_node = false;
14960        let mut new_selections = old_selections
14961            .iter()
14962            .map(|selection| {
14963                let old_range = selection.start..selection.end;
14964
14965                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14966                    // manually select word at selection
14967                    if ["string_content", "inline"].contains(&node.kind()) {
14968                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14969                        // ignore if word is already selected
14970                        if !word_range.is_empty() && old_range != word_range {
14971                            let (last_word_range, _) =
14972                                buffer.surrounding_word(old_range.end, false);
14973                            // only select word if start and end point belongs to same word
14974                            if word_range == last_word_range {
14975                                selected_larger_node = true;
14976                                return Selection {
14977                                    id: selection.id,
14978                                    start: word_range.start,
14979                                    end: word_range.end,
14980                                    goal: SelectionGoal::None,
14981                                    reversed: selection.reversed,
14982                                };
14983                            }
14984                        }
14985                    }
14986                }
14987
14988                let mut new_range = old_range.clone();
14989                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
14990                {
14991                    if !node.is_named() {
14992                        new_range = node.start_byte()..node.end_byte();
14993                        continue;
14994                    }
14995
14996                    new_range = match containing_range {
14997                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14998                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14999                    };
15000                    if !display_map.intersects_fold(new_range.start)
15001                        && !display_map.intersects_fold(new_range.end)
15002                    {
15003                        break;
15004                    }
15005                }
15006
15007                selected_larger_node |= new_range != old_range;
15008                Selection {
15009                    id: selection.id,
15010                    start: new_range.start,
15011                    end: new_range.end,
15012                    goal: SelectionGoal::None,
15013                    reversed: selection.reversed,
15014                }
15015            })
15016            .collect::<Vec<_>>();
15017
15018        if !selected_larger_node {
15019            return; // don't put this call in the history
15020        }
15021
15022        // scroll based on transformation done to the last selection created by the user
15023        let (last_old, last_new) = old_selections
15024            .last()
15025            .zip(new_selections.last().cloned())
15026            .expect("old_selections isn't empty");
15027
15028        // revert selection
15029        let is_selection_reversed = {
15030            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15031            new_selections.last_mut().expect("checked above").reversed =
15032                should_newest_selection_be_reversed;
15033            should_newest_selection_be_reversed
15034        };
15035
15036        if selected_larger_node {
15037            self.select_syntax_node_history.disable_clearing = true;
15038            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15039                s.select(new_selections.clone());
15040            });
15041            self.select_syntax_node_history.disable_clearing = false;
15042        }
15043
15044        let start_row = last_new.start.to_display_point(&display_map).row().0;
15045        let end_row = last_new.end.to_display_point(&display_map).row().0;
15046        let selection_height = end_row - start_row + 1;
15047        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15048
15049        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15050        let scroll_behavior = if fits_on_the_screen {
15051            self.request_autoscroll(Autoscroll::fit(), cx);
15052            SelectSyntaxNodeScrollBehavior::FitSelection
15053        } else if is_selection_reversed {
15054            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15055            SelectSyntaxNodeScrollBehavior::CursorTop
15056        } else {
15057            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15058            SelectSyntaxNodeScrollBehavior::CursorBottom
15059        };
15060
15061        self.select_syntax_node_history.push((
15062            old_selections,
15063            scroll_behavior,
15064            is_selection_reversed,
15065        ));
15066    }
15067
15068    pub fn select_smaller_syntax_node(
15069        &mut self,
15070        _: &SelectSmallerSyntaxNode,
15071        window: &mut Window,
15072        cx: &mut Context<Self>,
15073    ) {
15074        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15075
15076        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15077            self.select_syntax_node_history.pop()
15078        {
15079            if let Some(selection) = selections.last_mut() {
15080                selection.reversed = is_selection_reversed;
15081            }
15082
15083            self.select_syntax_node_history.disable_clearing = true;
15084            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15085                s.select(selections.to_vec());
15086            });
15087            self.select_syntax_node_history.disable_clearing = false;
15088
15089            match scroll_behavior {
15090                SelectSyntaxNodeScrollBehavior::CursorTop => {
15091                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15092                }
15093                SelectSyntaxNodeScrollBehavior::FitSelection => {
15094                    self.request_autoscroll(Autoscroll::fit(), cx);
15095                }
15096                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15097                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15098                }
15099            }
15100        }
15101    }
15102
15103    pub fn unwrap_syntax_node(
15104        &mut self,
15105        _: &UnwrapSyntaxNode,
15106        window: &mut Window,
15107        cx: &mut Context<Self>,
15108    ) {
15109        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15110
15111        let buffer = self.buffer.read(cx).snapshot(cx);
15112        let selections = self
15113            .selections
15114            .all::<usize>(cx)
15115            .into_iter()
15116            // subtracting the offset requires sorting
15117            .sorted_by_key(|i| i.start);
15118
15119        let full_edits = selections
15120            .into_iter()
15121            .filter_map(|selection| {
15122                // Only requires two branches once if-let-chains stabilize (#53667)
15123                let child = if !selection.is_empty() {
15124                    selection.range()
15125                } else if let Some((_, ancestor_range)) =
15126                    buffer.syntax_ancestor(selection.start..selection.end)
15127                {
15128                    match ancestor_range {
15129                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15130                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15131                    }
15132                } else {
15133                    selection.range()
15134                };
15135
15136                let mut parent = child.clone();
15137                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15138                    parent = match ancestor_range {
15139                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15140                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15141                    };
15142                    if parent.start < child.start || parent.end > child.end {
15143                        break;
15144                    }
15145                }
15146
15147                if parent == child {
15148                    return None;
15149                }
15150                let text = buffer.text_for_range(child).collect::<String>();
15151                Some((selection.id, parent, text))
15152            })
15153            .collect::<Vec<_>>();
15154
15155        self.transact(window, cx, |this, window, cx| {
15156            this.buffer.update(cx, |buffer, cx| {
15157                buffer.edit(
15158                    full_edits
15159                        .iter()
15160                        .map(|(_, p, t)| (p.clone(), t.clone()))
15161                        .collect::<Vec<_>>(),
15162                    None,
15163                    cx,
15164                );
15165            });
15166            this.change_selections(Default::default(), window, cx, |s| {
15167                let mut offset = 0;
15168                let mut selections = vec![];
15169                for (id, parent, text) in full_edits {
15170                    let start = parent.start - offset;
15171                    offset += parent.len() - text.len();
15172                    selections.push(Selection {
15173                        id,
15174                        start,
15175                        end: start + text.len(),
15176                        reversed: false,
15177                        goal: Default::default(),
15178                    });
15179                }
15180                s.select(selections);
15181            });
15182        });
15183    }
15184
15185    pub fn select_next_syntax_node(
15186        &mut self,
15187        _: &SelectNextSyntaxNode,
15188        window: &mut Window,
15189        cx: &mut Context<Self>,
15190    ) {
15191        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15192        if old_selections.is_empty() {
15193            return;
15194        }
15195
15196        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15197
15198        let buffer = self.buffer.read(cx).snapshot(cx);
15199        let mut selected_sibling = false;
15200
15201        let new_selections = old_selections
15202            .iter()
15203            .map(|selection| {
15204                let old_range = selection.start..selection.end;
15205
15206                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15207                    let new_range = node.byte_range();
15208                    selected_sibling = true;
15209                    Selection {
15210                        id: selection.id,
15211                        start: new_range.start,
15212                        end: new_range.end,
15213                        goal: SelectionGoal::None,
15214                        reversed: selection.reversed,
15215                    }
15216                } else {
15217                    selection.clone()
15218                }
15219            })
15220            .collect::<Vec<_>>();
15221
15222        if selected_sibling {
15223            self.change_selections(
15224                SelectionEffects::scroll(Autoscroll::fit()),
15225                window,
15226                cx,
15227                |s| {
15228                    s.select(new_selections);
15229                },
15230            );
15231        }
15232    }
15233
15234    pub fn select_prev_syntax_node(
15235        &mut self,
15236        _: &SelectPreviousSyntaxNode,
15237        window: &mut Window,
15238        cx: &mut Context<Self>,
15239    ) {
15240        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15241        if old_selections.is_empty() {
15242            return;
15243        }
15244
15245        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15246
15247        let buffer = self.buffer.read(cx).snapshot(cx);
15248        let mut selected_sibling = false;
15249
15250        let new_selections = old_selections
15251            .iter()
15252            .map(|selection| {
15253                let old_range = selection.start..selection.end;
15254
15255                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15256                    let new_range = node.byte_range();
15257                    selected_sibling = true;
15258                    Selection {
15259                        id: selection.id,
15260                        start: new_range.start,
15261                        end: new_range.end,
15262                        goal: SelectionGoal::None,
15263                        reversed: selection.reversed,
15264                    }
15265                } else {
15266                    selection.clone()
15267                }
15268            })
15269            .collect::<Vec<_>>();
15270
15271        if selected_sibling {
15272            self.change_selections(
15273                SelectionEffects::scroll(Autoscroll::fit()),
15274                window,
15275                cx,
15276                |s| {
15277                    s.select(new_selections);
15278                },
15279            );
15280        }
15281    }
15282
15283    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15284        if !EditorSettings::get_global(cx).gutter.runnables {
15285            self.clear_tasks();
15286            return Task::ready(());
15287        }
15288        let project = self.project().map(Entity::downgrade);
15289        let task_sources = self.lsp_task_sources(cx);
15290        let multi_buffer = self.buffer.downgrade();
15291        cx.spawn_in(window, async move |editor, cx| {
15292            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15293            let Some(project) = project.and_then(|p| p.upgrade()) else {
15294                return;
15295            };
15296            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15297                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15298            }) else {
15299                return;
15300            };
15301
15302            let hide_runnables = project
15303                .update(cx, |project, _| project.is_via_collab())
15304                .unwrap_or(true);
15305            if hide_runnables {
15306                return;
15307            }
15308            let new_rows =
15309                cx.background_spawn({
15310                    let snapshot = display_snapshot.clone();
15311                    async move {
15312                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15313                    }
15314                })
15315                    .await;
15316            let Ok(lsp_tasks) =
15317                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15318            else {
15319                return;
15320            };
15321            let lsp_tasks = lsp_tasks.await;
15322
15323            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15324                lsp_tasks
15325                    .into_iter()
15326                    .flat_map(|(kind, tasks)| {
15327                        tasks.into_iter().filter_map(move |(location, task)| {
15328                            Some((kind.clone(), location?, task))
15329                        })
15330                    })
15331                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15332                        let buffer = location.target.buffer;
15333                        let buffer_snapshot = buffer.read(cx).snapshot();
15334                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15335                            |(excerpt_id, snapshot, _)| {
15336                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15337                                    display_snapshot
15338                                        .buffer_snapshot
15339                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15340                                } else {
15341                                    None
15342                                }
15343                            },
15344                        );
15345                        if let Some(offset) = offset {
15346                            let task_buffer_range =
15347                                location.target.range.to_point(&buffer_snapshot);
15348                            let context_buffer_range =
15349                                task_buffer_range.to_offset(&buffer_snapshot);
15350                            let context_range = BufferOffset(context_buffer_range.start)
15351                                ..BufferOffset(context_buffer_range.end);
15352
15353                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15354                                .or_insert_with(|| RunnableTasks {
15355                                    templates: Vec::new(),
15356                                    offset,
15357                                    column: task_buffer_range.start.column,
15358                                    extra_variables: HashMap::default(),
15359                                    context_range,
15360                                })
15361                                .templates
15362                                .push((kind, task.original_task().clone()));
15363                        }
15364
15365                        acc
15366                    })
15367            }) else {
15368                return;
15369            };
15370
15371            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15372                buffer.language_settings(cx).tasks.prefer_lsp
15373            }) else {
15374                return;
15375            };
15376
15377            let rows = Self::runnable_rows(
15378                project,
15379                display_snapshot,
15380                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15381                new_rows,
15382                cx.clone(),
15383            )
15384            .await;
15385            editor
15386                .update(cx, |editor, _| {
15387                    editor.clear_tasks();
15388                    for (key, mut value) in rows {
15389                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15390                            value.templates.extend(lsp_tasks.templates);
15391                        }
15392
15393                        editor.insert_tasks(key, value);
15394                    }
15395                    for (key, value) in lsp_tasks_by_rows {
15396                        editor.insert_tasks(key, value);
15397                    }
15398                })
15399                .ok();
15400        })
15401    }
15402    fn fetch_runnable_ranges(
15403        snapshot: &DisplaySnapshot,
15404        range: Range<Anchor>,
15405    ) -> Vec<language::RunnableRange> {
15406        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15407    }
15408
15409    fn runnable_rows(
15410        project: Entity<Project>,
15411        snapshot: DisplaySnapshot,
15412        prefer_lsp: bool,
15413        runnable_ranges: Vec<RunnableRange>,
15414        cx: AsyncWindowContext,
15415    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15416        cx.spawn(async move |cx| {
15417            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15418            for mut runnable in runnable_ranges {
15419                let Some(tasks) = cx
15420                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15421                    .ok()
15422                else {
15423                    continue;
15424                };
15425                let mut tasks = tasks.await;
15426
15427                if prefer_lsp {
15428                    tasks.retain(|(task_kind, _)| {
15429                        !matches!(task_kind, TaskSourceKind::Language { .. })
15430                    });
15431                }
15432                if tasks.is_empty() {
15433                    continue;
15434                }
15435
15436                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15437                let Some(row) = snapshot
15438                    .buffer_snapshot
15439                    .buffer_line_for_row(MultiBufferRow(point.row))
15440                    .map(|(_, range)| range.start.row)
15441                else {
15442                    continue;
15443                };
15444
15445                let context_range =
15446                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15447                runnable_rows.push((
15448                    (runnable.buffer_id, row),
15449                    RunnableTasks {
15450                        templates: tasks,
15451                        offset: snapshot
15452                            .buffer_snapshot
15453                            .anchor_before(runnable.run_range.start),
15454                        context_range,
15455                        column: point.column,
15456                        extra_variables: runnable.extra_captures,
15457                    },
15458                ));
15459            }
15460            runnable_rows
15461        })
15462    }
15463
15464    fn templates_with_tags(
15465        project: &Entity<Project>,
15466        runnable: &mut Runnable,
15467        cx: &mut App,
15468    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15469        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15470            let (worktree_id, file) = project
15471                .buffer_for_id(runnable.buffer, cx)
15472                .and_then(|buffer| buffer.read(cx).file())
15473                .map(|file| (file.worktree_id(cx), file.clone()))
15474                .unzip();
15475
15476            (
15477                project.task_store().read(cx).task_inventory().cloned(),
15478                worktree_id,
15479                file,
15480            )
15481        });
15482
15483        let tags = mem::take(&mut runnable.tags);
15484        let language = runnable.language.clone();
15485        cx.spawn(async move |cx| {
15486            let mut templates_with_tags = Vec::new();
15487            if let Some(inventory) = inventory {
15488                for RunnableTag(tag) in tags {
15489                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15490                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15491                    }) else {
15492                        return templates_with_tags;
15493                    };
15494                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15495                        move |(_, template)| {
15496                            template.tags.iter().any(|source_tag| source_tag == &tag)
15497                        },
15498                    ));
15499                }
15500            }
15501            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15502
15503            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15504                // Strongest source wins; if we have worktree tag binding, prefer that to
15505                // global and language bindings;
15506                // if we have a global binding, prefer that to language binding.
15507                let first_mismatch = templates_with_tags
15508                    .iter()
15509                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15510                if let Some(index) = first_mismatch {
15511                    templates_with_tags.truncate(index);
15512                }
15513            }
15514
15515            templates_with_tags
15516        })
15517    }
15518
15519    pub fn move_to_enclosing_bracket(
15520        &mut self,
15521        _: &MoveToEnclosingBracket,
15522        window: &mut Window,
15523        cx: &mut Context<Self>,
15524    ) {
15525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15526        self.change_selections(Default::default(), window, cx, |s| {
15527            s.move_offsets_with(|snapshot, selection| {
15528                let Some(enclosing_bracket_ranges) =
15529                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15530                else {
15531                    return;
15532                };
15533
15534                let mut best_length = usize::MAX;
15535                let mut best_inside = false;
15536                let mut best_in_bracket_range = false;
15537                let mut best_destination = None;
15538                for (open, close) in enclosing_bracket_ranges {
15539                    let close = close.to_inclusive();
15540                    let length = close.end() - open.start;
15541                    let inside = selection.start >= open.end && selection.end <= *close.start();
15542                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15543                        || close.contains(&selection.head());
15544
15545                    // If best is next to a bracket and current isn't, skip
15546                    if !in_bracket_range && best_in_bracket_range {
15547                        continue;
15548                    }
15549
15550                    // Prefer smaller lengths unless best is inside and current isn't
15551                    if length > best_length && (best_inside || !inside) {
15552                        continue;
15553                    }
15554
15555                    best_length = length;
15556                    best_inside = inside;
15557                    best_in_bracket_range = in_bracket_range;
15558                    best_destination = Some(
15559                        if close.contains(&selection.start) && close.contains(&selection.end) {
15560                            if inside { open.end } else { open.start }
15561                        } else if inside {
15562                            *close.start()
15563                        } else {
15564                            *close.end()
15565                        },
15566                    );
15567                }
15568
15569                if let Some(destination) = best_destination {
15570                    selection.collapse_to(destination, SelectionGoal::None);
15571                }
15572            })
15573        });
15574    }
15575
15576    pub fn undo_selection(
15577        &mut self,
15578        _: &UndoSelection,
15579        window: &mut Window,
15580        cx: &mut Context<Self>,
15581    ) {
15582        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15583        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15584            self.selection_history.mode = SelectionHistoryMode::Undoing;
15585            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15586                this.end_selection(window, cx);
15587                this.change_selections(
15588                    SelectionEffects::scroll(Autoscroll::newest()),
15589                    window,
15590                    cx,
15591                    |s| s.select_anchors(entry.selections.to_vec()),
15592                );
15593            });
15594            self.selection_history.mode = SelectionHistoryMode::Normal;
15595
15596            self.select_next_state = entry.select_next_state;
15597            self.select_prev_state = entry.select_prev_state;
15598            self.add_selections_state = entry.add_selections_state;
15599        }
15600    }
15601
15602    pub fn redo_selection(
15603        &mut self,
15604        _: &RedoSelection,
15605        window: &mut Window,
15606        cx: &mut Context<Self>,
15607    ) {
15608        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15609        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15610            self.selection_history.mode = SelectionHistoryMode::Redoing;
15611            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15612                this.end_selection(window, cx);
15613                this.change_selections(
15614                    SelectionEffects::scroll(Autoscroll::newest()),
15615                    window,
15616                    cx,
15617                    |s| s.select_anchors(entry.selections.to_vec()),
15618                );
15619            });
15620            self.selection_history.mode = SelectionHistoryMode::Normal;
15621
15622            self.select_next_state = entry.select_next_state;
15623            self.select_prev_state = entry.select_prev_state;
15624            self.add_selections_state = entry.add_selections_state;
15625        }
15626    }
15627
15628    pub fn expand_excerpts(
15629        &mut self,
15630        action: &ExpandExcerpts,
15631        _: &mut Window,
15632        cx: &mut Context<Self>,
15633    ) {
15634        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15635    }
15636
15637    pub fn expand_excerpts_down(
15638        &mut self,
15639        action: &ExpandExcerptsDown,
15640        _: &mut Window,
15641        cx: &mut Context<Self>,
15642    ) {
15643        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15644    }
15645
15646    pub fn expand_excerpts_up(
15647        &mut self,
15648        action: &ExpandExcerptsUp,
15649        _: &mut Window,
15650        cx: &mut Context<Self>,
15651    ) {
15652        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15653    }
15654
15655    pub fn expand_excerpts_for_direction(
15656        &mut self,
15657        lines: u32,
15658        direction: ExpandExcerptDirection,
15659
15660        cx: &mut Context<Self>,
15661    ) {
15662        let selections = self.selections.disjoint_anchors();
15663
15664        let lines = if lines == 0 {
15665            EditorSettings::get_global(cx).expand_excerpt_lines
15666        } else {
15667            lines
15668        };
15669
15670        self.buffer.update(cx, |buffer, cx| {
15671            let snapshot = buffer.snapshot(cx);
15672            let mut excerpt_ids = selections
15673                .iter()
15674                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15675                .collect::<Vec<_>>();
15676            excerpt_ids.sort();
15677            excerpt_ids.dedup();
15678            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15679        })
15680    }
15681
15682    pub fn expand_excerpt(
15683        &mut self,
15684        excerpt: ExcerptId,
15685        direction: ExpandExcerptDirection,
15686        window: &mut Window,
15687        cx: &mut Context<Self>,
15688    ) {
15689        let current_scroll_position = self.scroll_position(cx);
15690        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15691        let mut should_scroll_up = false;
15692
15693        if direction == ExpandExcerptDirection::Down {
15694            let multi_buffer = self.buffer.read(cx);
15695            let snapshot = multi_buffer.snapshot(cx);
15696            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15697                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15698                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15699            {
15700                let buffer_snapshot = buffer.read(cx).snapshot();
15701                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15702                let last_row = buffer_snapshot.max_point().row;
15703                let lines_below = last_row.saturating_sub(excerpt_end_row);
15704                should_scroll_up = lines_below >= lines_to_expand;
15705            }
15706        }
15707
15708        self.buffer.update(cx, |buffer, cx| {
15709            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15710        });
15711
15712        if should_scroll_up {
15713            let new_scroll_position =
15714                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15715            self.set_scroll_position(new_scroll_position, window, cx);
15716        }
15717    }
15718
15719    pub fn go_to_singleton_buffer_point(
15720        &mut self,
15721        point: Point,
15722        window: &mut Window,
15723        cx: &mut Context<Self>,
15724    ) {
15725        self.go_to_singleton_buffer_range(point..point, window, cx);
15726    }
15727
15728    pub fn go_to_singleton_buffer_range(
15729        &mut self,
15730        range: Range<Point>,
15731        window: &mut Window,
15732        cx: &mut Context<Self>,
15733    ) {
15734        let multibuffer = self.buffer().read(cx);
15735        let Some(buffer) = multibuffer.as_singleton() else {
15736            return;
15737        };
15738        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15739            return;
15740        };
15741        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15742            return;
15743        };
15744        self.change_selections(
15745            SelectionEffects::default().nav_history(true),
15746            window,
15747            cx,
15748            |s| s.select_anchor_ranges([start..end]),
15749        );
15750    }
15751
15752    pub fn go_to_diagnostic(
15753        &mut self,
15754        action: &GoToDiagnostic,
15755        window: &mut Window,
15756        cx: &mut Context<Self>,
15757    ) {
15758        if !self.diagnostics_enabled() {
15759            return;
15760        }
15761        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15762        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15763    }
15764
15765    pub fn go_to_prev_diagnostic(
15766        &mut self,
15767        action: &GoToPreviousDiagnostic,
15768        window: &mut Window,
15769        cx: &mut Context<Self>,
15770    ) {
15771        if !self.diagnostics_enabled() {
15772            return;
15773        }
15774        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15775        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15776    }
15777
15778    pub fn go_to_diagnostic_impl(
15779        &mut self,
15780        direction: Direction,
15781        severity: GoToDiagnosticSeverityFilter,
15782        window: &mut Window,
15783        cx: &mut Context<Self>,
15784    ) {
15785        let buffer = self.buffer.read(cx).snapshot(cx);
15786        let selection = self.selections.newest::<usize>(cx);
15787
15788        let mut active_group_id = None;
15789        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15790            && active_group.active_range.start.to_offset(&buffer) == selection.start
15791        {
15792            active_group_id = Some(active_group.group_id);
15793        }
15794
15795        fn filtered(
15796            snapshot: EditorSnapshot,
15797            severity: GoToDiagnosticSeverityFilter,
15798            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15799        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15800            diagnostics
15801                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15802                .filter(|entry| entry.range.start != entry.range.end)
15803                .filter(|entry| !entry.diagnostic.is_unnecessary)
15804                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15805        }
15806
15807        let snapshot = self.snapshot(window, cx);
15808        let before = filtered(
15809            snapshot.clone(),
15810            severity,
15811            buffer
15812                .diagnostics_in_range(0..selection.start)
15813                .filter(|entry| entry.range.start <= selection.start),
15814        );
15815        let after = filtered(
15816            snapshot,
15817            severity,
15818            buffer
15819                .diagnostics_in_range(selection.start..buffer.len())
15820                .filter(|entry| entry.range.start >= selection.start),
15821        );
15822
15823        let mut found: Option<DiagnosticEntry<usize>> = None;
15824        if direction == Direction::Prev {
15825            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15826            {
15827                for diagnostic in prev_diagnostics.into_iter().rev() {
15828                    if diagnostic.range.start != selection.start
15829                        || active_group_id
15830                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15831                    {
15832                        found = Some(diagnostic);
15833                        break 'outer;
15834                    }
15835                }
15836            }
15837        } else {
15838            for diagnostic in after.chain(before) {
15839                if diagnostic.range.start != selection.start
15840                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15841                {
15842                    found = Some(diagnostic);
15843                    break;
15844                }
15845            }
15846        }
15847        let Some(next_diagnostic) = found else {
15848            return;
15849        };
15850
15851        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15852        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15853            return;
15854        };
15855        self.change_selections(Default::default(), window, cx, |s| {
15856            s.select_ranges(vec![
15857                next_diagnostic.range.start..next_diagnostic.range.start,
15858            ])
15859        });
15860        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15861        self.refresh_edit_prediction(false, true, window, cx);
15862    }
15863
15864    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15865        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15866        let snapshot = self.snapshot(window, cx);
15867        let selection = self.selections.newest::<Point>(cx);
15868        self.go_to_hunk_before_or_after_position(
15869            &snapshot,
15870            selection.head(),
15871            Direction::Next,
15872            window,
15873            cx,
15874        );
15875    }
15876
15877    pub fn go_to_hunk_before_or_after_position(
15878        &mut self,
15879        snapshot: &EditorSnapshot,
15880        position: Point,
15881        direction: Direction,
15882        window: &mut Window,
15883        cx: &mut Context<Editor>,
15884    ) {
15885        let row = if direction == Direction::Next {
15886            self.hunk_after_position(snapshot, position)
15887                .map(|hunk| hunk.row_range.start)
15888        } else {
15889            self.hunk_before_position(snapshot, position)
15890        };
15891
15892        if let Some(row) = row {
15893            let destination = Point::new(row.0, 0);
15894            let autoscroll = Autoscroll::center();
15895
15896            self.unfold_ranges(&[destination..destination], false, false, cx);
15897            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15898                s.select_ranges([destination..destination]);
15899            });
15900        }
15901    }
15902
15903    fn hunk_after_position(
15904        &mut self,
15905        snapshot: &EditorSnapshot,
15906        position: Point,
15907    ) -> Option<MultiBufferDiffHunk> {
15908        snapshot
15909            .buffer_snapshot
15910            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15911            .find(|hunk| hunk.row_range.start.0 > position.row)
15912            .or_else(|| {
15913                snapshot
15914                    .buffer_snapshot
15915                    .diff_hunks_in_range(Point::zero()..position)
15916                    .find(|hunk| hunk.row_range.end.0 < position.row)
15917            })
15918    }
15919
15920    fn go_to_prev_hunk(
15921        &mut self,
15922        _: &GoToPreviousHunk,
15923        window: &mut Window,
15924        cx: &mut Context<Self>,
15925    ) {
15926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15927        let snapshot = self.snapshot(window, cx);
15928        let selection = self.selections.newest::<Point>(cx);
15929        self.go_to_hunk_before_or_after_position(
15930            &snapshot,
15931            selection.head(),
15932            Direction::Prev,
15933            window,
15934            cx,
15935        );
15936    }
15937
15938    fn hunk_before_position(
15939        &mut self,
15940        snapshot: &EditorSnapshot,
15941        position: Point,
15942    ) -> Option<MultiBufferRow> {
15943        snapshot
15944            .buffer_snapshot
15945            .diff_hunk_before(position)
15946            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15947    }
15948
15949    fn go_to_next_change(
15950        &mut self,
15951        _: &GoToNextChange,
15952        window: &mut Window,
15953        cx: &mut Context<Self>,
15954    ) {
15955        if let Some(selections) = self
15956            .change_list
15957            .next_change(1, Direction::Next)
15958            .map(|s| s.to_vec())
15959        {
15960            self.change_selections(Default::default(), window, cx, |s| {
15961                let map = s.display_map();
15962                s.select_display_ranges(selections.iter().map(|a| {
15963                    let point = a.to_display_point(&map);
15964                    point..point
15965                }))
15966            })
15967        }
15968    }
15969
15970    fn go_to_previous_change(
15971        &mut self,
15972        _: &GoToPreviousChange,
15973        window: &mut Window,
15974        cx: &mut Context<Self>,
15975    ) {
15976        if let Some(selections) = self
15977            .change_list
15978            .next_change(1, Direction::Prev)
15979            .map(|s| s.to_vec())
15980        {
15981            self.change_selections(Default::default(), window, cx, |s| {
15982                let map = s.display_map();
15983                s.select_display_ranges(selections.iter().map(|a| {
15984                    let point = a.to_display_point(&map);
15985                    point..point
15986                }))
15987            })
15988        }
15989    }
15990
15991    pub fn go_to_next_document_highlight(
15992        &mut self,
15993        _: &GoToNextDocumentHighlight,
15994        window: &mut Window,
15995        cx: &mut Context<Self>,
15996    ) {
15997        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
15998    }
15999
16000    pub fn go_to_prev_document_highlight(
16001        &mut self,
16002        _: &GoToPreviousDocumentHighlight,
16003        window: &mut Window,
16004        cx: &mut Context<Self>,
16005    ) {
16006        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16007    }
16008
16009    pub fn go_to_document_highlight_before_or_after_position(
16010        &mut self,
16011        direction: Direction,
16012        window: &mut Window,
16013        cx: &mut Context<Editor>,
16014    ) {
16015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16016        let snapshot = self.snapshot(window, cx);
16017        let buffer = &snapshot.buffer_snapshot;
16018        let position = self.selections.newest::<Point>(cx).head();
16019        let anchor_position = buffer.anchor_after(position);
16020
16021        // Get all document highlights (both read and write)
16022        let mut all_highlights = Vec::new();
16023
16024        if let Some((_, read_highlights)) = self
16025            .background_highlights
16026            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16027        {
16028            all_highlights.extend(read_highlights.iter());
16029        }
16030
16031        if let Some((_, write_highlights)) = self
16032            .background_highlights
16033            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16034        {
16035            all_highlights.extend(write_highlights.iter());
16036        }
16037
16038        if all_highlights.is_empty() {
16039            return;
16040        }
16041
16042        // Sort highlights by position
16043        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16044
16045        let target_highlight = match direction {
16046            Direction::Next => {
16047                // Find the first highlight after the current position
16048                all_highlights
16049                    .iter()
16050                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16051            }
16052            Direction::Prev => {
16053                // Find the last highlight before the current position
16054                all_highlights
16055                    .iter()
16056                    .rev()
16057                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16058            }
16059        };
16060
16061        if let Some(highlight) = target_highlight {
16062            let destination = highlight.start.to_point(buffer);
16063            let autoscroll = Autoscroll::center();
16064
16065            self.unfold_ranges(&[destination..destination], false, false, cx);
16066            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16067                s.select_ranges([destination..destination]);
16068            });
16069        }
16070    }
16071
16072    fn go_to_line<T: 'static>(
16073        &mut self,
16074        position: Anchor,
16075        highlight_color: Option<Hsla>,
16076        window: &mut Window,
16077        cx: &mut Context<Self>,
16078    ) {
16079        let snapshot = self.snapshot(window, cx).display_snapshot;
16080        let position = position.to_point(&snapshot.buffer_snapshot);
16081        let start = snapshot
16082            .buffer_snapshot
16083            .clip_point(Point::new(position.row, 0), Bias::Left);
16084        let end = start + Point::new(1, 0);
16085        let start = snapshot.buffer_snapshot.anchor_before(start);
16086        let end = snapshot.buffer_snapshot.anchor_before(end);
16087
16088        self.highlight_rows::<T>(
16089            start..end,
16090            highlight_color
16091                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16092            Default::default(),
16093            cx,
16094        );
16095
16096        if self.buffer.read(cx).is_singleton() {
16097            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16098        }
16099    }
16100
16101    pub fn go_to_definition(
16102        &mut self,
16103        _: &GoToDefinition,
16104        window: &mut Window,
16105        cx: &mut Context<Self>,
16106    ) -> Task<Result<Navigated>> {
16107        let definition =
16108            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16109        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16110        cx.spawn_in(window, async move |editor, cx| {
16111            if definition.await? == Navigated::Yes {
16112                return Ok(Navigated::Yes);
16113            }
16114            match fallback_strategy {
16115                GoToDefinitionFallback::None => Ok(Navigated::No),
16116                GoToDefinitionFallback::FindAllReferences => {
16117                    match editor.update_in(cx, |editor, window, cx| {
16118                        editor.find_all_references(&FindAllReferences, window, cx)
16119                    })? {
16120                        Some(references) => references.await,
16121                        None => Ok(Navigated::No),
16122                    }
16123                }
16124            }
16125        })
16126    }
16127
16128    pub fn go_to_declaration(
16129        &mut self,
16130        _: &GoToDeclaration,
16131        window: &mut Window,
16132        cx: &mut Context<Self>,
16133    ) -> Task<Result<Navigated>> {
16134        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16135    }
16136
16137    pub fn go_to_declaration_split(
16138        &mut self,
16139        _: &GoToDeclaration,
16140        window: &mut Window,
16141        cx: &mut Context<Self>,
16142    ) -> Task<Result<Navigated>> {
16143        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16144    }
16145
16146    pub fn go_to_implementation(
16147        &mut self,
16148        _: &GoToImplementation,
16149        window: &mut Window,
16150        cx: &mut Context<Self>,
16151    ) -> Task<Result<Navigated>> {
16152        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16153    }
16154
16155    pub fn go_to_implementation_split(
16156        &mut self,
16157        _: &GoToImplementationSplit,
16158        window: &mut Window,
16159        cx: &mut Context<Self>,
16160    ) -> Task<Result<Navigated>> {
16161        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16162    }
16163
16164    pub fn go_to_type_definition(
16165        &mut self,
16166        _: &GoToTypeDefinition,
16167        window: &mut Window,
16168        cx: &mut Context<Self>,
16169    ) -> Task<Result<Navigated>> {
16170        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16171    }
16172
16173    pub fn go_to_definition_split(
16174        &mut self,
16175        _: &GoToDefinitionSplit,
16176        window: &mut Window,
16177        cx: &mut Context<Self>,
16178    ) -> Task<Result<Navigated>> {
16179        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16180    }
16181
16182    pub fn go_to_type_definition_split(
16183        &mut self,
16184        _: &GoToTypeDefinitionSplit,
16185        window: &mut Window,
16186        cx: &mut Context<Self>,
16187    ) -> Task<Result<Navigated>> {
16188        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16189    }
16190
16191    fn go_to_definition_of_kind(
16192        &mut self,
16193        kind: GotoDefinitionKind,
16194        split: bool,
16195        window: &mut Window,
16196        cx: &mut Context<Self>,
16197    ) -> Task<Result<Navigated>> {
16198        let Some(provider) = self.semantics_provider.clone() else {
16199            return Task::ready(Ok(Navigated::No));
16200        };
16201        let head = self.selections.newest::<usize>(cx).head();
16202        let buffer = self.buffer.read(cx);
16203        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16204            return Task::ready(Ok(Navigated::No));
16205        };
16206        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16207            return Task::ready(Ok(Navigated::No));
16208        };
16209
16210        cx.spawn_in(window, async move |editor, cx| {
16211            let Some(definitions) = definitions.await? else {
16212                return Ok(Navigated::No);
16213            };
16214            let navigated = editor
16215                .update_in(cx, |editor, window, cx| {
16216                    editor.navigate_to_hover_links(
16217                        Some(kind),
16218                        definitions
16219                            .into_iter()
16220                            .filter(|location| {
16221                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16222                            })
16223                            .map(HoverLink::Text)
16224                            .collect::<Vec<_>>(),
16225                        split,
16226                        window,
16227                        cx,
16228                    )
16229                })?
16230                .await?;
16231            anyhow::Ok(navigated)
16232        })
16233    }
16234
16235    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16236        let selection = self.selections.newest_anchor();
16237        let head = selection.head();
16238        let tail = selection.tail();
16239
16240        let Some((buffer, start_position)) =
16241            self.buffer.read(cx).text_anchor_for_position(head, cx)
16242        else {
16243            return;
16244        };
16245
16246        let end_position = if head != tail {
16247            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16248                return;
16249            };
16250            Some(pos)
16251        } else {
16252            None
16253        };
16254
16255        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16256            let url = if let Some(end_pos) = end_position {
16257                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16258            } else {
16259                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16260            };
16261
16262            if let Some(url) = url {
16263                editor.update(cx, |_, cx| {
16264                    cx.open_url(&url);
16265                })
16266            } else {
16267                Ok(())
16268            }
16269        });
16270
16271        url_finder.detach();
16272    }
16273
16274    pub fn open_selected_filename(
16275        &mut self,
16276        _: &OpenSelectedFilename,
16277        window: &mut Window,
16278        cx: &mut Context<Self>,
16279    ) {
16280        let Some(workspace) = self.workspace() else {
16281            return;
16282        };
16283
16284        let position = self.selections.newest_anchor().head();
16285
16286        let Some((buffer, buffer_position)) =
16287            self.buffer.read(cx).text_anchor_for_position(position, cx)
16288        else {
16289            return;
16290        };
16291
16292        let project = self.project.clone();
16293
16294        cx.spawn_in(window, async move |_, cx| {
16295            let result = find_file(&buffer, project, buffer_position, cx).await;
16296
16297            if let Some((_, path)) = result {
16298                workspace
16299                    .update_in(cx, |workspace, window, cx| {
16300                        workspace.open_resolved_path(path, window, cx)
16301                    })?
16302                    .await?;
16303            }
16304            anyhow::Ok(())
16305        })
16306        .detach();
16307    }
16308
16309    pub(crate) fn navigate_to_hover_links(
16310        &mut self,
16311        kind: Option<GotoDefinitionKind>,
16312        definitions: Vec<HoverLink>,
16313        split: bool,
16314        window: &mut Window,
16315        cx: &mut Context<Editor>,
16316    ) -> Task<Result<Navigated>> {
16317        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16318        let mut first_url_or_file = None;
16319        let definitions: Vec<_> = definitions
16320            .into_iter()
16321            .filter_map(|def| match def {
16322                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16323                HoverLink::InlayHint(lsp_location, server_id) => {
16324                    let computation =
16325                        self.compute_target_location(lsp_location, server_id, window, cx);
16326                    Some(cx.background_spawn(computation))
16327                }
16328                HoverLink::Url(url) => {
16329                    first_url_or_file = Some(Either::Left(url));
16330                    None
16331                }
16332                HoverLink::File(path) => {
16333                    first_url_or_file = Some(Either::Right(path));
16334                    None
16335                }
16336            })
16337            .collect();
16338
16339        let workspace = self.workspace();
16340
16341        cx.spawn_in(window, async move |editor, acx| {
16342            let mut locations: Vec<Location> = future::join_all(definitions)
16343                .await
16344                .into_iter()
16345                .filter_map(|location| location.transpose())
16346                .collect::<Result<_>>()
16347                .context("location tasks")?;
16348
16349            if locations.len() > 1 {
16350                let Some(workspace) = workspace else {
16351                    return Ok(Navigated::No);
16352                };
16353
16354                let tab_kind = match kind {
16355                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16356                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16357                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16358                    Some(GotoDefinitionKind::Type) => "Types",
16359                };
16360                let title = editor
16361                    .update_in(acx, |_, _, cx| {
16362                        let target = locations
16363                            .iter()
16364                            .map(|location| {
16365                                location
16366                                    .buffer
16367                                    .read(cx)
16368                                    .text_for_range(location.range.clone())
16369                                    .collect::<String>()
16370                            })
16371                            .filter(|text| !text.contains('\n'))
16372                            .unique()
16373                            .take(3)
16374                            .join(", ");
16375                        if target.is_empty() {
16376                            tab_kind.to_owned()
16377                        } else {
16378                            format!("{tab_kind} for {target}")
16379                        }
16380                    })
16381                    .context("buffer title")?;
16382
16383                let opened = workspace
16384                    .update_in(acx, |workspace, window, cx| {
16385                        Self::open_locations_in_multibuffer(
16386                            workspace,
16387                            locations,
16388                            title,
16389                            split,
16390                            MultibufferSelectionMode::First,
16391                            window,
16392                            cx,
16393                        )
16394                    })
16395                    .is_ok();
16396
16397                anyhow::Ok(Navigated::from_bool(opened))
16398            } else if locations.is_empty() {
16399                // If there is one definition, just open it directly
16400                match first_url_or_file {
16401                    Some(Either::Left(url)) => {
16402                        acx.update(|_, cx| cx.open_url(&url))?;
16403                        Ok(Navigated::Yes)
16404                    }
16405                    Some(Either::Right(path)) => {
16406                        let Some(workspace) = workspace else {
16407                            return Ok(Navigated::No);
16408                        };
16409
16410                        workspace
16411                            .update_in(acx, |workspace, window, cx| {
16412                                workspace.open_resolved_path(path, window, cx)
16413                            })?
16414                            .await?;
16415                        Ok(Navigated::Yes)
16416                    }
16417                    None => Ok(Navigated::No),
16418                }
16419            } else {
16420                let Some(workspace) = workspace else {
16421                    return Ok(Navigated::No);
16422                };
16423
16424                let target = locations.pop().unwrap();
16425                editor.update_in(acx, |editor, window, cx| {
16426                    let pane = workspace.read(cx).active_pane().clone();
16427
16428                    let range = target.range.to_point(target.buffer.read(cx));
16429                    let range = editor.range_for_match(&range);
16430                    let range = collapse_multiline_range(range);
16431
16432                    if !split
16433                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16434                    {
16435                        editor.go_to_singleton_buffer_range(range, window, cx);
16436                    } else {
16437                        window.defer(cx, move |window, cx| {
16438                            let target_editor: Entity<Self> =
16439                                workspace.update(cx, |workspace, cx| {
16440                                    let pane = if split {
16441                                        workspace.adjacent_pane(window, cx)
16442                                    } else {
16443                                        workspace.active_pane().clone()
16444                                    };
16445
16446                                    workspace.open_project_item(
16447                                        pane,
16448                                        target.buffer.clone(),
16449                                        true,
16450                                        true,
16451                                        window,
16452                                        cx,
16453                                    )
16454                                });
16455                            target_editor.update(cx, |target_editor, cx| {
16456                                // When selecting a definition in a different buffer, disable the nav history
16457                                // to avoid creating a history entry at the previous cursor location.
16458                                pane.update(cx, |pane, _| pane.disable_history());
16459                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16460                                pane.update(cx, |pane, _| pane.enable_history());
16461                            });
16462                        });
16463                    }
16464                    Navigated::Yes
16465                })
16466            }
16467        })
16468    }
16469
16470    fn compute_target_location(
16471        &self,
16472        lsp_location: lsp::Location,
16473        server_id: LanguageServerId,
16474        window: &mut Window,
16475        cx: &mut Context<Self>,
16476    ) -> Task<anyhow::Result<Option<Location>>> {
16477        let Some(project) = self.project.clone() else {
16478            return Task::ready(Ok(None));
16479        };
16480
16481        cx.spawn_in(window, async move |editor, cx| {
16482            let location_task = editor.update(cx, |_, cx| {
16483                project.update(cx, |project, cx| {
16484                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16485                })
16486            })?;
16487            let location = Some({
16488                let target_buffer_handle = location_task.await.context("open local buffer")?;
16489                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16490                    let target_start = target_buffer
16491                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16492                    let target_end = target_buffer
16493                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16494                    target_buffer.anchor_after(target_start)
16495                        ..target_buffer.anchor_before(target_end)
16496                })?;
16497                Location {
16498                    buffer: target_buffer_handle,
16499                    range,
16500                }
16501            });
16502            Ok(location)
16503        })
16504    }
16505
16506    pub fn find_all_references(
16507        &mut self,
16508        _: &FindAllReferences,
16509        window: &mut Window,
16510        cx: &mut Context<Self>,
16511    ) -> Option<Task<Result<Navigated>>> {
16512        let selection = self.selections.newest::<usize>(cx);
16513        let multi_buffer = self.buffer.read(cx);
16514        let head = selection.head();
16515
16516        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16517        let head_anchor = multi_buffer_snapshot.anchor_at(
16518            head,
16519            if head < selection.tail() {
16520                Bias::Right
16521            } else {
16522                Bias::Left
16523            },
16524        );
16525
16526        match self
16527            .find_all_references_task_sources
16528            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16529        {
16530            Ok(_) => {
16531                log::info!(
16532                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16533                );
16534                return None;
16535            }
16536            Err(i) => {
16537                self.find_all_references_task_sources.insert(i, head_anchor);
16538            }
16539        }
16540
16541        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16542        let workspace = self.workspace()?;
16543        let project = workspace.read(cx).project().clone();
16544        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16545        Some(cx.spawn_in(window, async move |editor, cx| {
16546            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16547                if let Ok(i) = editor
16548                    .find_all_references_task_sources
16549                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16550                {
16551                    editor.find_all_references_task_sources.remove(i);
16552                }
16553            });
16554
16555            let Some(locations) = references.await? else {
16556                return anyhow::Ok(Navigated::No);
16557            };
16558            if locations.is_empty() {
16559                return anyhow::Ok(Navigated::No);
16560            }
16561
16562            workspace.update_in(cx, |workspace, window, cx| {
16563                let target = locations
16564                    .iter()
16565                    .map(|location| {
16566                        location
16567                            .buffer
16568                            .read(cx)
16569                            .text_for_range(location.range.clone())
16570                            .collect::<String>()
16571                    })
16572                    .filter(|text| !text.contains('\n'))
16573                    .unique()
16574                    .take(3)
16575                    .join(", ");
16576                let title = if target.is_empty() {
16577                    "References".to_owned()
16578                } else {
16579                    format!("References to {target}")
16580                };
16581                Self::open_locations_in_multibuffer(
16582                    workspace,
16583                    locations,
16584                    title,
16585                    false,
16586                    MultibufferSelectionMode::First,
16587                    window,
16588                    cx,
16589                );
16590                Navigated::Yes
16591            })
16592        }))
16593    }
16594
16595    /// Opens a multibuffer with the given project locations in it
16596    pub fn open_locations_in_multibuffer(
16597        workspace: &mut Workspace,
16598        mut locations: Vec<Location>,
16599        title: String,
16600        split: bool,
16601        multibuffer_selection_mode: MultibufferSelectionMode,
16602        window: &mut Window,
16603        cx: &mut Context<Workspace>,
16604    ) {
16605        if locations.is_empty() {
16606            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16607            return;
16608        }
16609
16610        // If there are multiple definitions, open them in a multibuffer
16611        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16612        let mut locations = locations.into_iter().peekable();
16613        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16614        let capability = workspace.project().read(cx).capability();
16615
16616        let excerpt_buffer = cx.new(|cx| {
16617            let mut multibuffer = MultiBuffer::new(capability);
16618            while let Some(location) = locations.next() {
16619                let buffer = location.buffer.read(cx);
16620                let mut ranges_for_buffer = Vec::new();
16621                let range = location.range.to_point(buffer);
16622                ranges_for_buffer.push(range.clone());
16623
16624                while let Some(next_location) = locations.peek() {
16625                    if next_location.buffer == location.buffer {
16626                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16627                        locations.next();
16628                    } else {
16629                        break;
16630                    }
16631                }
16632
16633                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16634                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16635                    PathKey::for_buffer(&location.buffer, cx),
16636                    location.buffer.clone(),
16637                    ranges_for_buffer,
16638                    multibuffer_context_lines(cx),
16639                    cx,
16640                );
16641                ranges.extend(new_ranges)
16642            }
16643
16644            multibuffer.with_title(title)
16645        });
16646
16647        let editor = cx.new(|cx| {
16648            Editor::for_multibuffer(
16649                excerpt_buffer,
16650                Some(workspace.project().clone()),
16651                window,
16652                cx,
16653            )
16654        });
16655        editor.update(cx, |editor, cx| {
16656            match multibuffer_selection_mode {
16657                MultibufferSelectionMode::First => {
16658                    if let Some(first_range) = ranges.first() {
16659                        editor.change_selections(
16660                            SelectionEffects::no_scroll(),
16661                            window,
16662                            cx,
16663                            |selections| {
16664                                selections.clear_disjoint();
16665                                selections
16666                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16667                            },
16668                        );
16669                    }
16670                    editor.highlight_background::<Self>(
16671                        &ranges,
16672                        |theme| theme.colors().editor_highlighted_line_background,
16673                        cx,
16674                    );
16675                }
16676                MultibufferSelectionMode::All => {
16677                    editor.change_selections(
16678                        SelectionEffects::no_scroll(),
16679                        window,
16680                        cx,
16681                        |selections| {
16682                            selections.clear_disjoint();
16683                            selections.select_anchor_ranges(ranges);
16684                        },
16685                    );
16686                }
16687            }
16688            editor.register_buffers_with_language_servers(cx);
16689        });
16690
16691        let item = Box::new(editor);
16692        let item_id = item.item_id();
16693
16694        if split {
16695            workspace.split_item(SplitDirection::Right, item, window, cx);
16696        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16697            let (preview_item_id, preview_item_idx) =
16698                workspace.active_pane().read_with(cx, |pane, _| {
16699                    (pane.preview_item_id(), pane.preview_item_idx())
16700                });
16701
16702            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16703
16704            if let Some(preview_item_id) = preview_item_id {
16705                workspace.active_pane().update(cx, |pane, cx| {
16706                    pane.remove_item(preview_item_id, false, false, window, cx);
16707                });
16708            }
16709        } else {
16710            workspace.add_item_to_active_pane(item, None, true, window, cx);
16711        }
16712        workspace.active_pane().update(cx, |pane, cx| {
16713            pane.set_preview_item_id(Some(item_id), cx);
16714        });
16715    }
16716
16717    pub fn rename(
16718        &mut self,
16719        _: &Rename,
16720        window: &mut Window,
16721        cx: &mut Context<Self>,
16722    ) -> Option<Task<Result<()>>> {
16723        use language::ToOffset as _;
16724
16725        let provider = self.semantics_provider.clone()?;
16726        let selection = self.selections.newest_anchor().clone();
16727        let (cursor_buffer, cursor_buffer_position) = self
16728            .buffer
16729            .read(cx)
16730            .text_anchor_for_position(selection.head(), cx)?;
16731        let (tail_buffer, cursor_buffer_position_end) = self
16732            .buffer
16733            .read(cx)
16734            .text_anchor_for_position(selection.tail(), cx)?;
16735        if tail_buffer != cursor_buffer {
16736            return None;
16737        }
16738
16739        let snapshot = cursor_buffer.read(cx).snapshot();
16740        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16741        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16742        let prepare_rename = provider
16743            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16744            .unwrap_or_else(|| Task::ready(Ok(None)));
16745        drop(snapshot);
16746
16747        Some(cx.spawn_in(window, async move |this, cx| {
16748            let rename_range = if let Some(range) = prepare_rename.await? {
16749                Some(range)
16750            } else {
16751                this.update(cx, |this, cx| {
16752                    let buffer = this.buffer.read(cx).snapshot(cx);
16753                    let mut buffer_highlights = this
16754                        .document_highlights_for_position(selection.head(), &buffer)
16755                        .filter(|highlight| {
16756                            highlight.start.excerpt_id == selection.head().excerpt_id
16757                                && highlight.end.excerpt_id == selection.head().excerpt_id
16758                        });
16759                    buffer_highlights
16760                        .next()
16761                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16762                })?
16763            };
16764            if let Some(rename_range) = rename_range {
16765                this.update_in(cx, |this, window, cx| {
16766                    let snapshot = cursor_buffer.read(cx).snapshot();
16767                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16768                    let cursor_offset_in_rename_range =
16769                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16770                    let cursor_offset_in_rename_range_end =
16771                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16772
16773                    this.take_rename(false, window, cx);
16774                    let buffer = this.buffer.read(cx).read(cx);
16775                    let cursor_offset = selection.head().to_offset(&buffer);
16776                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16777                    let rename_end = rename_start + rename_buffer_range.len();
16778                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16779                    let mut old_highlight_id = None;
16780                    let old_name: Arc<str> = buffer
16781                        .chunks(rename_start..rename_end, true)
16782                        .map(|chunk| {
16783                            if old_highlight_id.is_none() {
16784                                old_highlight_id = chunk.syntax_highlight_id;
16785                            }
16786                            chunk.text
16787                        })
16788                        .collect::<String>()
16789                        .into();
16790
16791                    drop(buffer);
16792
16793                    // Position the selection in the rename editor so that it matches the current selection.
16794                    this.show_local_selections = false;
16795                    let rename_editor = cx.new(|cx| {
16796                        let mut editor = Editor::single_line(window, cx);
16797                        editor.buffer.update(cx, |buffer, cx| {
16798                            buffer.edit([(0..0, old_name.clone())], None, cx)
16799                        });
16800                        let rename_selection_range = match cursor_offset_in_rename_range
16801                            .cmp(&cursor_offset_in_rename_range_end)
16802                        {
16803                            Ordering::Equal => {
16804                                editor.select_all(&SelectAll, window, cx);
16805                                return editor;
16806                            }
16807                            Ordering::Less => {
16808                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16809                            }
16810                            Ordering::Greater => {
16811                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16812                            }
16813                        };
16814                        if rename_selection_range.end > old_name.len() {
16815                            editor.select_all(&SelectAll, window, cx);
16816                        } else {
16817                            editor.change_selections(Default::default(), window, cx, |s| {
16818                                s.select_ranges([rename_selection_range]);
16819                            });
16820                        }
16821                        editor
16822                    });
16823                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16824                        if e == &EditorEvent::Focused {
16825                            cx.emit(EditorEvent::FocusedIn)
16826                        }
16827                    })
16828                    .detach();
16829
16830                    let write_highlights =
16831                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16832                    let read_highlights =
16833                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16834                    let ranges = write_highlights
16835                        .iter()
16836                        .flat_map(|(_, ranges)| ranges.iter())
16837                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16838                        .cloned()
16839                        .collect();
16840
16841                    this.highlight_text::<Rename>(
16842                        ranges,
16843                        HighlightStyle {
16844                            fade_out: Some(0.6),
16845                            ..Default::default()
16846                        },
16847                        cx,
16848                    );
16849                    let rename_focus_handle = rename_editor.focus_handle(cx);
16850                    window.focus(&rename_focus_handle);
16851                    let block_id = this.insert_blocks(
16852                        [BlockProperties {
16853                            style: BlockStyle::Flex,
16854                            placement: BlockPlacement::Below(range.start),
16855                            height: Some(1),
16856                            render: Arc::new({
16857                                let rename_editor = rename_editor.clone();
16858                                move |cx: &mut BlockContext| {
16859                                    let mut text_style = cx.editor_style.text.clone();
16860                                    if let Some(highlight_style) = old_highlight_id
16861                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16862                                    {
16863                                        text_style = text_style.highlight(highlight_style);
16864                                    }
16865                                    div()
16866                                        .block_mouse_except_scroll()
16867                                        .pl(cx.anchor_x)
16868                                        .child(EditorElement::new(
16869                                            &rename_editor,
16870                                            EditorStyle {
16871                                                background: cx.theme().system().transparent,
16872                                                local_player: cx.editor_style.local_player,
16873                                                text: text_style,
16874                                                scrollbar_width: cx.editor_style.scrollbar_width,
16875                                                syntax: cx.editor_style.syntax.clone(),
16876                                                status: cx.editor_style.status.clone(),
16877                                                inlay_hints_style: HighlightStyle {
16878                                                    font_weight: Some(FontWeight::BOLD),
16879                                                    ..make_inlay_hints_style(cx.app)
16880                                                },
16881                                                edit_prediction_styles: make_suggestion_styles(
16882                                                    cx.app,
16883                                                ),
16884                                                ..EditorStyle::default()
16885                                            },
16886                                        ))
16887                                        .into_any_element()
16888                                }
16889                            }),
16890                            priority: 0,
16891                        }],
16892                        Some(Autoscroll::fit()),
16893                        cx,
16894                    )[0];
16895                    this.pending_rename = Some(RenameState {
16896                        range,
16897                        old_name,
16898                        editor: rename_editor,
16899                        block_id,
16900                    });
16901                })?;
16902            }
16903
16904            Ok(())
16905        }))
16906    }
16907
16908    pub fn confirm_rename(
16909        &mut self,
16910        _: &ConfirmRename,
16911        window: &mut Window,
16912        cx: &mut Context<Self>,
16913    ) -> Option<Task<Result<()>>> {
16914        let rename = self.take_rename(false, window, cx)?;
16915        let workspace = self.workspace()?.downgrade();
16916        let (buffer, start) = self
16917            .buffer
16918            .read(cx)
16919            .text_anchor_for_position(rename.range.start, cx)?;
16920        let (end_buffer, _) = self
16921            .buffer
16922            .read(cx)
16923            .text_anchor_for_position(rename.range.end, cx)?;
16924        if buffer != end_buffer {
16925            return None;
16926        }
16927
16928        let old_name = rename.old_name;
16929        let new_name = rename.editor.read(cx).text(cx);
16930
16931        let rename = self.semantics_provider.as_ref()?.perform_rename(
16932            &buffer,
16933            start,
16934            new_name.clone(),
16935            cx,
16936        )?;
16937
16938        Some(cx.spawn_in(window, async move |editor, cx| {
16939            let project_transaction = rename.await?;
16940            Self::open_project_transaction(
16941                &editor,
16942                workspace,
16943                project_transaction,
16944                format!("Rename: {}{}", old_name, new_name),
16945                cx,
16946            )
16947            .await?;
16948
16949            editor.update(cx, |editor, cx| {
16950                editor.refresh_document_highlights(cx);
16951            })?;
16952            Ok(())
16953        }))
16954    }
16955
16956    fn take_rename(
16957        &mut self,
16958        moving_cursor: bool,
16959        window: &mut Window,
16960        cx: &mut Context<Self>,
16961    ) -> Option<RenameState> {
16962        let rename = self.pending_rename.take()?;
16963        if rename.editor.focus_handle(cx).is_focused(window) {
16964            window.focus(&self.focus_handle);
16965        }
16966
16967        self.remove_blocks(
16968            [rename.block_id].into_iter().collect(),
16969            Some(Autoscroll::fit()),
16970            cx,
16971        );
16972        self.clear_highlights::<Rename>(cx);
16973        self.show_local_selections = true;
16974
16975        if moving_cursor {
16976            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16977                editor.selections.newest::<usize>(cx).head()
16978            });
16979
16980            // Update the selection to match the position of the selection inside
16981            // the rename editor.
16982            let snapshot = self.buffer.read(cx).read(cx);
16983            let rename_range = rename.range.to_offset(&snapshot);
16984            let cursor_in_editor = snapshot
16985                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16986                .min(rename_range.end);
16987            drop(snapshot);
16988
16989            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16990                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16991            });
16992        } else {
16993            self.refresh_document_highlights(cx);
16994        }
16995
16996        Some(rename)
16997    }
16998
16999    pub fn pending_rename(&self) -> Option<&RenameState> {
17000        self.pending_rename.as_ref()
17001    }
17002
17003    fn format(
17004        &mut self,
17005        _: &Format,
17006        window: &mut Window,
17007        cx: &mut Context<Self>,
17008    ) -> Option<Task<Result<()>>> {
17009        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17010
17011        let project = match &self.project {
17012            Some(project) => project.clone(),
17013            None => return None,
17014        };
17015
17016        Some(self.perform_format(
17017            project,
17018            FormatTrigger::Manual,
17019            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17020            window,
17021            cx,
17022        ))
17023    }
17024
17025    fn format_selections(
17026        &mut self,
17027        _: &FormatSelections,
17028        window: &mut Window,
17029        cx: &mut Context<Self>,
17030    ) -> Option<Task<Result<()>>> {
17031        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17032
17033        let project = match &self.project {
17034            Some(project) => project.clone(),
17035            None => return None,
17036        };
17037
17038        let ranges = self
17039            .selections
17040            .all_adjusted(cx)
17041            .into_iter()
17042            .map(|selection| selection.range())
17043            .collect_vec();
17044
17045        Some(self.perform_format(
17046            project,
17047            FormatTrigger::Manual,
17048            FormatTarget::Ranges(ranges),
17049            window,
17050            cx,
17051        ))
17052    }
17053
17054    fn perform_format(
17055        &mut self,
17056        project: Entity<Project>,
17057        trigger: FormatTrigger,
17058        target: FormatTarget,
17059        window: &mut Window,
17060        cx: &mut Context<Self>,
17061    ) -> Task<Result<()>> {
17062        let buffer = self.buffer.clone();
17063        let (buffers, target) = match target {
17064            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17065            FormatTarget::Ranges(selection_ranges) => {
17066                let multi_buffer = buffer.read(cx);
17067                let snapshot = multi_buffer.read(cx);
17068                let mut buffers = HashSet::default();
17069                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17070                    BTreeMap::new();
17071                for selection_range in selection_ranges {
17072                    for (buffer, buffer_range, _) in
17073                        snapshot.range_to_buffer_ranges(selection_range)
17074                    {
17075                        let buffer_id = buffer.remote_id();
17076                        let start = buffer.anchor_before(buffer_range.start);
17077                        let end = buffer.anchor_after(buffer_range.end);
17078                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17079                        buffer_id_to_ranges
17080                            .entry(buffer_id)
17081                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17082                            .or_insert_with(|| vec![start..end]);
17083                    }
17084                }
17085                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17086            }
17087        };
17088
17089        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17090        let selections_prev = transaction_id_prev
17091            .and_then(|transaction_id_prev| {
17092                // default to selections as they were after the last edit, if we have them,
17093                // instead of how they are now.
17094                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17095                // will take you back to where you made the last edit, instead of staying where you scrolled
17096                self.selection_history
17097                    .transaction(transaction_id_prev)
17098                    .map(|t| t.0.clone())
17099            })
17100            .unwrap_or_else(|| self.selections.disjoint_anchors());
17101
17102        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17103        let format = project.update(cx, |project, cx| {
17104            project.format(buffers, target, true, trigger, cx)
17105        });
17106
17107        cx.spawn_in(window, async move |editor, cx| {
17108            let transaction = futures::select_biased! {
17109                transaction = format.log_err().fuse() => transaction,
17110                () = timeout => {
17111                    log::warn!("timed out waiting for formatting");
17112                    None
17113                }
17114            };
17115
17116            buffer
17117                .update(cx, |buffer, cx| {
17118                    if let Some(transaction) = transaction
17119                        && !buffer.is_singleton()
17120                    {
17121                        buffer.push_transaction(&transaction.0, cx);
17122                    }
17123                    cx.notify();
17124                })
17125                .ok();
17126
17127            if let Some(transaction_id_now) =
17128                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17129            {
17130                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17131                if has_new_transaction {
17132                    _ = editor.update(cx, |editor, _| {
17133                        editor
17134                            .selection_history
17135                            .insert_transaction(transaction_id_now, selections_prev);
17136                    });
17137                }
17138            }
17139
17140            Ok(())
17141        })
17142    }
17143
17144    fn organize_imports(
17145        &mut self,
17146        _: &OrganizeImports,
17147        window: &mut Window,
17148        cx: &mut Context<Self>,
17149    ) -> Option<Task<Result<()>>> {
17150        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17151        let project = match &self.project {
17152            Some(project) => project.clone(),
17153            None => return None,
17154        };
17155        Some(self.perform_code_action_kind(
17156            project,
17157            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17158            window,
17159            cx,
17160        ))
17161    }
17162
17163    fn perform_code_action_kind(
17164        &mut self,
17165        project: Entity<Project>,
17166        kind: CodeActionKind,
17167        window: &mut Window,
17168        cx: &mut Context<Self>,
17169    ) -> Task<Result<()>> {
17170        let buffer = self.buffer.clone();
17171        let buffers = buffer.read(cx).all_buffers();
17172        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17173        let apply_action = project.update(cx, |project, cx| {
17174            project.apply_code_action_kind(buffers, kind, true, cx)
17175        });
17176        cx.spawn_in(window, async move |_, cx| {
17177            let transaction = futures::select_biased! {
17178                () = timeout => {
17179                    log::warn!("timed out waiting for executing code action");
17180                    None
17181                }
17182                transaction = apply_action.log_err().fuse() => transaction,
17183            };
17184            buffer
17185                .update(cx, |buffer, cx| {
17186                    // check if we need this
17187                    if let Some(transaction) = transaction
17188                        && !buffer.is_singleton()
17189                    {
17190                        buffer.push_transaction(&transaction.0, cx);
17191                    }
17192                    cx.notify();
17193                })
17194                .ok();
17195            Ok(())
17196        })
17197    }
17198
17199    pub fn restart_language_server(
17200        &mut self,
17201        _: &RestartLanguageServer,
17202        _: &mut Window,
17203        cx: &mut Context<Self>,
17204    ) {
17205        if let Some(project) = self.project.clone() {
17206            self.buffer.update(cx, |multi_buffer, cx| {
17207                project.update(cx, |project, cx| {
17208                    project.restart_language_servers_for_buffers(
17209                        multi_buffer.all_buffers().into_iter().collect(),
17210                        HashSet::default(),
17211                        cx,
17212                    );
17213                });
17214            })
17215        }
17216    }
17217
17218    pub fn stop_language_server(
17219        &mut self,
17220        _: &StopLanguageServer,
17221        _: &mut Window,
17222        cx: &mut Context<Self>,
17223    ) {
17224        if let Some(project) = self.project.clone() {
17225            self.buffer.update(cx, |multi_buffer, cx| {
17226                project.update(cx, |project, cx| {
17227                    project.stop_language_servers_for_buffers(
17228                        multi_buffer.all_buffers().into_iter().collect(),
17229                        HashSet::default(),
17230                        cx,
17231                    );
17232                    cx.emit(project::Event::RefreshInlayHints);
17233                });
17234            });
17235        }
17236    }
17237
17238    fn cancel_language_server_work(
17239        workspace: &mut Workspace,
17240        _: &actions::CancelLanguageServerWork,
17241        _: &mut Window,
17242        cx: &mut Context<Workspace>,
17243    ) {
17244        let project = workspace.project();
17245        let buffers = workspace
17246            .active_item(cx)
17247            .and_then(|item| item.act_as::<Editor>(cx))
17248            .map_or(HashSet::default(), |editor| {
17249                editor.read(cx).buffer.read(cx).all_buffers()
17250            });
17251        project.update(cx, |project, cx| {
17252            project.cancel_language_server_work_for_buffers(buffers, cx);
17253        });
17254    }
17255
17256    fn show_character_palette(
17257        &mut self,
17258        _: &ShowCharacterPalette,
17259        window: &mut Window,
17260        _: &mut Context<Self>,
17261    ) {
17262        window.show_character_palette();
17263    }
17264
17265    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17266        if !self.diagnostics_enabled() {
17267            return;
17268        }
17269
17270        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17271            let buffer = self.buffer.read(cx).snapshot(cx);
17272            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17273            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17274            let is_valid = buffer
17275                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17276                .any(|entry| {
17277                    entry.diagnostic.is_primary
17278                        && !entry.range.is_empty()
17279                        && entry.range.start == primary_range_start
17280                        && entry.diagnostic.message == active_diagnostics.active_message
17281                });
17282
17283            if !is_valid {
17284                self.dismiss_diagnostics(cx);
17285            }
17286        }
17287    }
17288
17289    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17290        match &self.active_diagnostics {
17291            ActiveDiagnostic::Group(group) => Some(group),
17292            _ => None,
17293        }
17294    }
17295
17296    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17297        if !self.diagnostics_enabled() {
17298            return;
17299        }
17300        self.dismiss_diagnostics(cx);
17301        self.active_diagnostics = ActiveDiagnostic::All;
17302    }
17303
17304    fn activate_diagnostics(
17305        &mut self,
17306        buffer_id: BufferId,
17307        diagnostic: DiagnosticEntry<usize>,
17308        window: &mut Window,
17309        cx: &mut Context<Self>,
17310    ) {
17311        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17312            return;
17313        }
17314        self.dismiss_diagnostics(cx);
17315        let snapshot = self.snapshot(window, cx);
17316        let buffer = self.buffer.read(cx).snapshot(cx);
17317        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17318            return;
17319        };
17320
17321        let diagnostic_group = buffer
17322            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17323            .collect::<Vec<_>>();
17324
17325        let blocks =
17326            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17327
17328        let blocks = self.display_map.update(cx, |display_map, cx| {
17329            display_map.insert_blocks(blocks, cx).into_iter().collect()
17330        });
17331        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17332            active_range: buffer.anchor_before(diagnostic.range.start)
17333                ..buffer.anchor_after(diagnostic.range.end),
17334            active_message: diagnostic.diagnostic.message.clone(),
17335            group_id: diagnostic.diagnostic.group_id,
17336            blocks,
17337        });
17338        cx.notify();
17339    }
17340
17341    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17342        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17343            return;
17344        };
17345
17346        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17347        if let ActiveDiagnostic::Group(group) = prev {
17348            self.display_map.update(cx, |display_map, cx| {
17349                display_map.remove_blocks(group.blocks, cx);
17350            });
17351            cx.notify();
17352        }
17353    }
17354
17355    /// Disable inline diagnostics rendering for this editor.
17356    pub fn disable_inline_diagnostics(&mut self) {
17357        self.inline_diagnostics_enabled = false;
17358        self.inline_diagnostics_update = Task::ready(());
17359        self.inline_diagnostics.clear();
17360    }
17361
17362    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17363        self.diagnostics_enabled = false;
17364        self.dismiss_diagnostics(cx);
17365        self.inline_diagnostics_update = Task::ready(());
17366        self.inline_diagnostics.clear();
17367    }
17368
17369    pub fn disable_word_completions(&mut self) {
17370        self.word_completions_enabled = false;
17371    }
17372
17373    pub fn diagnostics_enabled(&self) -> bool {
17374        self.diagnostics_enabled && self.mode.is_full()
17375    }
17376
17377    pub fn inline_diagnostics_enabled(&self) -> bool {
17378        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17379    }
17380
17381    pub fn show_inline_diagnostics(&self) -> bool {
17382        self.show_inline_diagnostics
17383    }
17384
17385    pub fn toggle_inline_diagnostics(
17386        &mut self,
17387        _: &ToggleInlineDiagnostics,
17388        window: &mut Window,
17389        cx: &mut Context<Editor>,
17390    ) {
17391        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17392        self.refresh_inline_diagnostics(false, window, cx);
17393    }
17394
17395    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17396        self.diagnostics_max_severity = severity;
17397        self.display_map.update(cx, |display_map, _| {
17398            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17399        });
17400    }
17401
17402    pub fn toggle_diagnostics(
17403        &mut self,
17404        _: &ToggleDiagnostics,
17405        window: &mut Window,
17406        cx: &mut Context<Editor>,
17407    ) {
17408        if !self.diagnostics_enabled() {
17409            return;
17410        }
17411
17412        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17413            EditorSettings::get_global(cx)
17414                .diagnostics_max_severity
17415                .filter(|severity| severity != &DiagnosticSeverity::Off)
17416                .unwrap_or(DiagnosticSeverity::Hint)
17417        } else {
17418            DiagnosticSeverity::Off
17419        };
17420        self.set_max_diagnostics_severity(new_severity, cx);
17421        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17422            self.active_diagnostics = ActiveDiagnostic::None;
17423            self.inline_diagnostics_update = Task::ready(());
17424            self.inline_diagnostics.clear();
17425        } else {
17426            self.refresh_inline_diagnostics(false, window, cx);
17427        }
17428
17429        cx.notify();
17430    }
17431
17432    pub fn toggle_minimap(
17433        &mut self,
17434        _: &ToggleMinimap,
17435        window: &mut Window,
17436        cx: &mut Context<Editor>,
17437    ) {
17438        if self.supports_minimap(cx) {
17439            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17440        }
17441    }
17442
17443    fn refresh_inline_diagnostics(
17444        &mut self,
17445        debounce: bool,
17446        window: &mut Window,
17447        cx: &mut Context<Self>,
17448    ) {
17449        let max_severity = ProjectSettings::get_global(cx)
17450            .diagnostics
17451            .inline
17452            .max_severity
17453            .unwrap_or(self.diagnostics_max_severity);
17454
17455        if !self.inline_diagnostics_enabled()
17456            || !self.show_inline_diagnostics
17457            || max_severity == DiagnosticSeverity::Off
17458        {
17459            self.inline_diagnostics_update = Task::ready(());
17460            self.inline_diagnostics.clear();
17461            return;
17462        }
17463
17464        let debounce_ms = ProjectSettings::get_global(cx)
17465            .diagnostics
17466            .inline
17467            .update_debounce_ms;
17468        let debounce = if debounce && debounce_ms > 0 {
17469            Some(Duration::from_millis(debounce_ms))
17470        } else {
17471            None
17472        };
17473        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17474            if let Some(debounce) = debounce {
17475                cx.background_executor().timer(debounce).await;
17476            }
17477            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17478                editor
17479                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17480                    .ok()
17481            }) else {
17482                return;
17483            };
17484
17485            let new_inline_diagnostics = cx
17486                .background_spawn(async move {
17487                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17488                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17489                        let message = diagnostic_entry
17490                            .diagnostic
17491                            .message
17492                            .split_once('\n')
17493                            .map(|(line, _)| line)
17494                            .map(SharedString::new)
17495                            .unwrap_or_else(|| {
17496                                SharedString::from(diagnostic_entry.diagnostic.message)
17497                            });
17498                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17499                        let (Ok(i) | Err(i)) = inline_diagnostics
17500                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17501                        inline_diagnostics.insert(
17502                            i,
17503                            (
17504                                start_anchor,
17505                                InlineDiagnostic {
17506                                    message,
17507                                    group_id: diagnostic_entry.diagnostic.group_id,
17508                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17509                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17510                                    severity: diagnostic_entry.diagnostic.severity,
17511                                },
17512                            ),
17513                        );
17514                    }
17515                    inline_diagnostics
17516                })
17517                .await;
17518
17519            editor
17520                .update(cx, |editor, cx| {
17521                    editor.inline_diagnostics = new_inline_diagnostics;
17522                    cx.notify();
17523                })
17524                .ok();
17525        });
17526    }
17527
17528    fn pull_diagnostics(
17529        &mut self,
17530        buffer_id: Option<BufferId>,
17531        window: &Window,
17532        cx: &mut Context<Self>,
17533    ) -> Option<()> {
17534        if !self.mode().is_full() {
17535            return None;
17536        }
17537        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17538            .diagnostics
17539            .lsp_pull_diagnostics;
17540        if !pull_diagnostics_settings.enabled {
17541            return None;
17542        }
17543        let project = self.project()?.downgrade();
17544        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17545        let mut buffers = self.buffer.read(cx).all_buffers();
17546        if let Some(buffer_id) = buffer_id {
17547            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17548        }
17549
17550        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17551            cx.background_executor().timer(debounce).await;
17552
17553            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17554                buffers
17555                    .into_iter()
17556                    .filter_map(|buffer| {
17557                        project
17558                            .update(cx, |project, cx| {
17559                                project.lsp_store().update(cx, |lsp_store, cx| {
17560                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17561                                })
17562                            })
17563                            .ok()
17564                    })
17565                    .collect::<FuturesUnordered<_>>()
17566            }) else {
17567                return;
17568            };
17569
17570            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17571                match pull_task {
17572                    Ok(()) => {
17573                        if editor
17574                            .update_in(cx, |editor, window, cx| {
17575                                editor.update_diagnostics_state(window, cx);
17576                            })
17577                            .is_err()
17578                        {
17579                            return;
17580                        }
17581                    }
17582                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17583                }
17584            }
17585        });
17586
17587        Some(())
17588    }
17589
17590    pub fn set_selections_from_remote(
17591        &mut self,
17592        selections: Vec<Selection<Anchor>>,
17593        pending_selection: Option<Selection<Anchor>>,
17594        window: &mut Window,
17595        cx: &mut Context<Self>,
17596    ) {
17597        let old_cursor_position = self.selections.newest_anchor().head();
17598        self.selections.change_with(cx, |s| {
17599            s.select_anchors(selections);
17600            if let Some(pending_selection) = pending_selection {
17601                s.set_pending(pending_selection, SelectMode::Character);
17602            } else {
17603                s.clear_pending();
17604            }
17605        });
17606        self.selections_did_change(
17607            false,
17608            &old_cursor_position,
17609            SelectionEffects::default(),
17610            window,
17611            cx,
17612        );
17613    }
17614
17615    pub fn transact(
17616        &mut self,
17617        window: &mut Window,
17618        cx: &mut Context<Self>,
17619        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17620    ) -> Option<TransactionId> {
17621        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17622            this.start_transaction_at(Instant::now(), window, cx);
17623            update(this, window, cx);
17624            this.end_transaction_at(Instant::now(), cx)
17625        })
17626    }
17627
17628    pub fn start_transaction_at(
17629        &mut self,
17630        now: Instant,
17631        window: &mut Window,
17632        cx: &mut Context<Self>,
17633    ) -> Option<TransactionId> {
17634        self.end_selection(window, cx);
17635        if let Some(tx_id) = self
17636            .buffer
17637            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17638        {
17639            self.selection_history
17640                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17641            cx.emit(EditorEvent::TransactionBegun {
17642                transaction_id: tx_id,
17643            });
17644            Some(tx_id)
17645        } else {
17646            None
17647        }
17648    }
17649
17650    pub fn end_transaction_at(
17651        &mut self,
17652        now: Instant,
17653        cx: &mut Context<Self>,
17654    ) -> Option<TransactionId> {
17655        if let Some(transaction_id) = self
17656            .buffer
17657            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17658        {
17659            if let Some((_, end_selections)) =
17660                self.selection_history.transaction_mut(transaction_id)
17661            {
17662                *end_selections = Some(self.selections.disjoint_anchors());
17663            } else {
17664                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17665            }
17666
17667            cx.emit(EditorEvent::Edited { transaction_id });
17668            Some(transaction_id)
17669        } else {
17670            None
17671        }
17672    }
17673
17674    pub fn modify_transaction_selection_history(
17675        &mut self,
17676        transaction_id: TransactionId,
17677        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17678    ) -> bool {
17679        self.selection_history
17680            .transaction_mut(transaction_id)
17681            .map(modify)
17682            .is_some()
17683    }
17684
17685    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17686        if self.selection_mark_mode {
17687            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17688                s.move_with(|_, sel| {
17689                    sel.collapse_to(sel.head(), SelectionGoal::None);
17690                });
17691            })
17692        }
17693        self.selection_mark_mode = true;
17694        cx.notify();
17695    }
17696
17697    pub fn swap_selection_ends(
17698        &mut self,
17699        _: &actions::SwapSelectionEnds,
17700        window: &mut Window,
17701        cx: &mut Context<Self>,
17702    ) {
17703        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17704            s.move_with(|_, sel| {
17705                if sel.start != sel.end {
17706                    sel.reversed = !sel.reversed
17707                }
17708            });
17709        });
17710        self.request_autoscroll(Autoscroll::newest(), cx);
17711        cx.notify();
17712    }
17713
17714    pub fn toggle_focus(
17715        workspace: &mut Workspace,
17716        _: &actions::ToggleFocus,
17717        window: &mut Window,
17718        cx: &mut Context<Workspace>,
17719    ) {
17720        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17721            return;
17722        };
17723        workspace.activate_item(&item, true, true, window, cx);
17724    }
17725
17726    pub fn toggle_fold(
17727        &mut self,
17728        _: &actions::ToggleFold,
17729        window: &mut Window,
17730        cx: &mut Context<Self>,
17731    ) {
17732        if self.is_singleton(cx) {
17733            let selection = self.selections.newest::<Point>(cx);
17734
17735            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17736            let range = if selection.is_empty() {
17737                let point = selection.head().to_display_point(&display_map);
17738                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17739                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17740                    .to_point(&display_map);
17741                start..end
17742            } else {
17743                selection.range()
17744            };
17745            if display_map.folds_in_range(range).next().is_some() {
17746                self.unfold_lines(&Default::default(), window, cx)
17747            } else {
17748                self.fold(&Default::default(), window, cx)
17749            }
17750        } else {
17751            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17752            let buffer_ids: HashSet<_> = self
17753                .selections
17754                .disjoint_anchor_ranges()
17755                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17756                .collect();
17757
17758            let should_unfold = buffer_ids
17759                .iter()
17760                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17761
17762            for buffer_id in buffer_ids {
17763                if should_unfold {
17764                    self.unfold_buffer(buffer_id, cx);
17765                } else {
17766                    self.fold_buffer(buffer_id, cx);
17767                }
17768            }
17769        }
17770    }
17771
17772    pub fn toggle_fold_recursive(
17773        &mut self,
17774        _: &actions::ToggleFoldRecursive,
17775        window: &mut Window,
17776        cx: &mut Context<Self>,
17777    ) {
17778        let selection = self.selections.newest::<Point>(cx);
17779
17780        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17781        let range = if selection.is_empty() {
17782            let point = selection.head().to_display_point(&display_map);
17783            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17784            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17785                .to_point(&display_map);
17786            start..end
17787        } else {
17788            selection.range()
17789        };
17790        if display_map.folds_in_range(range).next().is_some() {
17791            self.unfold_recursive(&Default::default(), window, cx)
17792        } else {
17793            self.fold_recursive(&Default::default(), window, cx)
17794        }
17795    }
17796
17797    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17798        if self.is_singleton(cx) {
17799            let mut to_fold = Vec::new();
17800            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17801            let selections = self.selections.all_adjusted(cx);
17802
17803            for selection in selections {
17804                let range = selection.range().sorted();
17805                let buffer_start_row = range.start.row;
17806
17807                if range.start.row != range.end.row {
17808                    let mut found = false;
17809                    let mut row = range.start.row;
17810                    while row <= range.end.row {
17811                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17812                        {
17813                            found = true;
17814                            row = crease.range().end.row + 1;
17815                            to_fold.push(crease);
17816                        } else {
17817                            row += 1
17818                        }
17819                    }
17820                    if found {
17821                        continue;
17822                    }
17823                }
17824
17825                for row in (0..=range.start.row).rev() {
17826                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17827                        && crease.range().end.row >= buffer_start_row
17828                    {
17829                        to_fold.push(crease);
17830                        if row <= range.start.row {
17831                            break;
17832                        }
17833                    }
17834                }
17835            }
17836
17837            self.fold_creases(to_fold, true, window, cx);
17838        } else {
17839            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17840            let buffer_ids = self
17841                .selections
17842                .disjoint_anchor_ranges()
17843                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17844                .collect::<HashSet<_>>();
17845            for buffer_id in buffer_ids {
17846                self.fold_buffer(buffer_id, cx);
17847            }
17848        }
17849    }
17850
17851    pub fn toggle_fold_all(
17852        &mut self,
17853        _: &actions::ToggleFoldAll,
17854        window: &mut Window,
17855        cx: &mut Context<Self>,
17856    ) {
17857        if self.buffer.read(cx).is_singleton() {
17858            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17859            let has_folds = display_map
17860                .folds_in_range(0..display_map.buffer_snapshot.len())
17861                .next()
17862                .is_some();
17863
17864            if has_folds {
17865                self.unfold_all(&actions::UnfoldAll, window, cx);
17866            } else {
17867                self.fold_all(&actions::FoldAll, window, cx);
17868            }
17869        } else {
17870            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17871            let should_unfold = buffer_ids
17872                .iter()
17873                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17874
17875            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17876                editor
17877                    .update_in(cx, |editor, _, cx| {
17878                        for buffer_id in buffer_ids {
17879                            if should_unfold {
17880                                editor.unfold_buffer(buffer_id, cx);
17881                            } else {
17882                                editor.fold_buffer(buffer_id, cx);
17883                            }
17884                        }
17885                    })
17886                    .ok();
17887            });
17888        }
17889    }
17890
17891    fn fold_at_level(
17892        &mut self,
17893        fold_at: &FoldAtLevel,
17894        window: &mut Window,
17895        cx: &mut Context<Self>,
17896    ) {
17897        if !self.buffer.read(cx).is_singleton() {
17898            return;
17899        }
17900
17901        let fold_at_level = fold_at.0;
17902        let snapshot = self.buffer.read(cx).snapshot(cx);
17903        let mut to_fold = Vec::new();
17904        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17905
17906        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17907            while start_row < end_row {
17908                match self
17909                    .snapshot(window, cx)
17910                    .crease_for_buffer_row(MultiBufferRow(start_row))
17911                {
17912                    Some(crease) => {
17913                        let nested_start_row = crease.range().start.row + 1;
17914                        let nested_end_row = crease.range().end.row;
17915
17916                        if current_level < fold_at_level {
17917                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17918                        } else if current_level == fold_at_level {
17919                            to_fold.push(crease);
17920                        }
17921
17922                        start_row = nested_end_row + 1;
17923                    }
17924                    None => start_row += 1,
17925                }
17926            }
17927        }
17928
17929        self.fold_creases(to_fold, true, window, cx);
17930    }
17931
17932    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17933        if self.buffer.read(cx).is_singleton() {
17934            let mut fold_ranges = Vec::new();
17935            let snapshot = self.buffer.read(cx).snapshot(cx);
17936
17937            for row in 0..snapshot.max_row().0 {
17938                if let Some(foldable_range) = self
17939                    .snapshot(window, cx)
17940                    .crease_for_buffer_row(MultiBufferRow(row))
17941                {
17942                    fold_ranges.push(foldable_range);
17943                }
17944            }
17945
17946            self.fold_creases(fold_ranges, true, window, cx);
17947        } else {
17948            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17949                editor
17950                    .update_in(cx, |editor, _, cx| {
17951                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17952                            editor.fold_buffer(buffer_id, cx);
17953                        }
17954                    })
17955                    .ok();
17956            });
17957        }
17958    }
17959
17960    pub fn fold_function_bodies(
17961        &mut self,
17962        _: &actions::FoldFunctionBodies,
17963        window: &mut Window,
17964        cx: &mut Context<Self>,
17965    ) {
17966        let snapshot = self.buffer.read(cx).snapshot(cx);
17967
17968        let ranges = snapshot
17969            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17970            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17971            .collect::<Vec<_>>();
17972
17973        let creases = ranges
17974            .into_iter()
17975            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17976            .collect();
17977
17978        self.fold_creases(creases, true, window, cx);
17979    }
17980
17981    pub fn fold_recursive(
17982        &mut self,
17983        _: &actions::FoldRecursive,
17984        window: &mut Window,
17985        cx: &mut Context<Self>,
17986    ) {
17987        let mut to_fold = Vec::new();
17988        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17989        let selections = self.selections.all_adjusted(cx);
17990
17991        for selection in selections {
17992            let range = selection.range().sorted();
17993            let buffer_start_row = range.start.row;
17994
17995            if range.start.row != range.end.row {
17996                let mut found = false;
17997                for row in range.start.row..=range.end.row {
17998                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17999                        found = true;
18000                        to_fold.push(crease);
18001                    }
18002                }
18003                if found {
18004                    continue;
18005                }
18006            }
18007
18008            for row in (0..=range.start.row).rev() {
18009                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18010                    if crease.range().end.row >= buffer_start_row {
18011                        to_fold.push(crease);
18012                    } else {
18013                        break;
18014                    }
18015                }
18016            }
18017        }
18018
18019        self.fold_creases(to_fold, true, window, cx);
18020    }
18021
18022    pub fn fold_at(
18023        &mut self,
18024        buffer_row: MultiBufferRow,
18025        window: &mut Window,
18026        cx: &mut Context<Self>,
18027    ) {
18028        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18029
18030        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18031            let autoscroll = self
18032                .selections
18033                .all::<Point>(cx)
18034                .iter()
18035                .any(|selection| crease.range().overlaps(&selection.range()));
18036
18037            self.fold_creases(vec![crease], autoscroll, window, cx);
18038        }
18039    }
18040
18041    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18042        if self.is_singleton(cx) {
18043            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18044            let buffer = &display_map.buffer_snapshot;
18045            let selections = self.selections.all::<Point>(cx);
18046            let ranges = selections
18047                .iter()
18048                .map(|s| {
18049                    let range = s.display_range(&display_map).sorted();
18050                    let mut start = range.start.to_point(&display_map);
18051                    let mut end = range.end.to_point(&display_map);
18052                    start.column = 0;
18053                    end.column = buffer.line_len(MultiBufferRow(end.row));
18054                    start..end
18055                })
18056                .collect::<Vec<_>>();
18057
18058            self.unfold_ranges(&ranges, true, true, cx);
18059        } else {
18060            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18061            let buffer_ids = self
18062                .selections
18063                .disjoint_anchor_ranges()
18064                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18065                .collect::<HashSet<_>>();
18066            for buffer_id in buffer_ids {
18067                self.unfold_buffer(buffer_id, cx);
18068            }
18069        }
18070    }
18071
18072    pub fn unfold_recursive(
18073        &mut self,
18074        _: &UnfoldRecursive,
18075        _window: &mut Window,
18076        cx: &mut Context<Self>,
18077    ) {
18078        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18079        let selections = self.selections.all::<Point>(cx);
18080        let ranges = selections
18081            .iter()
18082            .map(|s| {
18083                let mut range = s.display_range(&display_map).sorted();
18084                *range.start.column_mut() = 0;
18085                *range.end.column_mut() = display_map.line_len(range.end.row());
18086                let start = range.start.to_point(&display_map);
18087                let end = range.end.to_point(&display_map);
18088                start..end
18089            })
18090            .collect::<Vec<_>>();
18091
18092        self.unfold_ranges(&ranges, true, true, cx);
18093    }
18094
18095    pub fn unfold_at(
18096        &mut self,
18097        buffer_row: MultiBufferRow,
18098        _window: &mut Window,
18099        cx: &mut Context<Self>,
18100    ) {
18101        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18102
18103        let intersection_range = Point::new(buffer_row.0, 0)
18104            ..Point::new(
18105                buffer_row.0,
18106                display_map.buffer_snapshot.line_len(buffer_row),
18107            );
18108
18109        let autoscroll = self
18110            .selections
18111            .all::<Point>(cx)
18112            .iter()
18113            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18114
18115        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18116    }
18117
18118    pub fn unfold_all(
18119        &mut self,
18120        _: &actions::UnfoldAll,
18121        _window: &mut Window,
18122        cx: &mut Context<Self>,
18123    ) {
18124        if self.buffer.read(cx).is_singleton() {
18125            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18126            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18127        } else {
18128            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18129                editor
18130                    .update(cx, |editor, cx| {
18131                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18132                            editor.unfold_buffer(buffer_id, cx);
18133                        }
18134                    })
18135                    .ok();
18136            });
18137        }
18138    }
18139
18140    pub fn fold_selected_ranges(
18141        &mut self,
18142        _: &FoldSelectedRanges,
18143        window: &mut Window,
18144        cx: &mut Context<Self>,
18145    ) {
18146        let selections = self.selections.all_adjusted(cx);
18147        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18148        let ranges = selections
18149            .into_iter()
18150            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18151            .collect::<Vec<_>>();
18152        self.fold_creases(ranges, true, window, cx);
18153    }
18154
18155    pub fn fold_ranges<T: ToOffset + Clone>(
18156        &mut self,
18157        ranges: Vec<Range<T>>,
18158        auto_scroll: bool,
18159        window: &mut Window,
18160        cx: &mut Context<Self>,
18161    ) {
18162        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18163        let ranges = ranges
18164            .into_iter()
18165            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18166            .collect::<Vec<_>>();
18167        self.fold_creases(ranges, auto_scroll, window, cx);
18168    }
18169
18170    pub fn fold_creases<T: ToOffset + Clone>(
18171        &mut self,
18172        creases: Vec<Crease<T>>,
18173        auto_scroll: bool,
18174        _window: &mut Window,
18175        cx: &mut Context<Self>,
18176    ) {
18177        if creases.is_empty() {
18178            return;
18179        }
18180
18181        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18182
18183        if auto_scroll {
18184            self.request_autoscroll(Autoscroll::fit(), cx);
18185        }
18186
18187        cx.notify();
18188
18189        self.scrollbar_marker_state.dirty = true;
18190        self.folds_did_change(cx);
18191    }
18192
18193    /// Removes any folds whose ranges intersect any of the given ranges.
18194    pub fn unfold_ranges<T: ToOffset + Clone>(
18195        &mut self,
18196        ranges: &[Range<T>],
18197        inclusive: bool,
18198        auto_scroll: bool,
18199        cx: &mut Context<Self>,
18200    ) {
18201        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18202            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18203        });
18204        self.folds_did_change(cx);
18205    }
18206
18207    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18208        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18209            return;
18210        }
18211        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18212        self.display_map.update(cx, |display_map, cx| {
18213            display_map.fold_buffers([buffer_id], cx)
18214        });
18215        cx.emit(EditorEvent::BufferFoldToggled {
18216            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18217            folded: true,
18218        });
18219        cx.notify();
18220    }
18221
18222    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18223        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18224            return;
18225        }
18226        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18227        self.display_map.update(cx, |display_map, cx| {
18228            display_map.unfold_buffers([buffer_id], cx);
18229        });
18230        cx.emit(EditorEvent::BufferFoldToggled {
18231            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18232            folded: false,
18233        });
18234        cx.notify();
18235    }
18236
18237    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18238        self.display_map.read(cx).is_buffer_folded(buffer)
18239    }
18240
18241    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18242        self.display_map.read(cx).folded_buffers()
18243    }
18244
18245    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18246        self.display_map.update(cx, |display_map, cx| {
18247            display_map.disable_header_for_buffer(buffer_id, cx);
18248        });
18249        cx.notify();
18250    }
18251
18252    /// Removes any folds with the given ranges.
18253    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18254        &mut self,
18255        ranges: &[Range<T>],
18256        type_id: TypeId,
18257        auto_scroll: bool,
18258        cx: &mut Context<Self>,
18259    ) {
18260        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18261            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18262        });
18263        self.folds_did_change(cx);
18264    }
18265
18266    fn remove_folds_with<T: ToOffset + Clone>(
18267        &mut self,
18268        ranges: &[Range<T>],
18269        auto_scroll: bool,
18270        cx: &mut Context<Self>,
18271        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18272    ) {
18273        if ranges.is_empty() {
18274            return;
18275        }
18276
18277        let mut buffers_affected = HashSet::default();
18278        let multi_buffer = self.buffer().read(cx);
18279        for range in ranges {
18280            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18281                buffers_affected.insert(buffer.read(cx).remote_id());
18282            };
18283        }
18284
18285        self.display_map.update(cx, update);
18286
18287        if auto_scroll {
18288            self.request_autoscroll(Autoscroll::fit(), cx);
18289        }
18290
18291        cx.notify();
18292        self.scrollbar_marker_state.dirty = true;
18293        self.active_indent_guides_state.dirty = true;
18294    }
18295
18296    pub fn update_renderer_widths(
18297        &mut self,
18298        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18299        cx: &mut Context<Self>,
18300    ) -> bool {
18301        self.display_map
18302            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18303    }
18304
18305    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18306        self.display_map.read(cx).fold_placeholder.clone()
18307    }
18308
18309    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18310        self.buffer.update(cx, |buffer, cx| {
18311            buffer.set_all_diff_hunks_expanded(cx);
18312        });
18313    }
18314
18315    pub fn expand_all_diff_hunks(
18316        &mut self,
18317        _: &ExpandAllDiffHunks,
18318        _window: &mut Window,
18319        cx: &mut Context<Self>,
18320    ) {
18321        self.buffer.update(cx, |buffer, cx| {
18322            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18323        });
18324    }
18325
18326    pub fn toggle_selected_diff_hunks(
18327        &mut self,
18328        _: &ToggleSelectedDiffHunks,
18329        _window: &mut Window,
18330        cx: &mut Context<Self>,
18331    ) {
18332        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18333        self.toggle_diff_hunks_in_ranges(ranges, cx);
18334    }
18335
18336    pub fn diff_hunks_in_ranges<'a>(
18337        &'a self,
18338        ranges: &'a [Range<Anchor>],
18339        buffer: &'a MultiBufferSnapshot,
18340    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18341        ranges.iter().flat_map(move |range| {
18342            let end_excerpt_id = range.end.excerpt_id;
18343            let range = range.to_point(buffer);
18344            let mut peek_end = range.end;
18345            if range.end.row < buffer.max_row().0 {
18346                peek_end = Point::new(range.end.row + 1, 0);
18347            }
18348            buffer
18349                .diff_hunks_in_range(range.start..peek_end)
18350                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18351        })
18352    }
18353
18354    pub fn has_stageable_diff_hunks_in_ranges(
18355        &self,
18356        ranges: &[Range<Anchor>],
18357        snapshot: &MultiBufferSnapshot,
18358    ) -> bool {
18359        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18360        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18361    }
18362
18363    pub fn toggle_staged_selected_diff_hunks(
18364        &mut self,
18365        _: &::git::ToggleStaged,
18366        _: &mut Window,
18367        cx: &mut Context<Self>,
18368    ) {
18369        let snapshot = self.buffer.read(cx).snapshot(cx);
18370        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18371        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18372        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18373    }
18374
18375    pub fn set_render_diff_hunk_controls(
18376        &mut self,
18377        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18378        cx: &mut Context<Self>,
18379    ) {
18380        self.render_diff_hunk_controls = render_diff_hunk_controls;
18381        cx.notify();
18382    }
18383
18384    pub fn stage_and_next(
18385        &mut self,
18386        _: &::git::StageAndNext,
18387        window: &mut Window,
18388        cx: &mut Context<Self>,
18389    ) {
18390        self.do_stage_or_unstage_and_next(true, window, cx);
18391    }
18392
18393    pub fn unstage_and_next(
18394        &mut self,
18395        _: &::git::UnstageAndNext,
18396        window: &mut Window,
18397        cx: &mut Context<Self>,
18398    ) {
18399        self.do_stage_or_unstage_and_next(false, window, cx);
18400    }
18401
18402    pub fn stage_or_unstage_diff_hunks(
18403        &mut self,
18404        stage: bool,
18405        ranges: Vec<Range<Anchor>>,
18406        cx: &mut Context<Self>,
18407    ) {
18408        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18409        cx.spawn(async move |this, cx| {
18410            task.await?;
18411            this.update(cx, |this, cx| {
18412                let snapshot = this.buffer.read(cx).snapshot(cx);
18413                let chunk_by = this
18414                    .diff_hunks_in_ranges(&ranges, &snapshot)
18415                    .chunk_by(|hunk| hunk.buffer_id);
18416                for (buffer_id, hunks) in &chunk_by {
18417                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18418                }
18419            })
18420        })
18421        .detach_and_log_err(cx);
18422    }
18423
18424    fn save_buffers_for_ranges_if_needed(
18425        &mut self,
18426        ranges: &[Range<Anchor>],
18427        cx: &mut Context<Editor>,
18428    ) -> Task<Result<()>> {
18429        let multibuffer = self.buffer.read(cx);
18430        let snapshot = multibuffer.read(cx);
18431        let buffer_ids: HashSet<_> = ranges
18432            .iter()
18433            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18434            .collect();
18435        drop(snapshot);
18436
18437        let mut buffers = HashSet::default();
18438        for buffer_id in buffer_ids {
18439            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18440                let buffer = buffer_entity.read(cx);
18441                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18442                {
18443                    buffers.insert(buffer_entity);
18444                }
18445            }
18446        }
18447
18448        if let Some(project) = &self.project {
18449            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18450        } else {
18451            Task::ready(Ok(()))
18452        }
18453    }
18454
18455    fn do_stage_or_unstage_and_next(
18456        &mut self,
18457        stage: bool,
18458        window: &mut Window,
18459        cx: &mut Context<Self>,
18460    ) {
18461        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18462
18463        if ranges.iter().any(|range| range.start != range.end) {
18464            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18465            return;
18466        }
18467
18468        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18469        let snapshot = self.snapshot(window, cx);
18470        let position = self.selections.newest::<Point>(cx).head();
18471        let mut row = snapshot
18472            .buffer_snapshot
18473            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18474            .find(|hunk| hunk.row_range.start.0 > position.row)
18475            .map(|hunk| hunk.row_range.start);
18476
18477        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18478        // Outside of the project diff editor, wrap around to the beginning.
18479        if !all_diff_hunks_expanded {
18480            row = row.or_else(|| {
18481                snapshot
18482                    .buffer_snapshot
18483                    .diff_hunks_in_range(Point::zero()..position)
18484                    .find(|hunk| hunk.row_range.end.0 < position.row)
18485                    .map(|hunk| hunk.row_range.start)
18486            });
18487        }
18488
18489        if let Some(row) = row {
18490            let destination = Point::new(row.0, 0);
18491            let autoscroll = Autoscroll::center();
18492
18493            self.unfold_ranges(&[destination..destination], false, false, cx);
18494            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18495                s.select_ranges([destination..destination]);
18496            });
18497        }
18498    }
18499
18500    fn do_stage_or_unstage(
18501        &self,
18502        stage: bool,
18503        buffer_id: BufferId,
18504        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18505        cx: &mut App,
18506    ) -> Option<()> {
18507        let project = self.project()?;
18508        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18509        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18510        let buffer_snapshot = buffer.read(cx).snapshot();
18511        let file_exists = buffer_snapshot
18512            .file()
18513            .is_some_and(|file| file.disk_state().exists());
18514        diff.update(cx, |diff, cx| {
18515            diff.stage_or_unstage_hunks(
18516                stage,
18517                &hunks
18518                    .map(|hunk| buffer_diff::DiffHunk {
18519                        buffer_range: hunk.buffer_range,
18520                        diff_base_byte_range: hunk.diff_base_byte_range,
18521                        secondary_status: hunk.secondary_status,
18522                        range: Point::zero()..Point::zero(), // unused
18523                    })
18524                    .collect::<Vec<_>>(),
18525                &buffer_snapshot,
18526                file_exists,
18527                cx,
18528            )
18529        });
18530        None
18531    }
18532
18533    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18534        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18535        self.buffer
18536            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18537    }
18538
18539    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18540        self.buffer.update(cx, |buffer, cx| {
18541            let ranges = vec![Anchor::min()..Anchor::max()];
18542            if !buffer.all_diff_hunks_expanded()
18543                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18544            {
18545                buffer.collapse_diff_hunks(ranges, cx);
18546                true
18547            } else {
18548                false
18549            }
18550        })
18551    }
18552
18553    fn toggle_diff_hunks_in_ranges(
18554        &mut self,
18555        ranges: Vec<Range<Anchor>>,
18556        cx: &mut Context<Editor>,
18557    ) {
18558        self.buffer.update(cx, |buffer, cx| {
18559            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18560            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18561        })
18562    }
18563
18564    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18565        self.buffer.update(cx, |buffer, cx| {
18566            let snapshot = buffer.snapshot(cx);
18567            let excerpt_id = range.end.excerpt_id;
18568            let point_range = range.to_point(&snapshot);
18569            let expand = !buffer.single_hunk_is_expanded(range, cx);
18570            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18571        })
18572    }
18573
18574    pub(crate) fn apply_all_diff_hunks(
18575        &mut self,
18576        _: &ApplyAllDiffHunks,
18577        window: &mut Window,
18578        cx: &mut Context<Self>,
18579    ) {
18580        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18581
18582        let buffers = self.buffer.read(cx).all_buffers();
18583        for branch_buffer in buffers {
18584            branch_buffer.update(cx, |branch_buffer, cx| {
18585                branch_buffer.merge_into_base(Vec::new(), cx);
18586            });
18587        }
18588
18589        if let Some(project) = self.project.clone() {
18590            self.save(
18591                SaveOptions {
18592                    format: true,
18593                    autosave: false,
18594                },
18595                project,
18596                window,
18597                cx,
18598            )
18599            .detach_and_log_err(cx);
18600        }
18601    }
18602
18603    pub(crate) fn apply_selected_diff_hunks(
18604        &mut self,
18605        _: &ApplyDiffHunk,
18606        window: &mut Window,
18607        cx: &mut Context<Self>,
18608    ) {
18609        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18610        let snapshot = self.snapshot(window, cx);
18611        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18612        let mut ranges_by_buffer = HashMap::default();
18613        self.transact(window, cx, |editor, _window, cx| {
18614            for hunk in hunks {
18615                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18616                    ranges_by_buffer
18617                        .entry(buffer.clone())
18618                        .or_insert_with(Vec::new)
18619                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18620                }
18621            }
18622
18623            for (buffer, ranges) in ranges_by_buffer {
18624                buffer.update(cx, |buffer, cx| {
18625                    buffer.merge_into_base(ranges, cx);
18626                });
18627            }
18628        });
18629
18630        if let Some(project) = self.project.clone() {
18631            self.save(
18632                SaveOptions {
18633                    format: true,
18634                    autosave: false,
18635                },
18636                project,
18637                window,
18638                cx,
18639            )
18640            .detach_and_log_err(cx);
18641        }
18642    }
18643
18644    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18645        if hovered != self.gutter_hovered {
18646            self.gutter_hovered = hovered;
18647            cx.notify();
18648        }
18649    }
18650
18651    pub fn insert_blocks(
18652        &mut self,
18653        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18654        autoscroll: Option<Autoscroll>,
18655        cx: &mut Context<Self>,
18656    ) -> Vec<CustomBlockId> {
18657        let blocks = self
18658            .display_map
18659            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18660        if let Some(autoscroll) = autoscroll {
18661            self.request_autoscroll(autoscroll, cx);
18662        }
18663        cx.notify();
18664        blocks
18665    }
18666
18667    pub fn resize_blocks(
18668        &mut self,
18669        heights: HashMap<CustomBlockId, u32>,
18670        autoscroll: Option<Autoscroll>,
18671        cx: &mut Context<Self>,
18672    ) {
18673        self.display_map
18674            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18675        if let Some(autoscroll) = autoscroll {
18676            self.request_autoscroll(autoscroll, cx);
18677        }
18678        cx.notify();
18679    }
18680
18681    pub fn replace_blocks(
18682        &mut self,
18683        renderers: HashMap<CustomBlockId, RenderBlock>,
18684        autoscroll: Option<Autoscroll>,
18685        cx: &mut Context<Self>,
18686    ) {
18687        self.display_map
18688            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18689        if let Some(autoscroll) = autoscroll {
18690            self.request_autoscroll(autoscroll, cx);
18691        }
18692        cx.notify();
18693    }
18694
18695    pub fn remove_blocks(
18696        &mut self,
18697        block_ids: HashSet<CustomBlockId>,
18698        autoscroll: Option<Autoscroll>,
18699        cx: &mut Context<Self>,
18700    ) {
18701        self.display_map.update(cx, |display_map, cx| {
18702            display_map.remove_blocks(block_ids, cx)
18703        });
18704        if let Some(autoscroll) = autoscroll {
18705            self.request_autoscroll(autoscroll, cx);
18706        }
18707        cx.notify();
18708    }
18709
18710    pub fn row_for_block(
18711        &self,
18712        block_id: CustomBlockId,
18713        cx: &mut Context<Self>,
18714    ) -> Option<DisplayRow> {
18715        self.display_map
18716            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18717    }
18718
18719    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18720        self.focused_block = Some(focused_block);
18721    }
18722
18723    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18724        self.focused_block.take()
18725    }
18726
18727    pub fn insert_creases(
18728        &mut self,
18729        creases: impl IntoIterator<Item = Crease<Anchor>>,
18730        cx: &mut Context<Self>,
18731    ) -> Vec<CreaseId> {
18732        self.display_map
18733            .update(cx, |map, cx| map.insert_creases(creases, cx))
18734    }
18735
18736    pub fn remove_creases(
18737        &mut self,
18738        ids: impl IntoIterator<Item = CreaseId>,
18739        cx: &mut Context<Self>,
18740    ) -> Vec<(CreaseId, Range<Anchor>)> {
18741        self.display_map
18742            .update(cx, |map, cx| map.remove_creases(ids, cx))
18743    }
18744
18745    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18746        self.display_map
18747            .update(cx, |map, cx| map.snapshot(cx))
18748            .longest_row()
18749    }
18750
18751    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18752        self.display_map
18753            .update(cx, |map, cx| map.snapshot(cx))
18754            .max_point()
18755    }
18756
18757    pub fn text(&self, cx: &App) -> String {
18758        self.buffer.read(cx).read(cx).text()
18759    }
18760
18761    pub fn is_empty(&self, cx: &App) -> bool {
18762        self.buffer.read(cx).read(cx).is_empty()
18763    }
18764
18765    pub fn text_option(&self, cx: &App) -> Option<String> {
18766        let text = self.text(cx);
18767        let text = text.trim();
18768
18769        if text.is_empty() {
18770            return None;
18771        }
18772
18773        Some(text.to_string())
18774    }
18775
18776    pub fn set_text(
18777        &mut self,
18778        text: impl Into<Arc<str>>,
18779        window: &mut Window,
18780        cx: &mut Context<Self>,
18781    ) {
18782        self.transact(window, cx, |this, _, cx| {
18783            this.buffer
18784                .read(cx)
18785                .as_singleton()
18786                .expect("you can only call set_text on editors for singleton buffers")
18787                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18788        });
18789    }
18790
18791    pub fn display_text(&self, cx: &mut App) -> String {
18792        self.display_map
18793            .update(cx, |map, cx| map.snapshot(cx))
18794            .text()
18795    }
18796
18797    fn create_minimap(
18798        &self,
18799        minimap_settings: MinimapSettings,
18800        window: &mut Window,
18801        cx: &mut Context<Self>,
18802    ) -> Option<Entity<Self>> {
18803        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18804            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18805    }
18806
18807    fn initialize_new_minimap(
18808        &self,
18809        minimap_settings: MinimapSettings,
18810        window: &mut Window,
18811        cx: &mut Context<Self>,
18812    ) -> Entity<Self> {
18813        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18814
18815        let mut minimap = Editor::new_internal(
18816            EditorMode::Minimap {
18817                parent: cx.weak_entity(),
18818            },
18819            self.buffer.clone(),
18820            None,
18821            Some(self.display_map.clone()),
18822            window,
18823            cx,
18824        );
18825        minimap.scroll_manager.clone_state(&self.scroll_manager);
18826        minimap.set_text_style_refinement(TextStyleRefinement {
18827            font_size: Some(MINIMAP_FONT_SIZE),
18828            font_weight: Some(MINIMAP_FONT_WEIGHT),
18829            ..Default::default()
18830        });
18831        minimap.update_minimap_configuration(minimap_settings, cx);
18832        cx.new(|_| minimap)
18833    }
18834
18835    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18836        let current_line_highlight = minimap_settings
18837            .current_line_highlight
18838            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18839        self.set_current_line_highlight(Some(current_line_highlight));
18840    }
18841
18842    pub fn minimap(&self) -> Option<&Entity<Self>> {
18843        self.minimap
18844            .as_ref()
18845            .filter(|_| self.minimap_visibility.visible())
18846    }
18847
18848    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18849        let mut wrap_guides = smallvec![];
18850
18851        if self.show_wrap_guides == Some(false) {
18852            return wrap_guides;
18853        }
18854
18855        let settings = self.buffer.read(cx).language_settings(cx);
18856        if settings.show_wrap_guides {
18857            match self.soft_wrap_mode(cx) {
18858                SoftWrap::Column(soft_wrap) => {
18859                    wrap_guides.push((soft_wrap as usize, true));
18860                }
18861                SoftWrap::Bounded(soft_wrap) => {
18862                    wrap_guides.push((soft_wrap as usize, true));
18863                }
18864                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18865            }
18866            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18867        }
18868
18869        wrap_guides
18870    }
18871
18872    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18873        let settings = self.buffer.read(cx).language_settings(cx);
18874        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18875        match mode {
18876            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18877                SoftWrap::None
18878            }
18879            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18880            language_settings::SoftWrap::PreferredLineLength => {
18881                SoftWrap::Column(settings.preferred_line_length)
18882            }
18883            language_settings::SoftWrap::Bounded => {
18884                SoftWrap::Bounded(settings.preferred_line_length)
18885            }
18886        }
18887    }
18888
18889    pub fn set_soft_wrap_mode(
18890        &mut self,
18891        mode: language_settings::SoftWrap,
18892
18893        cx: &mut Context<Self>,
18894    ) {
18895        self.soft_wrap_mode_override = Some(mode);
18896        cx.notify();
18897    }
18898
18899    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18900        self.hard_wrap = hard_wrap;
18901        cx.notify();
18902    }
18903
18904    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18905        self.text_style_refinement = Some(style);
18906    }
18907
18908    /// called by the Element so we know what style we were most recently rendered with.
18909    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
18910        // We intentionally do not inform the display map about the minimap style
18911        // so that wrapping is not recalculated and stays consistent for the editor
18912        // and its linked minimap.
18913        if !self.mode.is_minimap() {
18914            let font = style.text.font();
18915            let font_size = style.text.font_size.to_pixels(window.rem_size());
18916            let display_map = self
18917                .placeholder_display_map
18918                .as_ref()
18919                .filter(|_| self.is_empty(cx))
18920                .unwrap_or(&self.display_map);
18921
18922            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
18923        }
18924        self.style = Some(style);
18925    }
18926
18927    pub fn style(&self) -> Option<&EditorStyle> {
18928        self.style.as_ref()
18929    }
18930
18931    // Called by the element. This method is not designed to be called outside of the editor
18932    // element's layout code because it does not notify when rewrapping is computed synchronously.
18933    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18934        if self.is_empty(cx) {
18935            self.placeholder_display_map
18936                .as_ref()
18937                .map_or(false, |display_map| {
18938                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
18939                })
18940        } else {
18941            self.display_map
18942                .update(cx, |map, cx| map.set_wrap_width(width, cx))
18943        }
18944    }
18945
18946    pub fn set_soft_wrap(&mut self) {
18947        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18948    }
18949
18950    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18951        if self.soft_wrap_mode_override.is_some() {
18952            self.soft_wrap_mode_override.take();
18953        } else {
18954            let soft_wrap = match self.soft_wrap_mode(cx) {
18955                SoftWrap::GitDiff => return,
18956                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18957                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18958                    language_settings::SoftWrap::None
18959                }
18960            };
18961            self.soft_wrap_mode_override = Some(soft_wrap);
18962        }
18963        cx.notify();
18964    }
18965
18966    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18967        let Some(workspace) = self.workspace() else {
18968            return;
18969        };
18970        let fs = workspace.read(cx).app_state().fs.clone();
18971        let current_show = TabBarSettings::get_global(cx).show;
18972        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18973            setting.show = Some(!current_show);
18974        });
18975    }
18976
18977    pub fn toggle_indent_guides(
18978        &mut self,
18979        _: &ToggleIndentGuides,
18980        _: &mut Window,
18981        cx: &mut Context<Self>,
18982    ) {
18983        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18984            self.buffer
18985                .read(cx)
18986                .language_settings(cx)
18987                .indent_guides
18988                .enabled
18989        });
18990        self.show_indent_guides = Some(!currently_enabled);
18991        cx.notify();
18992    }
18993
18994    fn should_show_indent_guides(&self) -> Option<bool> {
18995        self.show_indent_guides
18996    }
18997
18998    pub fn toggle_line_numbers(
18999        &mut self,
19000        _: &ToggleLineNumbers,
19001        _: &mut Window,
19002        cx: &mut Context<Self>,
19003    ) {
19004        let mut editor_settings = EditorSettings::get_global(cx).clone();
19005        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19006        EditorSettings::override_global(editor_settings, cx);
19007    }
19008
19009    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19010        if let Some(show_line_numbers) = self.show_line_numbers {
19011            return show_line_numbers;
19012        }
19013        EditorSettings::get_global(cx).gutter.line_numbers
19014    }
19015
19016    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19017        self.use_relative_line_numbers
19018            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19019    }
19020
19021    pub fn toggle_relative_line_numbers(
19022        &mut self,
19023        _: &ToggleRelativeLineNumbers,
19024        _: &mut Window,
19025        cx: &mut Context<Self>,
19026    ) {
19027        let is_relative = self.should_use_relative_line_numbers(cx);
19028        self.set_relative_line_number(Some(!is_relative), cx)
19029    }
19030
19031    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19032        self.use_relative_line_numbers = is_relative;
19033        cx.notify();
19034    }
19035
19036    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19037        self.show_gutter = show_gutter;
19038        cx.notify();
19039    }
19040
19041    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19042        self.show_scrollbars = ScrollbarAxes {
19043            horizontal: show,
19044            vertical: show,
19045        };
19046        cx.notify();
19047    }
19048
19049    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19050        self.show_scrollbars.vertical = show;
19051        cx.notify();
19052    }
19053
19054    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19055        self.show_scrollbars.horizontal = show;
19056        cx.notify();
19057    }
19058
19059    pub fn set_minimap_visibility(
19060        &mut self,
19061        minimap_visibility: MinimapVisibility,
19062        window: &mut Window,
19063        cx: &mut Context<Self>,
19064    ) {
19065        if self.minimap_visibility != minimap_visibility {
19066            if minimap_visibility.visible() && self.minimap.is_none() {
19067                let minimap_settings = EditorSettings::get_global(cx).minimap;
19068                self.minimap =
19069                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19070            }
19071            self.minimap_visibility = minimap_visibility;
19072            cx.notify();
19073        }
19074    }
19075
19076    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19077        self.set_show_scrollbars(false, cx);
19078        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19079    }
19080
19081    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19082        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19083    }
19084
19085    /// Normally the text in full mode and auto height editors is padded on the
19086    /// left side by roughly half a character width for improved hit testing.
19087    ///
19088    /// Use this method to disable this for cases where this is not wanted (e.g.
19089    /// if you want to align the editor text with some other text above or below)
19090    /// or if you want to add this padding to single-line editors.
19091    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19092        self.offset_content = offset_content;
19093        cx.notify();
19094    }
19095
19096    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19097        self.show_line_numbers = Some(show_line_numbers);
19098        cx.notify();
19099    }
19100
19101    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19102        self.disable_expand_excerpt_buttons = true;
19103        cx.notify();
19104    }
19105
19106    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19107        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19108        cx.notify();
19109    }
19110
19111    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19112        self.show_code_actions = Some(show_code_actions);
19113        cx.notify();
19114    }
19115
19116    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19117        self.show_runnables = Some(show_runnables);
19118        cx.notify();
19119    }
19120
19121    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19122        self.show_breakpoints = Some(show_breakpoints);
19123        cx.notify();
19124    }
19125
19126    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19127        if self.display_map.read(cx).masked != masked {
19128            self.display_map.update(cx, |map, _| map.masked = masked);
19129        }
19130        cx.notify()
19131    }
19132
19133    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19134        self.show_wrap_guides = Some(show_wrap_guides);
19135        cx.notify();
19136    }
19137
19138    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19139        self.show_indent_guides = Some(show_indent_guides);
19140        cx.notify();
19141    }
19142
19143    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19144        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19145            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19146                && let Some(dir) = file.abs_path(cx).parent()
19147            {
19148                return Some(dir.to_owned());
19149            }
19150
19151            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19152                return Some(project_path.path.to_path_buf());
19153            }
19154        }
19155
19156        None
19157    }
19158
19159    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19160        self.active_excerpt(cx)?
19161            .1
19162            .read(cx)
19163            .file()
19164            .and_then(|f| f.as_local())
19165    }
19166
19167    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19168        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19169            let buffer = buffer.read(cx);
19170            if let Some(project_path) = buffer.project_path(cx) {
19171                let project = self.project()?.read(cx);
19172                project.absolute_path(&project_path, cx)
19173            } else {
19174                buffer
19175                    .file()
19176                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19177            }
19178        })
19179    }
19180
19181    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19182        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19183            let project_path = buffer.read(cx).project_path(cx)?;
19184            let project = self.project()?.read(cx);
19185            let entry = project.entry_for_path(&project_path, cx)?;
19186            let path = entry.path.to_path_buf();
19187            Some(path)
19188        })
19189    }
19190
19191    pub fn reveal_in_finder(
19192        &mut self,
19193        _: &RevealInFileManager,
19194        _window: &mut Window,
19195        cx: &mut Context<Self>,
19196    ) {
19197        if let Some(target) = self.target_file(cx) {
19198            cx.reveal_path(&target.abs_path(cx));
19199        }
19200    }
19201
19202    pub fn copy_path(
19203        &mut self,
19204        _: &zed_actions::workspace::CopyPath,
19205        _window: &mut Window,
19206        cx: &mut Context<Self>,
19207    ) {
19208        if let Some(path) = self.target_file_abs_path(cx)
19209            && let Some(path) = path.to_str()
19210        {
19211            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19212        }
19213    }
19214
19215    pub fn copy_relative_path(
19216        &mut self,
19217        _: &zed_actions::workspace::CopyRelativePath,
19218        _window: &mut Window,
19219        cx: &mut Context<Self>,
19220    ) {
19221        if let Some(path) = self.target_file_path(cx)
19222            && let Some(path) = path.to_str()
19223        {
19224            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19225        }
19226    }
19227
19228    /// Returns the project path for the editor's buffer, if any buffer is
19229    /// opened in the editor.
19230    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19231        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19232            buffer.read(cx).project_path(cx)
19233        } else {
19234            None
19235        }
19236    }
19237
19238    // Returns true if the editor handled a go-to-line request
19239    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19240        maybe!({
19241            let breakpoint_store = self.breakpoint_store.as_ref()?;
19242
19243            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19244            else {
19245                self.clear_row_highlights::<ActiveDebugLine>();
19246                return None;
19247            };
19248
19249            let position = active_stack_frame.position;
19250            let buffer_id = position.buffer_id?;
19251            let snapshot = self
19252                .project
19253                .as_ref()?
19254                .read(cx)
19255                .buffer_for_id(buffer_id, cx)?
19256                .read(cx)
19257                .snapshot();
19258
19259            let mut handled = false;
19260            for (id, ExcerptRange { context, .. }) in
19261                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19262            {
19263                if context.start.cmp(&position, &snapshot).is_ge()
19264                    || context.end.cmp(&position, &snapshot).is_lt()
19265                {
19266                    continue;
19267                }
19268                let snapshot = self.buffer.read(cx).snapshot(cx);
19269                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19270
19271                handled = true;
19272                self.clear_row_highlights::<ActiveDebugLine>();
19273
19274                self.go_to_line::<ActiveDebugLine>(
19275                    multibuffer_anchor,
19276                    Some(cx.theme().colors().editor_debugger_active_line_background),
19277                    window,
19278                    cx,
19279                );
19280
19281                cx.notify();
19282            }
19283
19284            handled.then_some(())
19285        })
19286        .is_some()
19287    }
19288
19289    pub fn copy_file_name_without_extension(
19290        &mut self,
19291        _: &CopyFileNameWithoutExtension,
19292        _: &mut Window,
19293        cx: &mut Context<Self>,
19294    ) {
19295        if let Some(file) = self.target_file(cx)
19296            && let Some(file_stem) = file.path().file_stem()
19297            && let Some(name) = file_stem.to_str()
19298        {
19299            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19300        }
19301    }
19302
19303    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19304        if let Some(file) = self.target_file(cx)
19305            && let Some(file_name) = file.path().file_name()
19306            && let Some(name) = file_name.to_str()
19307        {
19308            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19309        }
19310    }
19311
19312    pub fn toggle_git_blame(
19313        &mut self,
19314        _: &::git::Blame,
19315        window: &mut Window,
19316        cx: &mut Context<Self>,
19317    ) {
19318        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19319
19320        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19321            self.start_git_blame(true, window, cx);
19322        }
19323
19324        cx.notify();
19325    }
19326
19327    pub fn toggle_git_blame_inline(
19328        &mut self,
19329        _: &ToggleGitBlameInline,
19330        window: &mut Window,
19331        cx: &mut Context<Self>,
19332    ) {
19333        self.toggle_git_blame_inline_internal(true, window, cx);
19334        cx.notify();
19335    }
19336
19337    pub fn open_git_blame_commit(
19338        &mut self,
19339        _: &OpenGitBlameCommit,
19340        window: &mut Window,
19341        cx: &mut Context<Self>,
19342    ) {
19343        self.open_git_blame_commit_internal(window, cx);
19344    }
19345
19346    fn open_git_blame_commit_internal(
19347        &mut self,
19348        window: &mut Window,
19349        cx: &mut Context<Self>,
19350    ) -> Option<()> {
19351        let blame = self.blame.as_ref()?;
19352        let snapshot = self.snapshot(window, cx);
19353        let cursor = self.selections.newest::<Point>(cx).head();
19354        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19355        let (_, blame_entry) = blame
19356            .update(cx, |blame, cx| {
19357                blame
19358                    .blame_for_rows(
19359                        &[RowInfo {
19360                            buffer_id: Some(buffer.remote_id()),
19361                            buffer_row: Some(point.row),
19362                            ..Default::default()
19363                        }],
19364                        cx,
19365                    )
19366                    .next()
19367            })
19368            .flatten()?;
19369        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19370        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19371        let workspace = self.workspace()?.downgrade();
19372        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19373        None
19374    }
19375
19376    pub fn git_blame_inline_enabled(&self) -> bool {
19377        self.git_blame_inline_enabled
19378    }
19379
19380    pub fn toggle_selection_menu(
19381        &mut self,
19382        _: &ToggleSelectionMenu,
19383        _: &mut Window,
19384        cx: &mut Context<Self>,
19385    ) {
19386        self.show_selection_menu = self
19387            .show_selection_menu
19388            .map(|show_selections_menu| !show_selections_menu)
19389            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19390
19391        cx.notify();
19392    }
19393
19394    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19395        self.show_selection_menu
19396            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19397    }
19398
19399    fn start_git_blame(
19400        &mut self,
19401        user_triggered: bool,
19402        window: &mut Window,
19403        cx: &mut Context<Self>,
19404    ) {
19405        if let Some(project) = self.project() {
19406            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19407                && buffer.read(cx).file().is_none()
19408            {
19409                return;
19410            }
19411
19412            let focused = self.focus_handle(cx).contains_focused(window, cx);
19413
19414            let project = project.clone();
19415            let blame = cx
19416                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19417            self.blame_subscription =
19418                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19419            self.blame = Some(blame);
19420        }
19421    }
19422
19423    fn toggle_git_blame_inline_internal(
19424        &mut self,
19425        user_triggered: bool,
19426        window: &mut Window,
19427        cx: &mut Context<Self>,
19428    ) {
19429        if self.git_blame_inline_enabled {
19430            self.git_blame_inline_enabled = false;
19431            self.show_git_blame_inline = false;
19432            self.show_git_blame_inline_delay_task.take();
19433        } else {
19434            self.git_blame_inline_enabled = true;
19435            self.start_git_blame_inline(user_triggered, window, cx);
19436        }
19437
19438        cx.notify();
19439    }
19440
19441    fn start_git_blame_inline(
19442        &mut self,
19443        user_triggered: bool,
19444        window: &mut Window,
19445        cx: &mut Context<Self>,
19446    ) {
19447        self.start_git_blame(user_triggered, window, cx);
19448
19449        if ProjectSettings::get_global(cx)
19450            .git
19451            .inline_blame_delay()
19452            .is_some()
19453        {
19454            self.start_inline_blame_timer(window, cx);
19455        } else {
19456            self.show_git_blame_inline = true
19457        }
19458    }
19459
19460    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19461        self.blame.as_ref()
19462    }
19463
19464    pub fn show_git_blame_gutter(&self) -> bool {
19465        self.show_git_blame_gutter
19466    }
19467
19468    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19469        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19470    }
19471
19472    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19473        self.show_git_blame_inline
19474            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19475            && !self.newest_selection_head_on_empty_line(cx)
19476            && self.has_blame_entries(cx)
19477    }
19478
19479    fn has_blame_entries(&self, cx: &App) -> bool {
19480        self.blame()
19481            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19482    }
19483
19484    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19485        let cursor_anchor = self.selections.newest_anchor().head();
19486
19487        let snapshot = self.buffer.read(cx).snapshot(cx);
19488        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19489
19490        snapshot.line_len(buffer_row) == 0
19491    }
19492
19493    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19494        let buffer_and_selection = maybe!({
19495            let selection = self.selections.newest::<Point>(cx);
19496            let selection_range = selection.range();
19497
19498            let multi_buffer = self.buffer().read(cx);
19499            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19500            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19501
19502            let (buffer, range, _) = if selection.reversed {
19503                buffer_ranges.first()
19504            } else {
19505                buffer_ranges.last()
19506            }?;
19507
19508            let selection = text::ToPoint::to_point(&range.start, buffer).row
19509                ..text::ToPoint::to_point(&range.end, buffer).row;
19510            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19511        });
19512
19513        let Some((buffer, selection)) = buffer_and_selection else {
19514            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19515        };
19516
19517        let Some(project) = self.project() else {
19518            return Task::ready(Err(anyhow!("editor does not have project")));
19519        };
19520
19521        project.update(cx, |project, cx| {
19522            project.get_permalink_to_line(&buffer, selection, cx)
19523        })
19524    }
19525
19526    pub fn copy_permalink_to_line(
19527        &mut self,
19528        _: &CopyPermalinkToLine,
19529        window: &mut Window,
19530        cx: &mut Context<Self>,
19531    ) {
19532        let permalink_task = self.get_permalink_to_line(cx);
19533        let workspace = self.workspace();
19534
19535        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19536            Ok(permalink) => {
19537                cx.update(|_, cx| {
19538                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19539                })
19540                .ok();
19541            }
19542            Err(err) => {
19543                let message = format!("Failed to copy permalink: {err}");
19544
19545                anyhow::Result::<()>::Err(err).log_err();
19546
19547                if let Some(workspace) = workspace {
19548                    workspace
19549                        .update_in(cx, |workspace, _, cx| {
19550                            struct CopyPermalinkToLine;
19551
19552                            workspace.show_toast(
19553                                Toast::new(
19554                                    NotificationId::unique::<CopyPermalinkToLine>(),
19555                                    message,
19556                                ),
19557                                cx,
19558                            )
19559                        })
19560                        .ok();
19561                }
19562            }
19563        })
19564        .detach();
19565    }
19566
19567    pub fn copy_file_location(
19568        &mut self,
19569        _: &CopyFileLocation,
19570        _: &mut Window,
19571        cx: &mut Context<Self>,
19572    ) {
19573        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19574        if let Some(file) = self.target_file(cx)
19575            && let Some(path) = file.path().to_str()
19576        {
19577            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19578        }
19579    }
19580
19581    pub fn open_permalink_to_line(
19582        &mut self,
19583        _: &OpenPermalinkToLine,
19584        window: &mut Window,
19585        cx: &mut Context<Self>,
19586    ) {
19587        let permalink_task = self.get_permalink_to_line(cx);
19588        let workspace = self.workspace();
19589
19590        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19591            Ok(permalink) => {
19592                cx.update(|_, cx| {
19593                    cx.open_url(permalink.as_ref());
19594                })
19595                .ok();
19596            }
19597            Err(err) => {
19598                let message = format!("Failed to open permalink: {err}");
19599
19600                anyhow::Result::<()>::Err(err).log_err();
19601
19602                if let Some(workspace) = workspace {
19603                    workspace
19604                        .update(cx, |workspace, cx| {
19605                            struct OpenPermalinkToLine;
19606
19607                            workspace.show_toast(
19608                                Toast::new(
19609                                    NotificationId::unique::<OpenPermalinkToLine>(),
19610                                    message,
19611                                ),
19612                                cx,
19613                            )
19614                        })
19615                        .ok();
19616                }
19617            }
19618        })
19619        .detach();
19620    }
19621
19622    pub fn insert_uuid_v4(
19623        &mut self,
19624        _: &InsertUuidV4,
19625        window: &mut Window,
19626        cx: &mut Context<Self>,
19627    ) {
19628        self.insert_uuid(UuidVersion::V4, window, cx);
19629    }
19630
19631    pub fn insert_uuid_v7(
19632        &mut self,
19633        _: &InsertUuidV7,
19634        window: &mut Window,
19635        cx: &mut Context<Self>,
19636    ) {
19637        self.insert_uuid(UuidVersion::V7, window, cx);
19638    }
19639
19640    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19641        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19642        self.transact(window, cx, |this, window, cx| {
19643            let edits = this
19644                .selections
19645                .all::<Point>(cx)
19646                .into_iter()
19647                .map(|selection| {
19648                    let uuid = match version {
19649                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19650                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19651                    };
19652
19653                    (selection.range(), uuid.to_string())
19654                });
19655            this.edit(edits, cx);
19656            this.refresh_edit_prediction(true, false, window, cx);
19657        });
19658    }
19659
19660    pub fn open_selections_in_multibuffer(
19661        &mut self,
19662        _: &OpenSelectionsInMultibuffer,
19663        window: &mut Window,
19664        cx: &mut Context<Self>,
19665    ) {
19666        let multibuffer = self.buffer.read(cx);
19667
19668        let Some(buffer) = multibuffer.as_singleton() else {
19669            return;
19670        };
19671
19672        let Some(workspace) = self.workspace() else {
19673            return;
19674        };
19675
19676        let title = multibuffer.title(cx).to_string();
19677
19678        let locations = self
19679            .selections
19680            .all_anchors(cx)
19681            .iter()
19682            .map(|selection| Location {
19683                buffer: buffer.clone(),
19684                range: selection.start.text_anchor..selection.end.text_anchor,
19685            })
19686            .collect::<Vec<_>>();
19687
19688        cx.spawn_in(window, async move |_, cx| {
19689            workspace.update_in(cx, |workspace, window, cx| {
19690                Self::open_locations_in_multibuffer(
19691                    workspace,
19692                    locations,
19693                    format!("Selections for '{title}'"),
19694                    false,
19695                    MultibufferSelectionMode::All,
19696                    window,
19697                    cx,
19698                );
19699            })
19700        })
19701        .detach();
19702    }
19703
19704    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19705    /// last highlight added will be used.
19706    ///
19707    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19708    pub fn highlight_rows<T: 'static>(
19709        &mut self,
19710        range: Range<Anchor>,
19711        color: Hsla,
19712        options: RowHighlightOptions,
19713        cx: &mut Context<Self>,
19714    ) {
19715        let snapshot = self.buffer().read(cx).snapshot(cx);
19716        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19717        let ix = row_highlights.binary_search_by(|highlight| {
19718            Ordering::Equal
19719                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19720                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19721        });
19722
19723        if let Err(mut ix) = ix {
19724            let index = post_inc(&mut self.highlight_order);
19725
19726            // If this range intersects with the preceding highlight, then merge it with
19727            // the preceding highlight. Otherwise insert a new highlight.
19728            let mut merged = false;
19729            if ix > 0 {
19730                let prev_highlight = &mut row_highlights[ix - 1];
19731                if prev_highlight
19732                    .range
19733                    .end
19734                    .cmp(&range.start, &snapshot)
19735                    .is_ge()
19736                {
19737                    ix -= 1;
19738                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19739                        prev_highlight.range.end = range.end;
19740                    }
19741                    merged = true;
19742                    prev_highlight.index = index;
19743                    prev_highlight.color = color;
19744                    prev_highlight.options = options;
19745                }
19746            }
19747
19748            if !merged {
19749                row_highlights.insert(
19750                    ix,
19751                    RowHighlight {
19752                        range,
19753                        index,
19754                        color,
19755                        options,
19756                        type_id: TypeId::of::<T>(),
19757                    },
19758                );
19759            }
19760
19761            // If any of the following highlights intersect with this one, merge them.
19762            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19763                let highlight = &row_highlights[ix];
19764                if next_highlight
19765                    .range
19766                    .start
19767                    .cmp(&highlight.range.end, &snapshot)
19768                    .is_le()
19769                {
19770                    if next_highlight
19771                        .range
19772                        .end
19773                        .cmp(&highlight.range.end, &snapshot)
19774                        .is_gt()
19775                    {
19776                        row_highlights[ix].range.end = next_highlight.range.end;
19777                    }
19778                    row_highlights.remove(ix + 1);
19779                } else {
19780                    break;
19781                }
19782            }
19783        }
19784    }
19785
19786    /// Remove any highlighted row ranges of the given type that intersect the
19787    /// given ranges.
19788    pub fn remove_highlighted_rows<T: 'static>(
19789        &mut self,
19790        ranges_to_remove: Vec<Range<Anchor>>,
19791        cx: &mut Context<Self>,
19792    ) {
19793        let snapshot = self.buffer().read(cx).snapshot(cx);
19794        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19795        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19796        row_highlights.retain(|highlight| {
19797            while let Some(range_to_remove) = ranges_to_remove.peek() {
19798                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19799                    Ordering::Less | Ordering::Equal => {
19800                        ranges_to_remove.next();
19801                    }
19802                    Ordering::Greater => {
19803                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19804                            Ordering::Less | Ordering::Equal => {
19805                                return false;
19806                            }
19807                            Ordering::Greater => break,
19808                        }
19809                    }
19810                }
19811            }
19812
19813            true
19814        })
19815    }
19816
19817    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19818    pub fn clear_row_highlights<T: 'static>(&mut self) {
19819        self.highlighted_rows.remove(&TypeId::of::<T>());
19820    }
19821
19822    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19823    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19824        self.highlighted_rows
19825            .get(&TypeId::of::<T>())
19826            .map_or(&[] as &[_], |vec| vec.as_slice())
19827            .iter()
19828            .map(|highlight| (highlight.range.clone(), highlight.color))
19829    }
19830
19831    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19832    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19833    /// Allows to ignore certain kinds of highlights.
19834    pub fn highlighted_display_rows(
19835        &self,
19836        window: &mut Window,
19837        cx: &mut App,
19838    ) -> BTreeMap<DisplayRow, LineHighlight> {
19839        let snapshot = self.snapshot(window, cx);
19840        let mut used_highlight_orders = HashMap::default();
19841        self.highlighted_rows
19842            .iter()
19843            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19844            .fold(
19845                BTreeMap::<DisplayRow, LineHighlight>::new(),
19846                |mut unique_rows, highlight| {
19847                    let start = highlight.range.start.to_display_point(&snapshot);
19848                    let end = highlight.range.end.to_display_point(&snapshot);
19849                    let start_row = start.row().0;
19850                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19851                        && end.column() == 0
19852                    {
19853                        end.row().0.saturating_sub(1)
19854                    } else {
19855                        end.row().0
19856                    };
19857                    for row in start_row..=end_row {
19858                        let used_index =
19859                            used_highlight_orders.entry(row).or_insert(highlight.index);
19860                        if highlight.index >= *used_index {
19861                            *used_index = highlight.index;
19862                            unique_rows.insert(
19863                                DisplayRow(row),
19864                                LineHighlight {
19865                                    include_gutter: highlight.options.include_gutter,
19866                                    border: None,
19867                                    background: highlight.color.into(),
19868                                    type_id: Some(highlight.type_id),
19869                                },
19870                            );
19871                        }
19872                    }
19873                    unique_rows
19874                },
19875            )
19876    }
19877
19878    pub fn highlighted_display_row_for_autoscroll(
19879        &self,
19880        snapshot: &DisplaySnapshot,
19881    ) -> Option<DisplayRow> {
19882        self.highlighted_rows
19883            .values()
19884            .flat_map(|highlighted_rows| highlighted_rows.iter())
19885            .filter_map(|highlight| {
19886                if highlight.options.autoscroll {
19887                    Some(highlight.range.start.to_display_point(snapshot).row())
19888                } else {
19889                    None
19890                }
19891            })
19892            .min()
19893    }
19894
19895    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19896        self.highlight_background::<SearchWithinRange>(
19897            ranges,
19898            |colors| colors.colors().editor_document_highlight_read_background,
19899            cx,
19900        )
19901    }
19902
19903    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19904        self.breadcrumb_header = Some(new_header);
19905    }
19906
19907    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19908        self.clear_background_highlights::<SearchWithinRange>(cx);
19909    }
19910
19911    pub fn highlight_background<T: 'static>(
19912        &mut self,
19913        ranges: &[Range<Anchor>],
19914        color_fetcher: fn(&Theme) -> Hsla,
19915        cx: &mut Context<Self>,
19916    ) {
19917        self.background_highlights.insert(
19918            HighlightKey::Type(TypeId::of::<T>()),
19919            (color_fetcher, Arc::from(ranges)),
19920        );
19921        self.scrollbar_marker_state.dirty = true;
19922        cx.notify();
19923    }
19924
19925    pub fn highlight_background_key<T: 'static>(
19926        &mut self,
19927        key: usize,
19928        ranges: &[Range<Anchor>],
19929        color_fetcher: fn(&Theme) -> Hsla,
19930        cx: &mut Context<Self>,
19931    ) {
19932        self.background_highlights.insert(
19933            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19934            (color_fetcher, Arc::from(ranges)),
19935        );
19936        self.scrollbar_marker_state.dirty = true;
19937        cx.notify();
19938    }
19939
19940    pub fn clear_background_highlights<T: 'static>(
19941        &mut self,
19942        cx: &mut Context<Self>,
19943    ) -> Option<BackgroundHighlight> {
19944        let text_highlights = self
19945            .background_highlights
19946            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19947        if !text_highlights.1.is_empty() {
19948            self.scrollbar_marker_state.dirty = true;
19949            cx.notify();
19950        }
19951        Some(text_highlights)
19952    }
19953
19954    pub fn highlight_gutter<T: 'static>(
19955        &mut self,
19956        ranges: impl Into<Vec<Range<Anchor>>>,
19957        color_fetcher: fn(&App) -> Hsla,
19958        cx: &mut Context<Self>,
19959    ) {
19960        self.gutter_highlights
19961            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19962        cx.notify();
19963    }
19964
19965    pub fn clear_gutter_highlights<T: 'static>(
19966        &mut self,
19967        cx: &mut Context<Self>,
19968    ) -> Option<GutterHighlight> {
19969        cx.notify();
19970        self.gutter_highlights.remove(&TypeId::of::<T>())
19971    }
19972
19973    pub fn insert_gutter_highlight<T: 'static>(
19974        &mut self,
19975        range: Range<Anchor>,
19976        color_fetcher: fn(&App) -> Hsla,
19977        cx: &mut Context<Self>,
19978    ) {
19979        let snapshot = self.buffer().read(cx).snapshot(cx);
19980        let mut highlights = self
19981            .gutter_highlights
19982            .remove(&TypeId::of::<T>())
19983            .map(|(_, highlights)| highlights)
19984            .unwrap_or_default();
19985        let ix = highlights.binary_search_by(|highlight| {
19986            Ordering::Equal
19987                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19988                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19989        });
19990        if let Err(ix) = ix {
19991            highlights.insert(ix, range);
19992        }
19993        self.gutter_highlights
19994            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19995    }
19996
19997    pub fn remove_gutter_highlights<T: 'static>(
19998        &mut self,
19999        ranges_to_remove: Vec<Range<Anchor>>,
20000        cx: &mut Context<Self>,
20001    ) {
20002        let snapshot = self.buffer().read(cx).snapshot(cx);
20003        let Some((color_fetcher, mut gutter_highlights)) =
20004            self.gutter_highlights.remove(&TypeId::of::<T>())
20005        else {
20006            return;
20007        };
20008        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20009        gutter_highlights.retain(|highlight| {
20010            while let Some(range_to_remove) = ranges_to_remove.peek() {
20011                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20012                    Ordering::Less | Ordering::Equal => {
20013                        ranges_to_remove.next();
20014                    }
20015                    Ordering::Greater => {
20016                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20017                            Ordering::Less | Ordering::Equal => {
20018                                return false;
20019                            }
20020                            Ordering::Greater => break,
20021                        }
20022                    }
20023                }
20024            }
20025
20026            true
20027        });
20028        self.gutter_highlights
20029            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20030    }
20031
20032    #[cfg(feature = "test-support")]
20033    pub fn all_text_highlights(
20034        &self,
20035        window: &mut Window,
20036        cx: &mut Context<Self>,
20037    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20038        let snapshot = self.snapshot(window, cx);
20039        self.display_map.update(cx, |display_map, _| {
20040            display_map
20041                .all_text_highlights()
20042                .map(|highlight| {
20043                    let (style, ranges) = highlight.as_ref();
20044                    (
20045                        *style,
20046                        ranges
20047                            .iter()
20048                            .map(|range| range.clone().to_display_points(&snapshot))
20049                            .collect(),
20050                    )
20051                })
20052                .collect()
20053        })
20054    }
20055
20056    #[cfg(feature = "test-support")]
20057    pub fn all_text_background_highlights(
20058        &self,
20059        window: &mut Window,
20060        cx: &mut Context<Self>,
20061    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20062        let snapshot = self.snapshot(window, cx);
20063        let buffer = &snapshot.buffer_snapshot;
20064        let start = buffer.anchor_before(0);
20065        let end = buffer.anchor_after(buffer.len());
20066        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20067    }
20068
20069    #[cfg(any(test, feature = "test-support"))]
20070    pub fn sorted_background_highlights_in_range(
20071        &self,
20072        search_range: Range<Anchor>,
20073        display_snapshot: &DisplaySnapshot,
20074        theme: &Theme,
20075    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20076        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20077        res.sort_by(|a, b| {
20078            a.0.start
20079                .cmp(&b.0.start)
20080                .then_with(|| a.0.end.cmp(&b.0.end))
20081                .then_with(|| a.1.cmp(&b.1))
20082        });
20083        res
20084    }
20085
20086    #[cfg(feature = "test-support")]
20087    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20088        let snapshot = self.buffer().read(cx).snapshot(cx);
20089
20090        let highlights = self
20091            .background_highlights
20092            .get(&HighlightKey::Type(TypeId::of::<
20093                items::BufferSearchHighlights,
20094            >()));
20095
20096        if let Some((_color, ranges)) = highlights {
20097            ranges
20098                .iter()
20099                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20100                .collect_vec()
20101        } else {
20102            vec![]
20103        }
20104    }
20105
20106    fn document_highlights_for_position<'a>(
20107        &'a self,
20108        position: Anchor,
20109        buffer: &'a MultiBufferSnapshot,
20110    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20111        let read_highlights = self
20112            .background_highlights
20113            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20114            .map(|h| &h.1);
20115        let write_highlights = self
20116            .background_highlights
20117            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20118            .map(|h| &h.1);
20119        let left_position = position.bias_left(buffer);
20120        let right_position = position.bias_right(buffer);
20121        read_highlights
20122            .into_iter()
20123            .chain(write_highlights)
20124            .flat_map(move |ranges| {
20125                let start_ix = match ranges.binary_search_by(|probe| {
20126                    let cmp = probe.end.cmp(&left_position, buffer);
20127                    if cmp.is_ge() {
20128                        Ordering::Greater
20129                    } else {
20130                        Ordering::Less
20131                    }
20132                }) {
20133                    Ok(i) | Err(i) => i,
20134                };
20135
20136                ranges[start_ix..]
20137                    .iter()
20138                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20139            })
20140    }
20141
20142    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20143        self.background_highlights
20144            .get(&HighlightKey::Type(TypeId::of::<T>()))
20145            .is_some_and(|(_, highlights)| !highlights.is_empty())
20146    }
20147
20148    /// Returns all background highlights for a given range.
20149    ///
20150    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20151    pub fn background_highlights_in_range(
20152        &self,
20153        search_range: Range<Anchor>,
20154        display_snapshot: &DisplaySnapshot,
20155        theme: &Theme,
20156    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20157        let mut results = Vec::new();
20158        for (color_fetcher, ranges) in self.background_highlights.values() {
20159            let color = color_fetcher(theme);
20160            let start_ix = match ranges.binary_search_by(|probe| {
20161                let cmp = probe
20162                    .end
20163                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20164                if cmp.is_gt() {
20165                    Ordering::Greater
20166                } else {
20167                    Ordering::Less
20168                }
20169            }) {
20170                Ok(i) | Err(i) => i,
20171            };
20172            for range in &ranges[start_ix..] {
20173                if range
20174                    .start
20175                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20176                    .is_ge()
20177                {
20178                    break;
20179                }
20180
20181                let start = range.start.to_display_point(display_snapshot);
20182                let end = range.end.to_display_point(display_snapshot);
20183                results.push((start..end, color))
20184            }
20185        }
20186        results
20187    }
20188
20189    pub fn gutter_highlights_in_range(
20190        &self,
20191        search_range: Range<Anchor>,
20192        display_snapshot: &DisplaySnapshot,
20193        cx: &App,
20194    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20195        let mut results = Vec::new();
20196        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20197            let color = color_fetcher(cx);
20198            let start_ix = match ranges.binary_search_by(|probe| {
20199                let cmp = probe
20200                    .end
20201                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20202                if cmp.is_gt() {
20203                    Ordering::Greater
20204                } else {
20205                    Ordering::Less
20206                }
20207            }) {
20208                Ok(i) | Err(i) => i,
20209            };
20210            for range in &ranges[start_ix..] {
20211                if range
20212                    .start
20213                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20214                    .is_ge()
20215                {
20216                    break;
20217                }
20218
20219                let start = range.start.to_display_point(display_snapshot);
20220                let end = range.end.to_display_point(display_snapshot);
20221                results.push((start..end, color))
20222            }
20223        }
20224        results
20225    }
20226
20227    /// Get the text ranges corresponding to the redaction query
20228    pub fn redacted_ranges(
20229        &self,
20230        search_range: Range<Anchor>,
20231        display_snapshot: &DisplaySnapshot,
20232        cx: &App,
20233    ) -> Vec<Range<DisplayPoint>> {
20234        display_snapshot
20235            .buffer_snapshot
20236            .redacted_ranges(search_range, |file| {
20237                if let Some(file) = file {
20238                    file.is_private()
20239                        && EditorSettings::get(
20240                            Some(SettingsLocation {
20241                                worktree_id: file.worktree_id(cx),
20242                                path: file.path().as_ref(),
20243                            }),
20244                            cx,
20245                        )
20246                        .redact_private_values
20247                } else {
20248                    false
20249                }
20250            })
20251            .map(|range| {
20252                range.start.to_display_point(display_snapshot)
20253                    ..range.end.to_display_point(display_snapshot)
20254            })
20255            .collect()
20256    }
20257
20258    pub fn highlight_text_key<T: 'static>(
20259        &mut self,
20260        key: usize,
20261        ranges: Vec<Range<Anchor>>,
20262        style: HighlightStyle,
20263        cx: &mut Context<Self>,
20264    ) {
20265        self.display_map.update(cx, |map, _| {
20266            map.highlight_text(
20267                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20268                ranges,
20269                style,
20270            );
20271        });
20272        cx.notify();
20273    }
20274
20275    pub fn highlight_text<T: 'static>(
20276        &mut self,
20277        ranges: Vec<Range<Anchor>>,
20278        style: HighlightStyle,
20279        cx: &mut Context<Self>,
20280    ) {
20281        self.display_map.update(cx, |map, _| {
20282            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20283        });
20284        cx.notify();
20285    }
20286
20287    pub(crate) fn highlight_inlays<T: 'static>(
20288        &mut self,
20289        highlights: Vec<InlayHighlight>,
20290        style: HighlightStyle,
20291        cx: &mut Context<Self>,
20292    ) {
20293        self.display_map.update(cx, |map, _| {
20294            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20295        });
20296        cx.notify();
20297    }
20298
20299    pub fn text_highlights<'a, T: 'static>(
20300        &'a self,
20301        cx: &'a App,
20302    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20303        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20304    }
20305
20306    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20307        let cleared = self
20308            .display_map
20309            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20310        if cleared {
20311            cx.notify();
20312        }
20313    }
20314
20315    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20316        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20317            && self.focus_handle.is_focused(window)
20318    }
20319
20320    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20321        self.show_cursor_when_unfocused = is_enabled;
20322        cx.notify();
20323    }
20324
20325    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20326        cx.notify();
20327    }
20328
20329    fn on_debug_session_event(
20330        &mut self,
20331        _session: Entity<Session>,
20332        event: &SessionEvent,
20333        cx: &mut Context<Self>,
20334    ) {
20335        if let SessionEvent::InvalidateInlineValue = event {
20336            self.refresh_inline_values(cx);
20337        }
20338    }
20339
20340    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20341        let Some(project) = self.project.clone() else {
20342            return;
20343        };
20344
20345        if !self.inline_value_cache.enabled {
20346            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20347            self.splice_inlays(&inlays, Vec::new(), cx);
20348            return;
20349        }
20350
20351        let current_execution_position = self
20352            .highlighted_rows
20353            .get(&TypeId::of::<ActiveDebugLine>())
20354            .and_then(|lines| lines.last().map(|line| line.range.end));
20355
20356        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20357            let inline_values = editor
20358                .update(cx, |editor, cx| {
20359                    let Some(current_execution_position) = current_execution_position else {
20360                        return Some(Task::ready(Ok(Vec::new())));
20361                    };
20362
20363                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20364                        let snapshot = buffer.snapshot(cx);
20365
20366                        let excerpt = snapshot.excerpt_containing(
20367                            current_execution_position..current_execution_position,
20368                        )?;
20369
20370                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20371                    })?;
20372
20373                    let range =
20374                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20375
20376                    project.inline_values(buffer, range, cx)
20377                })
20378                .ok()
20379                .flatten()?
20380                .await
20381                .context("refreshing debugger inlays")
20382                .log_err()?;
20383
20384            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20385
20386            for (buffer_id, inline_value) in inline_values
20387                .into_iter()
20388                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20389            {
20390                buffer_inline_values
20391                    .entry(buffer_id)
20392                    .or_default()
20393                    .push(inline_value);
20394            }
20395
20396            editor
20397                .update(cx, |editor, cx| {
20398                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20399                    let mut new_inlays = Vec::default();
20400
20401                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20402                        let buffer_id = buffer_snapshot.remote_id();
20403                        buffer_inline_values
20404                            .get(&buffer_id)
20405                            .into_iter()
20406                            .flatten()
20407                            .for_each(|hint| {
20408                                let inlay = Inlay::debugger(
20409                                    post_inc(&mut editor.next_inlay_id),
20410                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20411                                    hint.text(),
20412                                );
20413                                if !inlay.text.chars().contains(&'\n') {
20414                                    new_inlays.push(inlay);
20415                                }
20416                            });
20417                    }
20418
20419                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20420                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20421
20422                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20423                })
20424                .ok()?;
20425            Some(())
20426        });
20427    }
20428
20429    fn on_buffer_event(
20430        &mut self,
20431        multibuffer: &Entity<MultiBuffer>,
20432        event: &multi_buffer::Event,
20433        window: &mut Window,
20434        cx: &mut Context<Self>,
20435    ) {
20436        match event {
20437            multi_buffer::Event::Edited {
20438                singleton_buffer_edited,
20439                edited_buffer,
20440            } => {
20441                self.scrollbar_marker_state.dirty = true;
20442                self.active_indent_guides_state.dirty = true;
20443                self.refresh_active_diagnostics(cx);
20444                self.refresh_code_actions(window, cx);
20445                self.refresh_selected_text_highlights(true, window, cx);
20446                self.refresh_single_line_folds(window, cx);
20447                refresh_matching_bracket_highlights(self, window, cx);
20448                if self.has_active_edit_prediction() {
20449                    self.update_visible_edit_prediction(window, cx);
20450                }
20451                if let Some(project) = self.project.as_ref()
20452                    && let Some(edited_buffer) = edited_buffer
20453                {
20454                    project.update(cx, |project, cx| {
20455                        self.registered_buffers
20456                            .entry(edited_buffer.read(cx).remote_id())
20457                            .or_insert_with(|| {
20458                                project.register_buffer_with_language_servers(edited_buffer, cx)
20459                            });
20460                    });
20461                }
20462                cx.emit(EditorEvent::BufferEdited);
20463                cx.emit(SearchEvent::MatchesInvalidated);
20464
20465                if let Some(buffer) = edited_buffer {
20466                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20467                }
20468
20469                if *singleton_buffer_edited {
20470                    if let Some(buffer) = edited_buffer
20471                        && buffer.read(cx).file().is_none()
20472                    {
20473                        cx.emit(EditorEvent::TitleChanged);
20474                    }
20475                    if let Some(project) = &self.project {
20476                        #[allow(clippy::mutable_key_type)]
20477                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20478                            multibuffer
20479                                .all_buffers()
20480                                .into_iter()
20481                                .filter_map(|buffer| {
20482                                    buffer.update(cx, |buffer, cx| {
20483                                        let language = buffer.language()?;
20484                                        let should_discard = project.update(cx, |project, cx| {
20485                                            project.is_local()
20486                                                && !project.has_language_servers_for(buffer, cx)
20487                                        });
20488                                        should_discard.not().then_some(language.clone())
20489                                    })
20490                                })
20491                                .collect::<HashSet<_>>()
20492                        });
20493                        if !languages_affected.is_empty() {
20494                            self.refresh_inlay_hints(
20495                                InlayHintRefreshReason::BufferEdited(languages_affected),
20496                                cx,
20497                            );
20498                        }
20499                    }
20500                }
20501
20502                let Some(project) = &self.project else { return };
20503                let (telemetry, is_via_ssh) = {
20504                    let project = project.read(cx);
20505                    let telemetry = project.client().telemetry().clone();
20506                    let is_via_ssh = project.is_via_remote_server();
20507                    (telemetry, is_via_ssh)
20508                };
20509                refresh_linked_ranges(self, window, cx);
20510                telemetry.log_edit_event("editor", is_via_ssh);
20511            }
20512            multi_buffer::Event::ExcerptsAdded {
20513                buffer,
20514                predecessor,
20515                excerpts,
20516            } => {
20517                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20518                let buffer_id = buffer.read(cx).remote_id();
20519                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20520                    && let Some(project) = &self.project
20521                {
20522                    update_uncommitted_diff_for_buffer(
20523                        cx.entity(),
20524                        project,
20525                        [buffer.clone()],
20526                        self.buffer.clone(),
20527                        cx,
20528                    )
20529                    .detach();
20530                }
20531                self.update_lsp_data(false, Some(buffer_id), window, cx);
20532                cx.emit(EditorEvent::ExcerptsAdded {
20533                    buffer: buffer.clone(),
20534                    predecessor: *predecessor,
20535                    excerpts: excerpts.clone(),
20536                });
20537                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20538            }
20539            multi_buffer::Event::ExcerptsRemoved {
20540                ids,
20541                removed_buffer_ids,
20542            } => {
20543                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20544                let buffer = self.buffer.read(cx);
20545                self.registered_buffers
20546                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20547                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20548                cx.emit(EditorEvent::ExcerptsRemoved {
20549                    ids: ids.clone(),
20550                    removed_buffer_ids: removed_buffer_ids.clone(),
20551                });
20552            }
20553            multi_buffer::Event::ExcerptsEdited {
20554                excerpt_ids,
20555                buffer_ids,
20556            } => {
20557                self.display_map.update(cx, |map, cx| {
20558                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20559                });
20560                cx.emit(EditorEvent::ExcerptsEdited {
20561                    ids: excerpt_ids.clone(),
20562                });
20563            }
20564            multi_buffer::Event::ExcerptsExpanded { ids } => {
20565                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20566                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20567            }
20568            multi_buffer::Event::Reparsed(buffer_id) => {
20569                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20570                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20571
20572                cx.emit(EditorEvent::Reparsed(*buffer_id));
20573            }
20574            multi_buffer::Event::DiffHunksToggled => {
20575                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20576            }
20577            multi_buffer::Event::LanguageChanged(buffer_id) => {
20578                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20579                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20580                cx.emit(EditorEvent::Reparsed(*buffer_id));
20581                cx.notify();
20582            }
20583            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20584            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20585            multi_buffer::Event::FileHandleChanged
20586            | multi_buffer::Event::Reloaded
20587            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20588            multi_buffer::Event::DiagnosticsUpdated => {
20589                self.update_diagnostics_state(window, cx);
20590            }
20591            _ => {}
20592        };
20593    }
20594
20595    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20596        if !self.diagnostics_enabled() {
20597            return;
20598        }
20599        self.refresh_active_diagnostics(cx);
20600        self.refresh_inline_diagnostics(true, window, cx);
20601        self.scrollbar_marker_state.dirty = true;
20602        cx.notify();
20603    }
20604
20605    pub fn start_temporary_diff_override(&mut self) {
20606        self.load_diff_task.take();
20607        self.temporary_diff_override = true;
20608    }
20609
20610    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20611        self.temporary_diff_override = false;
20612        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20613        self.buffer.update(cx, |buffer, cx| {
20614            buffer.set_all_diff_hunks_collapsed(cx);
20615        });
20616
20617        if let Some(project) = self.project.clone() {
20618            self.load_diff_task = Some(
20619                update_uncommitted_diff_for_buffer(
20620                    cx.entity(),
20621                    &project,
20622                    self.buffer.read(cx).all_buffers(),
20623                    self.buffer.clone(),
20624                    cx,
20625                )
20626                .shared(),
20627            );
20628        }
20629    }
20630
20631    fn on_display_map_changed(
20632        &mut self,
20633        _: Entity<DisplayMap>,
20634        _: &mut Window,
20635        cx: &mut Context<Self>,
20636    ) {
20637        cx.notify();
20638    }
20639
20640    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20641        if self.diagnostics_enabled() {
20642            let new_severity = EditorSettings::get_global(cx)
20643                .diagnostics_max_severity
20644                .unwrap_or(DiagnosticSeverity::Hint);
20645            self.set_max_diagnostics_severity(new_severity, cx);
20646        }
20647        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20648        self.update_edit_prediction_settings(cx);
20649        self.refresh_edit_prediction(true, false, window, cx);
20650        self.refresh_inline_values(cx);
20651        self.refresh_inlay_hints(
20652            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20653                self.selections.newest_anchor().head(),
20654                &self.buffer.read(cx).snapshot(cx),
20655                cx,
20656            )),
20657            cx,
20658        );
20659
20660        let old_cursor_shape = self.cursor_shape;
20661        let old_show_breadcrumbs = self.show_breadcrumbs;
20662
20663        {
20664            let editor_settings = EditorSettings::get_global(cx);
20665            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20666            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20667            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20668            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20669        }
20670
20671        if old_cursor_shape != self.cursor_shape {
20672            cx.emit(EditorEvent::CursorShapeChanged);
20673        }
20674
20675        if old_show_breadcrumbs != self.show_breadcrumbs {
20676            cx.emit(EditorEvent::BreadcrumbsChanged);
20677        }
20678
20679        let project_settings = ProjectSettings::get_global(cx);
20680        self.serialize_dirty_buffers =
20681            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20682
20683        if self.mode.is_full() {
20684            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20685            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20686            if self.show_inline_diagnostics != show_inline_diagnostics {
20687                self.show_inline_diagnostics = show_inline_diagnostics;
20688                self.refresh_inline_diagnostics(false, window, cx);
20689            }
20690
20691            if self.git_blame_inline_enabled != inline_blame_enabled {
20692                self.toggle_git_blame_inline_internal(false, window, cx);
20693            }
20694
20695            let minimap_settings = EditorSettings::get_global(cx).minimap;
20696            if self.minimap_visibility != MinimapVisibility::Disabled {
20697                if self.minimap_visibility.settings_visibility()
20698                    != minimap_settings.minimap_enabled()
20699                {
20700                    self.set_minimap_visibility(
20701                        MinimapVisibility::for_mode(self.mode(), cx),
20702                        window,
20703                        cx,
20704                    );
20705                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20706                    minimap_entity.update(cx, |minimap_editor, cx| {
20707                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20708                    })
20709                }
20710            }
20711        }
20712
20713        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20714            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20715        }) {
20716            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20717                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20718            }
20719            self.refresh_colors(false, None, window, cx);
20720        }
20721
20722        cx.notify();
20723    }
20724
20725    pub fn set_searchable(&mut self, searchable: bool) {
20726        self.searchable = searchable;
20727    }
20728
20729    pub fn searchable(&self) -> bool {
20730        self.searchable
20731    }
20732
20733    fn open_proposed_changes_editor(
20734        &mut self,
20735        _: &OpenProposedChangesEditor,
20736        window: &mut Window,
20737        cx: &mut Context<Self>,
20738    ) {
20739        let Some(workspace) = self.workspace() else {
20740            cx.propagate();
20741            return;
20742        };
20743
20744        let selections = self.selections.all::<usize>(cx);
20745        let multi_buffer = self.buffer.read(cx);
20746        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20747        let mut new_selections_by_buffer = HashMap::default();
20748        for selection in selections {
20749            for (buffer, range, _) in
20750                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20751            {
20752                let mut range = range.to_point(buffer);
20753                range.start.column = 0;
20754                range.end.column = buffer.line_len(range.end.row);
20755                new_selections_by_buffer
20756                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20757                    .or_insert(Vec::new())
20758                    .push(range)
20759            }
20760        }
20761
20762        let proposed_changes_buffers = new_selections_by_buffer
20763            .into_iter()
20764            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20765            .collect::<Vec<_>>();
20766        let proposed_changes_editor = cx.new(|cx| {
20767            ProposedChangesEditor::new(
20768                "Proposed changes",
20769                proposed_changes_buffers,
20770                self.project.clone(),
20771                window,
20772                cx,
20773            )
20774        });
20775
20776        window.defer(cx, move |window, cx| {
20777            workspace.update(cx, |workspace, cx| {
20778                workspace.active_pane().update(cx, |pane, cx| {
20779                    pane.add_item(
20780                        Box::new(proposed_changes_editor),
20781                        true,
20782                        true,
20783                        None,
20784                        window,
20785                        cx,
20786                    );
20787                });
20788            });
20789        });
20790    }
20791
20792    pub fn open_excerpts_in_split(
20793        &mut self,
20794        _: &OpenExcerptsSplit,
20795        window: &mut Window,
20796        cx: &mut Context<Self>,
20797    ) {
20798        self.open_excerpts_common(None, true, window, cx)
20799    }
20800
20801    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20802        self.open_excerpts_common(None, false, window, cx)
20803    }
20804
20805    fn open_excerpts_common(
20806        &mut self,
20807        jump_data: Option<JumpData>,
20808        split: bool,
20809        window: &mut Window,
20810        cx: &mut Context<Self>,
20811    ) {
20812        let Some(workspace) = self.workspace() else {
20813            cx.propagate();
20814            return;
20815        };
20816
20817        if self.buffer.read(cx).is_singleton() {
20818            cx.propagate();
20819            return;
20820        }
20821
20822        let mut new_selections_by_buffer = HashMap::default();
20823        match &jump_data {
20824            Some(JumpData::MultiBufferPoint {
20825                excerpt_id,
20826                position,
20827                anchor,
20828                line_offset_from_top,
20829            }) => {
20830                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20831                if let Some(buffer) = multi_buffer_snapshot
20832                    .buffer_id_for_excerpt(*excerpt_id)
20833                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20834                {
20835                    let buffer_snapshot = buffer.read(cx).snapshot();
20836                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20837                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20838                    } else {
20839                        buffer_snapshot.clip_point(*position, Bias::Left)
20840                    };
20841                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20842                    new_selections_by_buffer.insert(
20843                        buffer,
20844                        (
20845                            vec![jump_to_offset..jump_to_offset],
20846                            Some(*line_offset_from_top),
20847                        ),
20848                    );
20849                }
20850            }
20851            Some(JumpData::MultiBufferRow {
20852                row,
20853                line_offset_from_top,
20854            }) => {
20855                let point = MultiBufferPoint::new(row.0, 0);
20856                if let Some((buffer, buffer_point, _)) =
20857                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20858                {
20859                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20860                    new_selections_by_buffer
20861                        .entry(buffer)
20862                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20863                        .0
20864                        .push(buffer_offset..buffer_offset)
20865                }
20866            }
20867            None => {
20868                let selections = self.selections.all::<usize>(cx);
20869                let multi_buffer = self.buffer.read(cx);
20870                for selection in selections {
20871                    for (snapshot, range, _, anchor) in multi_buffer
20872                        .snapshot(cx)
20873                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20874                    {
20875                        if let Some(anchor) = anchor {
20876                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20877                            else {
20878                                continue;
20879                            };
20880                            let offset = text::ToOffset::to_offset(
20881                                &anchor.text_anchor,
20882                                &buffer_handle.read(cx).snapshot(),
20883                            );
20884                            let range = offset..offset;
20885                            new_selections_by_buffer
20886                                .entry(buffer_handle)
20887                                .or_insert((Vec::new(), None))
20888                                .0
20889                                .push(range)
20890                        } else {
20891                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20892                            else {
20893                                continue;
20894                            };
20895                            new_selections_by_buffer
20896                                .entry(buffer_handle)
20897                                .or_insert((Vec::new(), None))
20898                                .0
20899                                .push(range)
20900                        }
20901                    }
20902                }
20903            }
20904        }
20905
20906        new_selections_by_buffer
20907            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20908
20909        if new_selections_by_buffer.is_empty() {
20910            return;
20911        }
20912
20913        // We defer the pane interaction because we ourselves are a workspace item
20914        // and activating a new item causes the pane to call a method on us reentrantly,
20915        // which panics if we're on the stack.
20916        window.defer(cx, move |window, cx| {
20917            workspace.update(cx, |workspace, cx| {
20918                let pane = if split {
20919                    workspace.adjacent_pane(window, cx)
20920                } else {
20921                    workspace.active_pane().clone()
20922                };
20923
20924                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20925                    let editor = buffer
20926                        .read(cx)
20927                        .file()
20928                        .is_none()
20929                        .then(|| {
20930                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20931                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20932                            // Instead, we try to activate the existing editor in the pane first.
20933                            let (editor, pane_item_index) =
20934                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20935                                    let editor = item.downcast::<Editor>()?;
20936                                    let singleton_buffer =
20937                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20938                                    if singleton_buffer == buffer {
20939                                        Some((editor, i))
20940                                    } else {
20941                                        None
20942                                    }
20943                                })?;
20944                            pane.update(cx, |pane, cx| {
20945                                pane.activate_item(pane_item_index, true, true, window, cx)
20946                            });
20947                            Some(editor)
20948                        })
20949                        .flatten()
20950                        .unwrap_or_else(|| {
20951                            workspace.open_project_item::<Self>(
20952                                pane.clone(),
20953                                buffer,
20954                                true,
20955                                true,
20956                                window,
20957                                cx,
20958                            )
20959                        });
20960
20961                    editor.update(cx, |editor, cx| {
20962                        let autoscroll = match scroll_offset {
20963                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20964                            None => Autoscroll::newest(),
20965                        };
20966                        let nav_history = editor.nav_history.take();
20967                        editor.change_selections(
20968                            SelectionEffects::scroll(autoscroll),
20969                            window,
20970                            cx,
20971                            |s| {
20972                                s.select_ranges(ranges);
20973                            },
20974                        );
20975                        editor.nav_history = nav_history;
20976                    });
20977                }
20978            })
20979        });
20980    }
20981
20982    // For now, don't allow opening excerpts in buffers that aren't backed by
20983    // regular project files.
20984    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20985        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20986    }
20987
20988    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20989        let snapshot = self.buffer.read(cx).read(cx);
20990        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20991        Some(
20992            ranges
20993                .iter()
20994                .map(move |range| {
20995                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20996                })
20997                .collect(),
20998        )
20999    }
21000
21001    fn selection_replacement_ranges(
21002        &self,
21003        range: Range<OffsetUtf16>,
21004        cx: &mut App,
21005    ) -> Vec<Range<OffsetUtf16>> {
21006        let selections = self.selections.all::<OffsetUtf16>(cx);
21007        let newest_selection = selections
21008            .iter()
21009            .max_by_key(|selection| selection.id)
21010            .unwrap();
21011        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21012        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21013        let snapshot = self.buffer.read(cx).read(cx);
21014        selections
21015            .into_iter()
21016            .map(|mut selection| {
21017                selection.start.0 =
21018                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21019                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21020                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21021                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21022            })
21023            .collect()
21024    }
21025
21026    fn report_editor_event(
21027        &self,
21028        reported_event: ReportEditorEvent,
21029        file_extension: Option<String>,
21030        cx: &App,
21031    ) {
21032        if cfg!(any(test, feature = "test-support")) {
21033            return;
21034        }
21035
21036        let Some(project) = &self.project else { return };
21037
21038        // If None, we are in a file without an extension
21039        let file = self
21040            .buffer
21041            .read(cx)
21042            .as_singleton()
21043            .and_then(|b| b.read(cx).file());
21044        let file_extension = file_extension.or(file
21045            .as_ref()
21046            .and_then(|file| Path::new(file.file_name(cx)).extension())
21047            .and_then(|e| e.to_str())
21048            .map(|a| a.to_string()));
21049
21050        let vim_mode = vim_enabled(cx);
21051
21052        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21053        let copilot_enabled = edit_predictions_provider
21054            == language::language_settings::EditPredictionProvider::Copilot;
21055        let copilot_enabled_for_language = self
21056            .buffer
21057            .read(cx)
21058            .language_settings(cx)
21059            .show_edit_predictions;
21060
21061        let project = project.read(cx);
21062        let event_type = reported_event.event_type();
21063
21064        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21065            telemetry::event!(
21066                event_type,
21067                type = if auto_saved {"autosave"} else {"manual"},
21068                file_extension,
21069                vim_mode,
21070                copilot_enabled,
21071                copilot_enabled_for_language,
21072                edit_predictions_provider,
21073                is_via_ssh = project.is_via_remote_server(),
21074            );
21075        } else {
21076            telemetry::event!(
21077                event_type,
21078                file_extension,
21079                vim_mode,
21080                copilot_enabled,
21081                copilot_enabled_for_language,
21082                edit_predictions_provider,
21083                is_via_ssh = project.is_via_remote_server(),
21084            );
21085        };
21086    }
21087
21088    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21089    /// with each line being an array of {text, highlight} objects.
21090    fn copy_highlight_json(
21091        &mut self,
21092        _: &CopyHighlightJson,
21093        window: &mut Window,
21094        cx: &mut Context<Self>,
21095    ) {
21096        #[derive(Serialize)]
21097        struct Chunk<'a> {
21098            text: String,
21099            highlight: Option<&'a str>,
21100        }
21101
21102        let snapshot = self.buffer.read(cx).snapshot(cx);
21103        let range = self
21104            .selected_text_range(false, window, cx)
21105            .and_then(|selection| {
21106                if selection.range.is_empty() {
21107                    None
21108                } else {
21109                    Some(selection.range)
21110                }
21111            })
21112            .unwrap_or_else(|| 0..snapshot.len());
21113
21114        let chunks = snapshot.chunks(range, true);
21115        let mut lines = Vec::new();
21116        let mut line: VecDeque<Chunk> = VecDeque::new();
21117
21118        let Some(style) = self.style.as_ref() else {
21119            return;
21120        };
21121
21122        for chunk in chunks {
21123            let highlight = chunk
21124                .syntax_highlight_id
21125                .and_then(|id| id.name(&style.syntax));
21126            let mut chunk_lines = chunk.text.split('\n').peekable();
21127            while let Some(text) = chunk_lines.next() {
21128                let mut merged_with_last_token = false;
21129                if let Some(last_token) = line.back_mut()
21130                    && last_token.highlight == highlight
21131                {
21132                    last_token.text.push_str(text);
21133                    merged_with_last_token = true;
21134                }
21135
21136                if !merged_with_last_token {
21137                    line.push_back(Chunk {
21138                        text: text.into(),
21139                        highlight,
21140                    });
21141                }
21142
21143                if chunk_lines.peek().is_some() {
21144                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21145                        line.pop_front();
21146                    }
21147                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21148                        line.pop_back();
21149                    }
21150
21151                    lines.push(mem::take(&mut line));
21152                }
21153            }
21154        }
21155
21156        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21157            return;
21158        };
21159        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21160    }
21161
21162    pub fn open_context_menu(
21163        &mut self,
21164        _: &OpenContextMenu,
21165        window: &mut Window,
21166        cx: &mut Context<Self>,
21167    ) {
21168        self.request_autoscroll(Autoscroll::newest(), cx);
21169        let position = self.selections.newest_display(cx).start;
21170        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21171    }
21172
21173    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21174        &self.inlay_hint_cache
21175    }
21176
21177    pub fn replay_insert_event(
21178        &mut self,
21179        text: &str,
21180        relative_utf16_range: Option<Range<isize>>,
21181        window: &mut Window,
21182        cx: &mut Context<Self>,
21183    ) {
21184        if !self.input_enabled {
21185            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21186            return;
21187        }
21188        if let Some(relative_utf16_range) = relative_utf16_range {
21189            let selections = self.selections.all::<OffsetUtf16>(cx);
21190            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21191                let new_ranges = selections.into_iter().map(|range| {
21192                    let start = OffsetUtf16(
21193                        range
21194                            .head()
21195                            .0
21196                            .saturating_add_signed(relative_utf16_range.start),
21197                    );
21198                    let end = OffsetUtf16(
21199                        range
21200                            .head()
21201                            .0
21202                            .saturating_add_signed(relative_utf16_range.end),
21203                    );
21204                    start..end
21205                });
21206                s.select_ranges(new_ranges);
21207            });
21208        }
21209
21210        self.handle_input(text, window, cx);
21211    }
21212
21213    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21214        let Some(provider) = self.semantics_provider.as_ref() else {
21215            return false;
21216        };
21217
21218        let mut supports = false;
21219        self.buffer().update(cx, |this, cx| {
21220            this.for_each_buffer(|buffer| {
21221                supports |= provider.supports_inlay_hints(buffer, cx);
21222            });
21223        });
21224
21225        supports
21226    }
21227
21228    pub fn is_focused(&self, window: &Window) -> bool {
21229        self.focus_handle.is_focused(window)
21230    }
21231
21232    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21233        cx.emit(EditorEvent::Focused);
21234
21235        if let Some(descendant) = self
21236            .last_focused_descendant
21237            .take()
21238            .and_then(|descendant| descendant.upgrade())
21239        {
21240            window.focus(&descendant);
21241        } else {
21242            if let Some(blame) = self.blame.as_ref() {
21243                blame.update(cx, GitBlame::focus)
21244            }
21245
21246            self.blink_manager.update(cx, BlinkManager::enable);
21247            self.show_cursor_names(window, cx);
21248            self.buffer.update(cx, |buffer, cx| {
21249                buffer.finalize_last_transaction(cx);
21250                if self.leader_id.is_none() {
21251                    buffer.set_active_selections(
21252                        &self.selections.disjoint_anchors(),
21253                        self.selections.line_mode,
21254                        self.cursor_shape,
21255                        cx,
21256                    );
21257                }
21258            });
21259        }
21260    }
21261
21262    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21263        cx.emit(EditorEvent::FocusedIn)
21264    }
21265
21266    fn handle_focus_out(
21267        &mut self,
21268        event: FocusOutEvent,
21269        _window: &mut Window,
21270        cx: &mut Context<Self>,
21271    ) {
21272        if event.blurred != self.focus_handle {
21273            self.last_focused_descendant = Some(event.blurred);
21274        }
21275        self.selection_drag_state = SelectionDragState::None;
21276        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21277    }
21278
21279    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21280        self.blink_manager.update(cx, BlinkManager::disable);
21281        self.buffer
21282            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21283
21284        if let Some(blame) = self.blame.as_ref() {
21285            blame.update(cx, GitBlame::blur)
21286        }
21287        if !self.hover_state.focused(window, cx) {
21288            hide_hover(self, cx);
21289        }
21290        if !self
21291            .context_menu
21292            .borrow()
21293            .as_ref()
21294            .is_some_and(|context_menu| context_menu.focused(window, cx))
21295        {
21296            self.hide_context_menu(window, cx);
21297        }
21298        self.discard_edit_prediction(false, cx);
21299        cx.emit(EditorEvent::Blurred);
21300        cx.notify();
21301    }
21302
21303    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21304        let mut pending: String = window
21305            .pending_input_keystrokes()
21306            .into_iter()
21307            .flatten()
21308            .filter_map(|keystroke| {
21309                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21310                    keystroke.key_char.clone()
21311                } else {
21312                    None
21313                }
21314            })
21315            .collect();
21316
21317        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21318            pending = "".to_string();
21319        }
21320
21321        let existing_pending = self
21322            .text_highlights::<PendingInput>(cx)
21323            .map(|(_, ranges)| ranges.to_vec());
21324        if existing_pending.is_none() && pending.is_empty() {
21325            return;
21326        }
21327        let transaction =
21328            self.transact(window, cx, |this, window, cx| {
21329                let selections = this.selections.all::<usize>(cx);
21330                let edits = selections
21331                    .iter()
21332                    .map(|selection| (selection.end..selection.end, pending.clone()));
21333                this.edit(edits, cx);
21334                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21335                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21336                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21337                    }));
21338                });
21339                if let Some(existing_ranges) = existing_pending {
21340                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21341                    this.edit(edits, cx);
21342                }
21343            });
21344
21345        let snapshot = self.snapshot(window, cx);
21346        let ranges = self
21347            .selections
21348            .all::<usize>(cx)
21349            .into_iter()
21350            .map(|selection| {
21351                snapshot.buffer_snapshot.anchor_after(selection.end)
21352                    ..snapshot
21353                        .buffer_snapshot
21354                        .anchor_before(selection.end + pending.len())
21355            })
21356            .collect();
21357
21358        if pending.is_empty() {
21359            self.clear_highlights::<PendingInput>(cx);
21360        } else {
21361            self.highlight_text::<PendingInput>(
21362                ranges,
21363                HighlightStyle {
21364                    underline: Some(UnderlineStyle {
21365                        thickness: px(1.),
21366                        color: None,
21367                        wavy: false,
21368                    }),
21369                    ..Default::default()
21370                },
21371                cx,
21372            );
21373        }
21374
21375        self.ime_transaction = self.ime_transaction.or(transaction);
21376        if let Some(transaction) = self.ime_transaction {
21377            self.buffer.update(cx, |buffer, cx| {
21378                buffer.group_until_transaction(transaction, cx);
21379            });
21380        }
21381
21382        if self.text_highlights::<PendingInput>(cx).is_none() {
21383            self.ime_transaction.take();
21384        }
21385    }
21386
21387    pub fn register_action_renderer(
21388        &mut self,
21389        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21390    ) -> Subscription {
21391        let id = self.next_editor_action_id.post_inc();
21392        self.editor_actions
21393            .borrow_mut()
21394            .insert(id, Box::new(listener));
21395
21396        let editor_actions = self.editor_actions.clone();
21397        Subscription::new(move || {
21398            editor_actions.borrow_mut().remove(&id);
21399        })
21400    }
21401
21402    pub fn register_action<A: Action>(
21403        &mut self,
21404        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21405    ) -> Subscription {
21406        let id = self.next_editor_action_id.post_inc();
21407        let listener = Arc::new(listener);
21408        self.editor_actions.borrow_mut().insert(
21409            id,
21410            Box::new(move |_, window, _| {
21411                let listener = listener.clone();
21412                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21413                    let action = action.downcast_ref().unwrap();
21414                    if phase == DispatchPhase::Bubble {
21415                        listener(action, window, cx)
21416                    }
21417                })
21418            }),
21419        );
21420
21421        let editor_actions = self.editor_actions.clone();
21422        Subscription::new(move || {
21423            editor_actions.borrow_mut().remove(&id);
21424        })
21425    }
21426
21427    pub fn file_header_size(&self) -> u32 {
21428        FILE_HEADER_HEIGHT
21429    }
21430
21431    pub fn restore(
21432        &mut self,
21433        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21434        window: &mut Window,
21435        cx: &mut Context<Self>,
21436    ) {
21437        let workspace = self.workspace();
21438        let project = self.project();
21439        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21440            let mut tasks = Vec::new();
21441            for (buffer_id, changes) in revert_changes {
21442                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21443                    buffer.update(cx, |buffer, cx| {
21444                        buffer.edit(
21445                            changes
21446                                .into_iter()
21447                                .map(|(range, text)| (range, text.to_string())),
21448                            None,
21449                            cx,
21450                        );
21451                    });
21452
21453                    if let Some(project) =
21454                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21455                    {
21456                        project.update(cx, |project, cx| {
21457                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21458                        })
21459                    }
21460                }
21461            }
21462            tasks
21463        });
21464        cx.spawn_in(window, async move |_, cx| {
21465            for (buffer, task) in save_tasks {
21466                let result = task.await;
21467                if result.is_err() {
21468                    let Some(path) = buffer
21469                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21470                        .ok()
21471                    else {
21472                        continue;
21473                    };
21474                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21475                        let Some(task) = cx
21476                            .update_window_entity(workspace, |workspace, window, cx| {
21477                                workspace
21478                                    .open_path_preview(path, None, false, false, false, window, cx)
21479                            })
21480                            .ok()
21481                        else {
21482                            continue;
21483                        };
21484                        task.await.log_err();
21485                    }
21486                }
21487            }
21488        })
21489        .detach();
21490        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21491            selections.refresh()
21492        });
21493    }
21494
21495    pub fn to_pixel_point(
21496        &self,
21497        source: multi_buffer::Anchor,
21498        editor_snapshot: &EditorSnapshot,
21499        window: &mut Window,
21500    ) -> Option<gpui::Point<Pixels>> {
21501        let source_point = source.to_display_point(editor_snapshot);
21502        self.display_to_pixel_point(source_point, editor_snapshot, window)
21503    }
21504
21505    pub fn display_to_pixel_point(
21506        &self,
21507        source: DisplayPoint,
21508        editor_snapshot: &EditorSnapshot,
21509        window: &mut Window,
21510    ) -> Option<gpui::Point<Pixels>> {
21511        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21512        let text_layout_details = self.text_layout_details(window);
21513        let scroll_top = text_layout_details
21514            .scroll_anchor
21515            .scroll_position(editor_snapshot)
21516            .y;
21517
21518        if source.row().as_f32() < scroll_top.floor() {
21519            return None;
21520        }
21521        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21522        let source_y = line_height * (source.row().as_f32() - scroll_top);
21523        Some(gpui::Point::new(source_x, source_y))
21524    }
21525
21526    pub fn has_visible_completions_menu(&self) -> bool {
21527        !self.edit_prediction_preview_is_active()
21528            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21529                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21530            })
21531    }
21532
21533    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21534        if self.mode.is_minimap() {
21535            return;
21536        }
21537        self.addons
21538            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21539    }
21540
21541    pub fn unregister_addon<T: Addon>(&mut self) {
21542        self.addons.remove(&std::any::TypeId::of::<T>());
21543    }
21544
21545    pub fn addon<T: Addon>(&self) -> Option<&T> {
21546        let type_id = std::any::TypeId::of::<T>();
21547        self.addons
21548            .get(&type_id)
21549            .and_then(|item| item.to_any().downcast_ref::<T>())
21550    }
21551
21552    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21553        let type_id = std::any::TypeId::of::<T>();
21554        self.addons
21555            .get_mut(&type_id)
21556            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21557    }
21558
21559    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21560        let text_layout_details = self.text_layout_details(window);
21561        let style = &text_layout_details.editor_style;
21562        let font_id = window.text_system().resolve_font(&style.text.font());
21563        let font_size = style.text.font_size.to_pixels(window.rem_size());
21564        let line_height = style.text.line_height_in_pixels(window.rem_size());
21565        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21566        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21567
21568        CharacterDimensions {
21569            em_width,
21570            em_advance,
21571            line_height,
21572        }
21573    }
21574
21575    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21576        self.load_diff_task.clone()
21577    }
21578
21579    fn read_metadata_from_db(
21580        &mut self,
21581        item_id: u64,
21582        workspace_id: WorkspaceId,
21583        window: &mut Window,
21584        cx: &mut Context<Editor>,
21585    ) {
21586        if self.is_singleton(cx)
21587            && !self.mode.is_minimap()
21588            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21589        {
21590            let buffer_snapshot = OnceCell::new();
21591
21592            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21593                && !folds.is_empty()
21594            {
21595                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21596                self.fold_ranges(
21597                    folds
21598                        .into_iter()
21599                        .map(|(start, end)| {
21600                            snapshot.clip_offset(start, Bias::Left)
21601                                ..snapshot.clip_offset(end, Bias::Right)
21602                        })
21603                        .collect(),
21604                    false,
21605                    window,
21606                    cx,
21607                );
21608            }
21609
21610            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21611                && !selections.is_empty()
21612            {
21613                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21614                // skip adding the initial selection to selection history
21615                self.selection_history.mode = SelectionHistoryMode::Skipping;
21616                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21617                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21618                        snapshot.clip_offset(start, Bias::Left)
21619                            ..snapshot.clip_offset(end, Bias::Right)
21620                    }));
21621                });
21622                self.selection_history.mode = SelectionHistoryMode::Normal;
21623            };
21624        }
21625
21626        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21627    }
21628
21629    fn update_lsp_data(
21630        &mut self,
21631        ignore_cache: bool,
21632        for_buffer: Option<BufferId>,
21633        window: &mut Window,
21634        cx: &mut Context<'_, Self>,
21635    ) {
21636        self.pull_diagnostics(for_buffer, window, cx);
21637        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21638    }
21639}
21640
21641fn vim_enabled(cx: &App) -> bool {
21642    cx.global::<SettingsStore>()
21643        .raw_user_settings()
21644        .get("vim_mode")
21645        == Some(&serde_json::Value::Bool(true))
21646}
21647
21648fn process_completion_for_edit(
21649    completion: &Completion,
21650    intent: CompletionIntent,
21651    buffer: &Entity<Buffer>,
21652    cursor_position: &text::Anchor,
21653    cx: &mut Context<Editor>,
21654) -> CompletionEdit {
21655    let buffer = buffer.read(cx);
21656    let buffer_snapshot = buffer.snapshot();
21657    let (snippet, new_text) = if completion.is_snippet() {
21658        // Workaround for typescript language server issues so that methods don't expand within
21659        // strings and functions with type expressions. The previous point is used because the query
21660        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21661        let mut snippet_source = completion.new_text.clone();
21662        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21663        previous_point.column = previous_point.column.saturating_sub(1);
21664        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21665            && scope.prefers_label_for_snippet_in_completion()
21666            && let Some(label) = completion.label()
21667            && matches!(
21668                completion.kind(),
21669                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21670            )
21671        {
21672            snippet_source = label;
21673        }
21674        match Snippet::parse(&snippet_source).log_err() {
21675            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21676            None => (None, completion.new_text.clone()),
21677        }
21678    } else {
21679        (None, completion.new_text.clone())
21680    };
21681
21682    let mut range_to_replace = {
21683        let replace_range = &completion.replace_range;
21684        if let CompletionSource::Lsp {
21685            insert_range: Some(insert_range),
21686            ..
21687        } = &completion.source
21688        {
21689            debug_assert_eq!(
21690                insert_range.start, replace_range.start,
21691                "insert_range and replace_range should start at the same position"
21692            );
21693            debug_assert!(
21694                insert_range
21695                    .start
21696                    .cmp(cursor_position, &buffer_snapshot)
21697                    .is_le(),
21698                "insert_range should start before or at cursor position"
21699            );
21700            debug_assert!(
21701                replace_range
21702                    .start
21703                    .cmp(cursor_position, &buffer_snapshot)
21704                    .is_le(),
21705                "replace_range should start before or at cursor position"
21706            );
21707
21708            let should_replace = match intent {
21709                CompletionIntent::CompleteWithInsert => false,
21710                CompletionIntent::CompleteWithReplace => true,
21711                CompletionIntent::Complete | CompletionIntent::Compose => {
21712                    let insert_mode =
21713                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21714                            .completions
21715                            .lsp_insert_mode;
21716                    match insert_mode {
21717                        LspInsertMode::Insert => false,
21718                        LspInsertMode::Replace => true,
21719                        LspInsertMode::ReplaceSubsequence => {
21720                            let mut text_to_replace = buffer.chars_for_range(
21721                                buffer.anchor_before(replace_range.start)
21722                                    ..buffer.anchor_after(replace_range.end),
21723                            );
21724                            let mut current_needle = text_to_replace.next();
21725                            for haystack_ch in completion.label.text.chars() {
21726                                if let Some(needle_ch) = current_needle
21727                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21728                                {
21729                                    current_needle = text_to_replace.next();
21730                                }
21731                            }
21732                            current_needle.is_none()
21733                        }
21734                        LspInsertMode::ReplaceSuffix => {
21735                            if replace_range
21736                                .end
21737                                .cmp(cursor_position, &buffer_snapshot)
21738                                .is_gt()
21739                            {
21740                                let range_after_cursor = *cursor_position..replace_range.end;
21741                                let text_after_cursor = buffer
21742                                    .text_for_range(
21743                                        buffer.anchor_before(range_after_cursor.start)
21744                                            ..buffer.anchor_after(range_after_cursor.end),
21745                                    )
21746                                    .collect::<String>()
21747                                    .to_ascii_lowercase();
21748                                completion
21749                                    .label
21750                                    .text
21751                                    .to_ascii_lowercase()
21752                                    .ends_with(&text_after_cursor)
21753                            } else {
21754                                true
21755                            }
21756                        }
21757                    }
21758                }
21759            };
21760
21761            if should_replace {
21762                replace_range.clone()
21763            } else {
21764                insert_range.clone()
21765            }
21766        } else {
21767            replace_range.clone()
21768        }
21769    };
21770
21771    if range_to_replace
21772        .end
21773        .cmp(cursor_position, &buffer_snapshot)
21774        .is_lt()
21775    {
21776        range_to_replace.end = *cursor_position;
21777    }
21778
21779    CompletionEdit {
21780        new_text,
21781        replace_range: range_to_replace.to_offset(buffer),
21782        snippet,
21783    }
21784}
21785
21786struct CompletionEdit {
21787    new_text: String,
21788    replace_range: Range<usize>,
21789    snippet: Option<Snippet>,
21790}
21791
21792fn insert_extra_newline_brackets(
21793    buffer: &MultiBufferSnapshot,
21794    range: Range<usize>,
21795    language: &language::LanguageScope,
21796) -> bool {
21797    let leading_whitespace_len = buffer
21798        .reversed_chars_at(range.start)
21799        .take_while(|c| c.is_whitespace() && *c != '\n')
21800        .map(|c| c.len_utf8())
21801        .sum::<usize>();
21802    let trailing_whitespace_len = buffer
21803        .chars_at(range.end)
21804        .take_while(|c| c.is_whitespace() && *c != '\n')
21805        .map(|c| c.len_utf8())
21806        .sum::<usize>();
21807    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21808
21809    language.brackets().any(|(pair, enabled)| {
21810        let pair_start = pair.start.trim_end();
21811        let pair_end = pair.end.trim_start();
21812
21813        enabled
21814            && pair.newline
21815            && buffer.contains_str_at(range.end, pair_end)
21816            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21817    })
21818}
21819
21820fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21821    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21822        [(buffer, range, _)] => (*buffer, range.clone()),
21823        _ => return false,
21824    };
21825    let pair = {
21826        let mut result: Option<BracketMatch> = None;
21827
21828        for pair in buffer
21829            .all_bracket_ranges(range.clone())
21830            .filter(move |pair| {
21831                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21832            })
21833        {
21834            let len = pair.close_range.end - pair.open_range.start;
21835
21836            if let Some(existing) = &result {
21837                let existing_len = existing.close_range.end - existing.open_range.start;
21838                if len > existing_len {
21839                    continue;
21840                }
21841            }
21842
21843            result = Some(pair);
21844        }
21845
21846        result
21847    };
21848    let Some(pair) = pair else {
21849        return false;
21850    };
21851    pair.newline_only
21852        && buffer
21853            .chars_for_range(pair.open_range.end..range.start)
21854            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21855            .all(|c| c.is_whitespace() && c != '\n')
21856}
21857
21858fn update_uncommitted_diff_for_buffer(
21859    editor: Entity<Editor>,
21860    project: &Entity<Project>,
21861    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21862    buffer: Entity<MultiBuffer>,
21863    cx: &mut App,
21864) -> Task<()> {
21865    let mut tasks = Vec::new();
21866    project.update(cx, |project, cx| {
21867        for buffer in buffers {
21868            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21869                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21870            }
21871        }
21872    });
21873    cx.spawn(async move |cx| {
21874        let diffs = future::join_all(tasks).await;
21875        if editor
21876            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21877            .unwrap_or(false)
21878        {
21879            return;
21880        }
21881
21882        buffer
21883            .update(cx, |buffer, cx| {
21884                for diff in diffs.into_iter().flatten() {
21885                    buffer.add_diff(diff, cx);
21886                }
21887            })
21888            .ok();
21889    })
21890}
21891
21892fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21893    let tab_size = tab_size.get() as usize;
21894    let mut width = offset;
21895
21896    for ch in text.chars() {
21897        width += if ch == '\t' {
21898            tab_size - (width % tab_size)
21899        } else {
21900            1
21901        };
21902    }
21903
21904    width - offset
21905}
21906
21907#[cfg(test)]
21908mod tests {
21909    use super::*;
21910
21911    #[test]
21912    fn test_string_size_with_expanded_tabs() {
21913        let nz = |val| NonZeroU32::new(val).unwrap();
21914        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21915        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21916        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21917        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21918        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21919        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21920        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21921        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21922    }
21923}
21924
21925/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21926struct WordBreakingTokenizer<'a> {
21927    input: &'a str,
21928}
21929
21930impl<'a> WordBreakingTokenizer<'a> {
21931    fn new(input: &'a str) -> Self {
21932        Self { input }
21933    }
21934}
21935
21936fn is_char_ideographic(ch: char) -> bool {
21937    use unicode_script::Script::*;
21938    use unicode_script::UnicodeScript;
21939    matches!(ch.script(), Han | Tangut | Yi)
21940}
21941
21942fn is_grapheme_ideographic(text: &str) -> bool {
21943    text.chars().any(is_char_ideographic)
21944}
21945
21946fn is_grapheme_whitespace(text: &str) -> bool {
21947    text.chars().any(|x| x.is_whitespace())
21948}
21949
21950fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21951    text.chars()
21952        .next()
21953        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21954}
21955
21956#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21957enum WordBreakToken<'a> {
21958    Word { token: &'a str, grapheme_len: usize },
21959    InlineWhitespace { token: &'a str, grapheme_len: usize },
21960    Newline,
21961}
21962
21963impl<'a> Iterator for WordBreakingTokenizer<'a> {
21964    /// Yields a span, the count of graphemes in the token, and whether it was
21965    /// whitespace. Note that it also breaks at word boundaries.
21966    type Item = WordBreakToken<'a>;
21967
21968    fn next(&mut self) -> Option<Self::Item> {
21969        use unicode_segmentation::UnicodeSegmentation;
21970        if self.input.is_empty() {
21971            return None;
21972        }
21973
21974        let mut iter = self.input.graphemes(true).peekable();
21975        let mut offset = 0;
21976        let mut grapheme_len = 0;
21977        if let Some(first_grapheme) = iter.next() {
21978            let is_newline = first_grapheme == "\n";
21979            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21980            offset += first_grapheme.len();
21981            grapheme_len += 1;
21982            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21983                if let Some(grapheme) = iter.peek().copied()
21984                    && should_stay_with_preceding_ideograph(grapheme)
21985                {
21986                    offset += grapheme.len();
21987                    grapheme_len += 1;
21988                }
21989            } else {
21990                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21991                let mut next_word_bound = words.peek().copied();
21992                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21993                    next_word_bound = words.next();
21994                }
21995                while let Some(grapheme) = iter.peek().copied() {
21996                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21997                        break;
21998                    };
21999                    if is_grapheme_whitespace(grapheme) != is_whitespace
22000                        || (grapheme == "\n") != is_newline
22001                    {
22002                        break;
22003                    };
22004                    offset += grapheme.len();
22005                    grapheme_len += 1;
22006                    iter.next();
22007                }
22008            }
22009            let token = &self.input[..offset];
22010            self.input = &self.input[offset..];
22011            if token == "\n" {
22012                Some(WordBreakToken::Newline)
22013            } else if is_whitespace {
22014                Some(WordBreakToken::InlineWhitespace {
22015                    token,
22016                    grapheme_len,
22017                })
22018            } else {
22019                Some(WordBreakToken::Word {
22020                    token,
22021                    grapheme_len,
22022                })
22023            }
22024        } else {
22025            None
22026        }
22027    }
22028}
22029
22030#[test]
22031fn test_word_breaking_tokenizer() {
22032    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22033        ("", &[]),
22034        ("  ", &[whitespace("  ", 2)]),
22035        ("Ʒ", &[word("Ʒ", 1)]),
22036        ("Ǽ", &[word("Ǽ", 1)]),
22037        ("", &[word("", 1)]),
22038        ("⋑⋑", &[word("⋑⋑", 2)]),
22039        (
22040            "原理,进而",
22041            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22042        ),
22043        (
22044            "hello world",
22045            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22046        ),
22047        (
22048            "hello, world",
22049            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22050        ),
22051        (
22052            "  hello world",
22053            &[
22054                whitespace("  ", 2),
22055                word("hello", 5),
22056                whitespace(" ", 1),
22057                word("world", 5),
22058            ],
22059        ),
22060        (
22061            "这是什么 \n 钢笔",
22062            &[
22063                word("", 1),
22064                word("", 1),
22065                word("", 1),
22066                word("", 1),
22067                whitespace(" ", 1),
22068                newline(),
22069                whitespace(" ", 1),
22070                word("", 1),
22071                word("", 1),
22072            ],
22073        ),
22074        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22075    ];
22076
22077    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22078        WordBreakToken::Word {
22079            token,
22080            grapheme_len,
22081        }
22082    }
22083
22084    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22085        WordBreakToken::InlineWhitespace {
22086            token,
22087            grapheme_len,
22088        }
22089    }
22090
22091    fn newline() -> WordBreakToken<'static> {
22092        WordBreakToken::Newline
22093    }
22094
22095    for (input, result) in tests {
22096        assert_eq!(
22097            WordBreakingTokenizer::new(input)
22098                .collect::<Vec<_>>()
22099                .as_slice(),
22100            *result,
22101        );
22102    }
22103}
22104
22105fn wrap_with_prefix(
22106    first_line_prefix: String,
22107    subsequent_lines_prefix: String,
22108    unwrapped_text: String,
22109    wrap_column: usize,
22110    tab_size: NonZeroU32,
22111    preserve_existing_whitespace: bool,
22112) -> String {
22113    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22114    let subsequent_lines_prefix_len =
22115        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22116    let mut wrapped_text = String::new();
22117    let mut current_line = first_line_prefix;
22118    let mut is_first_line = true;
22119
22120    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22121    let mut current_line_len = first_line_prefix_len;
22122    let mut in_whitespace = false;
22123    for token in tokenizer {
22124        let have_preceding_whitespace = in_whitespace;
22125        match token {
22126            WordBreakToken::Word {
22127                token,
22128                grapheme_len,
22129            } => {
22130                in_whitespace = false;
22131                let current_prefix_len = if is_first_line {
22132                    first_line_prefix_len
22133                } else {
22134                    subsequent_lines_prefix_len
22135                };
22136                if current_line_len + grapheme_len > wrap_column
22137                    && current_line_len != current_prefix_len
22138                {
22139                    wrapped_text.push_str(current_line.trim_end());
22140                    wrapped_text.push('\n');
22141                    is_first_line = false;
22142                    current_line = subsequent_lines_prefix.clone();
22143                    current_line_len = subsequent_lines_prefix_len;
22144                }
22145                current_line.push_str(token);
22146                current_line_len += grapheme_len;
22147            }
22148            WordBreakToken::InlineWhitespace {
22149                mut token,
22150                mut grapheme_len,
22151            } => {
22152                in_whitespace = true;
22153                if have_preceding_whitespace && !preserve_existing_whitespace {
22154                    continue;
22155                }
22156                if !preserve_existing_whitespace {
22157                    token = " ";
22158                    grapheme_len = 1;
22159                }
22160                let current_prefix_len = if is_first_line {
22161                    first_line_prefix_len
22162                } else {
22163                    subsequent_lines_prefix_len
22164                };
22165                if current_line_len + grapheme_len > wrap_column {
22166                    wrapped_text.push_str(current_line.trim_end());
22167                    wrapped_text.push('\n');
22168                    is_first_line = false;
22169                    current_line = subsequent_lines_prefix.clone();
22170                    current_line_len = subsequent_lines_prefix_len;
22171                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22172                    current_line.push_str(token);
22173                    current_line_len += grapheme_len;
22174                }
22175            }
22176            WordBreakToken::Newline => {
22177                in_whitespace = true;
22178                let current_prefix_len = if is_first_line {
22179                    first_line_prefix_len
22180                } else {
22181                    subsequent_lines_prefix_len
22182                };
22183                if preserve_existing_whitespace {
22184                    wrapped_text.push_str(current_line.trim_end());
22185                    wrapped_text.push('\n');
22186                    is_first_line = false;
22187                    current_line = subsequent_lines_prefix.clone();
22188                    current_line_len = subsequent_lines_prefix_len;
22189                } else if have_preceding_whitespace {
22190                    continue;
22191                } else if current_line_len + 1 > wrap_column
22192                    && current_line_len != current_prefix_len
22193                {
22194                    wrapped_text.push_str(current_line.trim_end());
22195                    wrapped_text.push('\n');
22196                    is_first_line = false;
22197                    current_line = subsequent_lines_prefix.clone();
22198                    current_line_len = subsequent_lines_prefix_len;
22199                } else if current_line_len != current_prefix_len {
22200                    current_line.push(' ');
22201                    current_line_len += 1;
22202                }
22203            }
22204        }
22205    }
22206
22207    if !current_line.is_empty() {
22208        wrapped_text.push_str(&current_line);
22209    }
22210    wrapped_text
22211}
22212
22213#[test]
22214fn test_wrap_with_prefix() {
22215    assert_eq!(
22216        wrap_with_prefix(
22217            "# ".to_string(),
22218            "# ".to_string(),
22219            "abcdefg".to_string(),
22220            4,
22221            NonZeroU32::new(4).unwrap(),
22222            false,
22223        ),
22224        "# abcdefg"
22225    );
22226    assert_eq!(
22227        wrap_with_prefix(
22228            "".to_string(),
22229            "".to_string(),
22230            "\thello world".to_string(),
22231            8,
22232            NonZeroU32::new(4).unwrap(),
22233            false,
22234        ),
22235        "hello\nworld"
22236    );
22237    assert_eq!(
22238        wrap_with_prefix(
22239            "// ".to_string(),
22240            "// ".to_string(),
22241            "xx \nyy zz aa bb cc".to_string(),
22242            12,
22243            NonZeroU32::new(4).unwrap(),
22244            false,
22245        ),
22246        "// xx yy zz\n// aa bb cc"
22247    );
22248    assert_eq!(
22249        wrap_with_prefix(
22250            String::new(),
22251            String::new(),
22252            "这是什么 \n 钢笔".to_string(),
22253            3,
22254            NonZeroU32::new(4).unwrap(),
22255            false,
22256        ),
22257        "这是什\n么 钢\n"
22258    );
22259}
22260
22261pub trait CollaborationHub {
22262    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22263    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22264    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22265}
22266
22267impl CollaborationHub for Entity<Project> {
22268    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22269        self.read(cx).collaborators()
22270    }
22271
22272    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22273        self.read(cx).user_store().read(cx).participant_indices()
22274    }
22275
22276    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22277        let this = self.read(cx);
22278        let user_ids = this.collaborators().values().map(|c| c.user_id);
22279        this.user_store().read(cx).participant_names(user_ids, cx)
22280    }
22281}
22282
22283pub trait SemanticsProvider {
22284    fn hover(
22285        &self,
22286        buffer: &Entity<Buffer>,
22287        position: text::Anchor,
22288        cx: &mut App,
22289    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22290
22291    fn inline_values(
22292        &self,
22293        buffer_handle: Entity<Buffer>,
22294        range: Range<text::Anchor>,
22295        cx: &mut App,
22296    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22297
22298    fn inlay_hints(
22299        &self,
22300        buffer_handle: Entity<Buffer>,
22301        range: Range<text::Anchor>,
22302        cx: &mut App,
22303    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22304
22305    fn resolve_inlay_hint(
22306        &self,
22307        hint: InlayHint,
22308        buffer_handle: Entity<Buffer>,
22309        server_id: LanguageServerId,
22310        cx: &mut App,
22311    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22312
22313    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22314
22315    fn document_highlights(
22316        &self,
22317        buffer: &Entity<Buffer>,
22318        position: text::Anchor,
22319        cx: &mut App,
22320    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22321
22322    fn definitions(
22323        &self,
22324        buffer: &Entity<Buffer>,
22325        position: text::Anchor,
22326        kind: GotoDefinitionKind,
22327        cx: &mut App,
22328    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22329
22330    fn range_for_rename(
22331        &self,
22332        buffer: &Entity<Buffer>,
22333        position: text::Anchor,
22334        cx: &mut App,
22335    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22336
22337    fn perform_rename(
22338        &self,
22339        buffer: &Entity<Buffer>,
22340        position: text::Anchor,
22341        new_name: String,
22342        cx: &mut App,
22343    ) -> Option<Task<Result<ProjectTransaction>>>;
22344}
22345
22346pub trait CompletionProvider {
22347    fn completions(
22348        &self,
22349        excerpt_id: ExcerptId,
22350        buffer: &Entity<Buffer>,
22351        buffer_position: text::Anchor,
22352        trigger: CompletionContext,
22353        window: &mut Window,
22354        cx: &mut Context<Editor>,
22355    ) -> Task<Result<Vec<CompletionResponse>>>;
22356
22357    fn resolve_completions(
22358        &self,
22359        _buffer: Entity<Buffer>,
22360        _completion_indices: Vec<usize>,
22361        _completions: Rc<RefCell<Box<[Completion]>>>,
22362        _cx: &mut Context<Editor>,
22363    ) -> Task<Result<bool>> {
22364        Task::ready(Ok(false))
22365    }
22366
22367    fn apply_additional_edits_for_completion(
22368        &self,
22369        _buffer: Entity<Buffer>,
22370        _completions: Rc<RefCell<Box<[Completion]>>>,
22371        _completion_index: usize,
22372        _push_to_history: bool,
22373        _cx: &mut Context<Editor>,
22374    ) -> Task<Result<Option<language::Transaction>>> {
22375        Task::ready(Ok(None))
22376    }
22377
22378    fn is_completion_trigger(
22379        &self,
22380        buffer: &Entity<Buffer>,
22381        position: language::Anchor,
22382        text: &str,
22383        trigger_in_words: bool,
22384        menu_is_open: bool,
22385        cx: &mut Context<Editor>,
22386    ) -> bool;
22387
22388    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22389
22390    fn sort_completions(&self) -> bool {
22391        true
22392    }
22393
22394    fn filter_completions(&self) -> bool {
22395        true
22396    }
22397}
22398
22399pub trait CodeActionProvider {
22400    fn id(&self) -> Arc<str>;
22401
22402    fn code_actions(
22403        &self,
22404        buffer: &Entity<Buffer>,
22405        range: Range<text::Anchor>,
22406        window: &mut Window,
22407        cx: &mut App,
22408    ) -> Task<Result<Vec<CodeAction>>>;
22409
22410    fn apply_code_action(
22411        &self,
22412        buffer_handle: Entity<Buffer>,
22413        action: CodeAction,
22414        excerpt_id: ExcerptId,
22415        push_to_history: bool,
22416        window: &mut Window,
22417        cx: &mut App,
22418    ) -> Task<Result<ProjectTransaction>>;
22419}
22420
22421impl CodeActionProvider for Entity<Project> {
22422    fn id(&self) -> Arc<str> {
22423        "project".into()
22424    }
22425
22426    fn code_actions(
22427        &self,
22428        buffer: &Entity<Buffer>,
22429        range: Range<text::Anchor>,
22430        _window: &mut Window,
22431        cx: &mut App,
22432    ) -> Task<Result<Vec<CodeAction>>> {
22433        self.update(cx, |project, cx| {
22434            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22435            let code_actions = project.code_actions(buffer, range, None, cx);
22436            cx.background_spawn(async move {
22437                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22438                Ok(code_lens_actions
22439                    .context("code lens fetch")?
22440                    .into_iter()
22441                    .flatten()
22442                    .chain(
22443                        code_actions
22444                            .context("code action fetch")?
22445                            .into_iter()
22446                            .flatten(),
22447                    )
22448                    .collect())
22449            })
22450        })
22451    }
22452
22453    fn apply_code_action(
22454        &self,
22455        buffer_handle: Entity<Buffer>,
22456        action: CodeAction,
22457        _excerpt_id: ExcerptId,
22458        push_to_history: bool,
22459        _window: &mut Window,
22460        cx: &mut App,
22461    ) -> Task<Result<ProjectTransaction>> {
22462        self.update(cx, |project, cx| {
22463            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22464        })
22465    }
22466}
22467
22468fn snippet_completions(
22469    project: &Project,
22470    buffer: &Entity<Buffer>,
22471    buffer_position: text::Anchor,
22472    cx: &mut App,
22473) -> Task<Result<CompletionResponse>> {
22474    let languages = buffer.read(cx).languages_at(buffer_position);
22475    let snippet_store = project.snippets().read(cx);
22476
22477    let scopes: Vec<_> = languages
22478        .iter()
22479        .filter_map(|language| {
22480            let language_name = language.lsp_id();
22481            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22482
22483            if snippets.is_empty() {
22484                None
22485            } else {
22486                Some((language.default_scope(), snippets))
22487            }
22488        })
22489        .collect();
22490
22491    if scopes.is_empty() {
22492        return Task::ready(Ok(CompletionResponse {
22493            completions: vec![],
22494            display_options: CompletionDisplayOptions::default(),
22495            is_incomplete: false,
22496        }));
22497    }
22498
22499    let snapshot = buffer.read(cx).text_snapshot();
22500    let chars: String = snapshot
22501        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22502        .collect();
22503    let executor = cx.background_executor().clone();
22504
22505    cx.background_spawn(async move {
22506        let mut is_incomplete = false;
22507        let mut completions: Vec<Completion> = Vec::new();
22508        for (scope, snippets) in scopes.into_iter() {
22509            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22510            let mut last_word = chars
22511                .chars()
22512                .take_while(|c| classifier.is_word(*c))
22513                .collect::<String>();
22514            last_word = last_word.chars().rev().collect();
22515
22516            if last_word.is_empty() {
22517                return Ok(CompletionResponse {
22518                    completions: vec![],
22519                    display_options: CompletionDisplayOptions::default(),
22520                    is_incomplete: true,
22521                });
22522            }
22523
22524            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22525            let to_lsp = |point: &text::Anchor| {
22526                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22527                point_to_lsp(end)
22528            };
22529            let lsp_end = to_lsp(&buffer_position);
22530
22531            let candidates = snippets
22532                .iter()
22533                .enumerate()
22534                .flat_map(|(ix, snippet)| {
22535                    snippet
22536                        .prefix
22537                        .iter()
22538                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22539                })
22540                .collect::<Vec<StringMatchCandidate>>();
22541
22542            const MAX_RESULTS: usize = 100;
22543            let mut matches = fuzzy::match_strings(
22544                &candidates,
22545                &last_word,
22546                last_word.chars().any(|c| c.is_uppercase()),
22547                true,
22548                MAX_RESULTS,
22549                &Default::default(),
22550                executor.clone(),
22551            )
22552            .await;
22553
22554            if matches.len() >= MAX_RESULTS {
22555                is_incomplete = true;
22556            }
22557
22558            // Remove all candidates where the query's start does not match the start of any word in the candidate
22559            if let Some(query_start) = last_word.chars().next() {
22560                matches.retain(|string_match| {
22561                    split_words(&string_match.string).any(|word| {
22562                        // Check that the first codepoint of the word as lowercase matches the first
22563                        // codepoint of the query as lowercase
22564                        word.chars()
22565                            .flat_map(|codepoint| codepoint.to_lowercase())
22566                            .zip(query_start.to_lowercase())
22567                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22568                    })
22569                });
22570            }
22571
22572            let matched_strings = matches
22573                .into_iter()
22574                .map(|m| m.string)
22575                .collect::<HashSet<_>>();
22576
22577            completions.extend(snippets.iter().filter_map(|snippet| {
22578                let matching_prefix = snippet
22579                    .prefix
22580                    .iter()
22581                    .find(|prefix| matched_strings.contains(*prefix))?;
22582                let start = as_offset - last_word.len();
22583                let start = snapshot.anchor_before(start);
22584                let range = start..buffer_position;
22585                let lsp_start = to_lsp(&start);
22586                let lsp_range = lsp::Range {
22587                    start: lsp_start,
22588                    end: lsp_end,
22589                };
22590                Some(Completion {
22591                    replace_range: range,
22592                    new_text: snippet.body.clone(),
22593                    source: CompletionSource::Lsp {
22594                        insert_range: None,
22595                        server_id: LanguageServerId(usize::MAX),
22596                        resolved: true,
22597                        lsp_completion: Box::new(lsp::CompletionItem {
22598                            label: snippet.prefix.first().unwrap().clone(),
22599                            kind: Some(CompletionItemKind::SNIPPET),
22600                            label_details: snippet.description.as_ref().map(|description| {
22601                                lsp::CompletionItemLabelDetails {
22602                                    detail: Some(description.clone()),
22603                                    description: None,
22604                                }
22605                            }),
22606                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22607                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22608                                lsp::InsertReplaceEdit {
22609                                    new_text: snippet.body.clone(),
22610                                    insert: lsp_range,
22611                                    replace: lsp_range,
22612                                },
22613                            )),
22614                            filter_text: Some(snippet.body.clone()),
22615                            sort_text: Some(char::MAX.to_string()),
22616                            ..lsp::CompletionItem::default()
22617                        }),
22618                        lsp_defaults: None,
22619                    },
22620                    label: CodeLabel {
22621                        text: matching_prefix.clone(),
22622                        runs: Vec::new(),
22623                        filter_range: 0..matching_prefix.len(),
22624                    },
22625                    icon_path: None,
22626                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22627                        single_line: snippet.name.clone().into(),
22628                        plain_text: snippet
22629                            .description
22630                            .clone()
22631                            .map(|description| description.into()),
22632                    }),
22633                    insert_text_mode: None,
22634                    confirm: None,
22635                })
22636            }))
22637        }
22638
22639        Ok(CompletionResponse {
22640            completions,
22641            display_options: CompletionDisplayOptions::default(),
22642            is_incomplete,
22643        })
22644    })
22645}
22646
22647impl CompletionProvider for Entity<Project> {
22648    fn completions(
22649        &self,
22650        _excerpt_id: ExcerptId,
22651        buffer: &Entity<Buffer>,
22652        buffer_position: text::Anchor,
22653        options: CompletionContext,
22654        _window: &mut Window,
22655        cx: &mut Context<Editor>,
22656    ) -> Task<Result<Vec<CompletionResponse>>> {
22657        self.update(cx, |project, cx| {
22658            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22659            let project_completions = project.completions(buffer, buffer_position, options, cx);
22660            cx.background_spawn(async move {
22661                let mut responses = project_completions.await?;
22662                let snippets = snippets.await?;
22663                if !snippets.completions.is_empty() {
22664                    responses.push(snippets);
22665                }
22666                Ok(responses)
22667            })
22668        })
22669    }
22670
22671    fn resolve_completions(
22672        &self,
22673        buffer: Entity<Buffer>,
22674        completion_indices: Vec<usize>,
22675        completions: Rc<RefCell<Box<[Completion]>>>,
22676        cx: &mut Context<Editor>,
22677    ) -> Task<Result<bool>> {
22678        self.update(cx, |project, cx| {
22679            project.lsp_store().update(cx, |lsp_store, cx| {
22680                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22681            })
22682        })
22683    }
22684
22685    fn apply_additional_edits_for_completion(
22686        &self,
22687        buffer: Entity<Buffer>,
22688        completions: Rc<RefCell<Box<[Completion]>>>,
22689        completion_index: usize,
22690        push_to_history: bool,
22691        cx: &mut Context<Editor>,
22692    ) -> Task<Result<Option<language::Transaction>>> {
22693        self.update(cx, |project, cx| {
22694            project.lsp_store().update(cx, |lsp_store, cx| {
22695                lsp_store.apply_additional_edits_for_completion(
22696                    buffer,
22697                    completions,
22698                    completion_index,
22699                    push_to_history,
22700                    cx,
22701                )
22702            })
22703        })
22704    }
22705
22706    fn is_completion_trigger(
22707        &self,
22708        buffer: &Entity<Buffer>,
22709        position: language::Anchor,
22710        text: &str,
22711        trigger_in_words: bool,
22712        menu_is_open: bool,
22713        cx: &mut Context<Editor>,
22714    ) -> bool {
22715        let mut chars = text.chars();
22716        let char = if let Some(char) = chars.next() {
22717            char
22718        } else {
22719            return false;
22720        };
22721        if chars.next().is_some() {
22722            return false;
22723        }
22724
22725        let buffer = buffer.read(cx);
22726        let snapshot = buffer.snapshot();
22727        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22728            return false;
22729        }
22730        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22731        if trigger_in_words && classifier.is_word(char) {
22732            return true;
22733        }
22734
22735        buffer.completion_triggers().contains(text)
22736    }
22737}
22738
22739impl SemanticsProvider for Entity<Project> {
22740    fn hover(
22741        &self,
22742        buffer: &Entity<Buffer>,
22743        position: text::Anchor,
22744        cx: &mut App,
22745    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22746        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22747    }
22748
22749    fn document_highlights(
22750        &self,
22751        buffer: &Entity<Buffer>,
22752        position: text::Anchor,
22753        cx: &mut App,
22754    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22755        Some(self.update(cx, |project, cx| {
22756            project.document_highlights(buffer, position, cx)
22757        }))
22758    }
22759
22760    fn definitions(
22761        &self,
22762        buffer: &Entity<Buffer>,
22763        position: text::Anchor,
22764        kind: GotoDefinitionKind,
22765        cx: &mut App,
22766    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22767        Some(self.update(cx, |project, cx| match kind {
22768            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22769            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22770            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22771            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22772        }))
22773    }
22774
22775    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22776        self.update(cx, |project, cx| {
22777            if project
22778                .active_debug_session(cx)
22779                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22780            {
22781                return true;
22782            }
22783
22784            buffer.update(cx, |buffer, cx| {
22785                project.any_language_server_supports_inlay_hints(buffer, cx)
22786            })
22787        })
22788    }
22789
22790    fn inline_values(
22791        &self,
22792        buffer_handle: Entity<Buffer>,
22793        range: Range<text::Anchor>,
22794        cx: &mut App,
22795    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22796        self.update(cx, |project, cx| {
22797            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22798
22799            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22800        })
22801    }
22802
22803    fn inlay_hints(
22804        &self,
22805        buffer_handle: Entity<Buffer>,
22806        range: Range<text::Anchor>,
22807        cx: &mut App,
22808    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22809        Some(self.update(cx, |project, cx| {
22810            project.inlay_hints(buffer_handle, range, cx)
22811        }))
22812    }
22813
22814    fn resolve_inlay_hint(
22815        &self,
22816        hint: InlayHint,
22817        buffer_handle: Entity<Buffer>,
22818        server_id: LanguageServerId,
22819        cx: &mut App,
22820    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22821        Some(self.update(cx, |project, cx| {
22822            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22823        }))
22824    }
22825
22826    fn range_for_rename(
22827        &self,
22828        buffer: &Entity<Buffer>,
22829        position: text::Anchor,
22830        cx: &mut App,
22831    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22832        Some(self.update(cx, |project, cx| {
22833            let buffer = buffer.clone();
22834            let task = project.prepare_rename(buffer.clone(), position, cx);
22835            cx.spawn(async move |_, cx| {
22836                Ok(match task.await? {
22837                    PrepareRenameResponse::Success(range) => Some(range),
22838                    PrepareRenameResponse::InvalidPosition => None,
22839                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22840                        // Fallback on using TreeSitter info to determine identifier range
22841                        buffer.read_with(cx, |buffer, _| {
22842                            let snapshot = buffer.snapshot();
22843                            let (range, kind) = snapshot.surrounding_word(position, false);
22844                            if kind != Some(CharKind::Word) {
22845                                return None;
22846                            }
22847                            Some(
22848                                snapshot.anchor_before(range.start)
22849                                    ..snapshot.anchor_after(range.end),
22850                            )
22851                        })?
22852                    }
22853                })
22854            })
22855        }))
22856    }
22857
22858    fn perform_rename(
22859        &self,
22860        buffer: &Entity<Buffer>,
22861        position: text::Anchor,
22862        new_name: String,
22863        cx: &mut App,
22864    ) -> Option<Task<Result<ProjectTransaction>>> {
22865        Some(self.update(cx, |project, cx| {
22866            project.perform_rename(buffer.clone(), position, new_name, cx)
22867        }))
22868    }
22869}
22870
22871fn inlay_hint_settings(
22872    location: Anchor,
22873    snapshot: &MultiBufferSnapshot,
22874    cx: &mut Context<Editor>,
22875) -> InlayHintSettings {
22876    let file = snapshot.file_at(location);
22877    let language = snapshot.language_at(location).map(|l| l.name());
22878    language_settings(language, file, cx).inlay_hints
22879}
22880
22881fn consume_contiguous_rows(
22882    contiguous_row_selections: &mut Vec<Selection<Point>>,
22883    selection: &Selection<Point>,
22884    display_map: &DisplaySnapshot,
22885    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22886) -> (MultiBufferRow, MultiBufferRow) {
22887    contiguous_row_selections.push(selection.clone());
22888    let start_row = starting_row(selection, display_map);
22889    let mut end_row = ending_row(selection, display_map);
22890
22891    while let Some(next_selection) = selections.peek() {
22892        if next_selection.start.row <= end_row.0 {
22893            end_row = ending_row(next_selection, display_map);
22894            contiguous_row_selections.push(selections.next().unwrap().clone());
22895        } else {
22896            break;
22897        }
22898    }
22899    (start_row, end_row)
22900}
22901
22902fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22903    if selection.start.column > 0 {
22904        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22905    } else {
22906        MultiBufferRow(selection.start.row)
22907    }
22908}
22909
22910fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22911    if next_selection.end.column > 0 || next_selection.is_empty() {
22912        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22913    } else {
22914        MultiBufferRow(next_selection.end.row)
22915    }
22916}
22917
22918impl EditorSnapshot {
22919    pub fn remote_selections_in_range<'a>(
22920        &'a self,
22921        range: &'a Range<Anchor>,
22922        collaboration_hub: &dyn CollaborationHub,
22923        cx: &'a App,
22924    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22925        let participant_names = collaboration_hub.user_names(cx);
22926        let participant_indices = collaboration_hub.user_participant_indices(cx);
22927        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22928        let collaborators_by_replica_id = collaborators_by_peer_id
22929            .values()
22930            .map(|collaborator| (collaborator.replica_id, collaborator))
22931            .collect::<HashMap<_, _>>();
22932        self.buffer_snapshot
22933            .selections_in_range(range, false)
22934            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22935                if replica_id == AGENT_REPLICA_ID {
22936                    Some(RemoteSelection {
22937                        replica_id,
22938                        selection,
22939                        cursor_shape,
22940                        line_mode,
22941                        collaborator_id: CollaboratorId::Agent,
22942                        user_name: Some("Agent".into()),
22943                        color: cx.theme().players().agent(),
22944                    })
22945                } else {
22946                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22947                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22948                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22949                    Some(RemoteSelection {
22950                        replica_id,
22951                        selection,
22952                        cursor_shape,
22953                        line_mode,
22954                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22955                        user_name,
22956                        color: if let Some(index) = participant_index {
22957                            cx.theme().players().color_for_participant(index.0)
22958                        } else {
22959                            cx.theme().players().absent()
22960                        },
22961                    })
22962                }
22963            })
22964    }
22965
22966    pub fn hunks_for_ranges(
22967        &self,
22968        ranges: impl IntoIterator<Item = Range<Point>>,
22969    ) -> Vec<MultiBufferDiffHunk> {
22970        let mut hunks = Vec::new();
22971        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22972            HashMap::default();
22973        for query_range in ranges {
22974            let query_rows =
22975                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22976            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22977                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22978            ) {
22979                // Include deleted hunks that are adjacent to the query range, because
22980                // otherwise they would be missed.
22981                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22982                if hunk.status().is_deleted() {
22983                    intersects_range |= hunk.row_range.start == query_rows.end;
22984                    intersects_range |= hunk.row_range.end == query_rows.start;
22985                }
22986                if intersects_range {
22987                    if !processed_buffer_rows
22988                        .entry(hunk.buffer_id)
22989                        .or_default()
22990                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22991                    {
22992                        continue;
22993                    }
22994                    hunks.push(hunk);
22995                }
22996            }
22997        }
22998
22999        hunks
23000    }
23001
23002    fn display_diff_hunks_for_rows<'a>(
23003        &'a self,
23004        display_rows: Range<DisplayRow>,
23005        folded_buffers: &'a HashSet<BufferId>,
23006    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23007        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23008        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23009
23010        self.buffer_snapshot
23011            .diff_hunks_in_range(buffer_start..buffer_end)
23012            .filter_map(|hunk| {
23013                if folded_buffers.contains(&hunk.buffer_id) {
23014                    return None;
23015                }
23016
23017                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23018                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23019
23020                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23021                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23022
23023                let display_hunk = if hunk_display_start.column() != 0 {
23024                    DisplayDiffHunk::Folded {
23025                        display_row: hunk_display_start.row(),
23026                    }
23027                } else {
23028                    let mut end_row = hunk_display_end.row();
23029                    if hunk_display_end.column() > 0 {
23030                        end_row.0 += 1;
23031                    }
23032                    let is_created_file = hunk.is_created_file();
23033                    DisplayDiffHunk::Unfolded {
23034                        status: hunk.status(),
23035                        diff_base_byte_range: hunk.diff_base_byte_range,
23036                        display_row_range: hunk_display_start.row()..end_row,
23037                        multi_buffer_range: Anchor::range_in_buffer(
23038                            hunk.excerpt_id,
23039                            hunk.buffer_id,
23040                            hunk.buffer_range,
23041                        ),
23042                        is_created_file,
23043                    }
23044                };
23045
23046                Some(display_hunk)
23047            })
23048    }
23049
23050    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23051        self.display_snapshot.buffer_snapshot.language_at(position)
23052    }
23053
23054    pub fn is_focused(&self) -> bool {
23055        self.is_focused
23056    }
23057
23058    pub fn placeholder_text(&self) -> Option<String> {
23059        self.placeholder_display_snapshot
23060            .as_ref()
23061            .map(|display_map| display_map.text())
23062    }
23063
23064    pub fn scroll_position(&self) -> gpui::Point<f32> {
23065        self.scroll_anchor.scroll_position(&self.display_snapshot)
23066    }
23067
23068    fn gutter_dimensions(
23069        &self,
23070        font_id: FontId,
23071        font_size: Pixels,
23072        max_line_number_width: Pixels,
23073        cx: &App,
23074    ) -> Option<GutterDimensions> {
23075        if !self.show_gutter {
23076            return None;
23077        }
23078
23079        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23080        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23081
23082        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23083            matches!(
23084                ProjectSettings::get_global(cx).git.git_gutter,
23085                Some(GitGutterSetting::TrackedFiles)
23086            )
23087        });
23088        let gutter_settings = EditorSettings::get_global(cx).gutter;
23089        let show_line_numbers = self
23090            .show_line_numbers
23091            .unwrap_or(gutter_settings.line_numbers);
23092        let line_gutter_width = if show_line_numbers {
23093            // Avoid flicker-like gutter resizes when the line number gains another digit by
23094            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23095            let min_width_for_number_on_gutter =
23096                ch_advance * gutter_settings.min_line_number_digits as f32;
23097            max_line_number_width.max(min_width_for_number_on_gutter)
23098        } else {
23099            0.0.into()
23100        };
23101
23102        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23103        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23104
23105        let git_blame_entries_width =
23106            self.git_blame_gutter_max_author_length
23107                .map(|max_author_length| {
23108                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23109                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23110
23111                    /// The number of characters to dedicate to gaps and margins.
23112                    const SPACING_WIDTH: usize = 4;
23113
23114                    let max_char_count = max_author_length.min(renderer.max_author_length())
23115                        + ::git::SHORT_SHA_LENGTH
23116                        + MAX_RELATIVE_TIMESTAMP.len()
23117                        + SPACING_WIDTH;
23118
23119                    ch_advance * max_char_count
23120                });
23121
23122        let is_singleton = self.buffer_snapshot.is_singleton();
23123
23124        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23125        left_padding += if !is_singleton {
23126            ch_width * 4.0
23127        } else if show_runnables || show_breakpoints {
23128            ch_width * 3.0
23129        } else if show_git_gutter && show_line_numbers {
23130            ch_width * 2.0
23131        } else if show_git_gutter || show_line_numbers {
23132            ch_width
23133        } else {
23134            px(0.)
23135        };
23136
23137        let shows_folds = is_singleton && gutter_settings.folds;
23138
23139        let right_padding = if shows_folds && show_line_numbers {
23140            ch_width * 4.0
23141        } else if shows_folds || (!is_singleton && show_line_numbers) {
23142            ch_width * 3.0
23143        } else if show_line_numbers {
23144            ch_width
23145        } else {
23146            px(0.)
23147        };
23148
23149        Some(GutterDimensions {
23150            left_padding,
23151            right_padding,
23152            width: line_gutter_width + left_padding + right_padding,
23153            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23154            git_blame_entries_width,
23155        })
23156    }
23157
23158    pub fn render_crease_toggle(
23159        &self,
23160        buffer_row: MultiBufferRow,
23161        row_contains_cursor: bool,
23162        editor: Entity<Editor>,
23163        window: &mut Window,
23164        cx: &mut App,
23165    ) -> Option<AnyElement> {
23166        let folded = self.is_line_folded(buffer_row);
23167        let mut is_foldable = false;
23168
23169        if let Some(crease) = self
23170            .crease_snapshot
23171            .query_row(buffer_row, &self.buffer_snapshot)
23172        {
23173            is_foldable = true;
23174            match crease {
23175                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23176                    if let Some(render_toggle) = render_toggle {
23177                        let toggle_callback =
23178                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23179                                if folded {
23180                                    editor.update(cx, |editor, cx| {
23181                                        editor.fold_at(buffer_row, window, cx)
23182                                    });
23183                                } else {
23184                                    editor.update(cx, |editor, cx| {
23185                                        editor.unfold_at(buffer_row, window, cx)
23186                                    });
23187                                }
23188                            });
23189                        return Some((render_toggle)(
23190                            buffer_row,
23191                            folded,
23192                            toggle_callback,
23193                            window,
23194                            cx,
23195                        ));
23196                    }
23197                }
23198            }
23199        }
23200
23201        is_foldable |= self.starts_indent(buffer_row);
23202
23203        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23204            Some(
23205                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23206                    .toggle_state(folded)
23207                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23208                        if folded {
23209                            this.unfold_at(buffer_row, window, cx);
23210                        } else {
23211                            this.fold_at(buffer_row, window, cx);
23212                        }
23213                    }))
23214                    .into_any_element(),
23215            )
23216        } else {
23217            None
23218        }
23219    }
23220
23221    pub fn render_crease_trailer(
23222        &self,
23223        buffer_row: MultiBufferRow,
23224        window: &mut Window,
23225        cx: &mut App,
23226    ) -> Option<AnyElement> {
23227        let folded = self.is_line_folded(buffer_row);
23228        if let Crease::Inline { render_trailer, .. } = self
23229            .crease_snapshot
23230            .query_row(buffer_row, &self.buffer_snapshot)?
23231        {
23232            let render_trailer = render_trailer.as_ref()?;
23233            Some(render_trailer(buffer_row, folded, window, cx))
23234        } else {
23235            None
23236        }
23237    }
23238}
23239
23240impl Deref for EditorSnapshot {
23241    type Target = DisplaySnapshot;
23242
23243    fn deref(&self) -> &Self::Target {
23244        &self.display_snapshot
23245    }
23246}
23247
23248#[derive(Clone, Debug, PartialEq, Eq)]
23249pub enum EditorEvent {
23250    InputIgnored {
23251        text: Arc<str>,
23252    },
23253    InputHandled {
23254        utf16_range_to_replace: Option<Range<isize>>,
23255        text: Arc<str>,
23256    },
23257    ExcerptsAdded {
23258        buffer: Entity<Buffer>,
23259        predecessor: ExcerptId,
23260        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23261    },
23262    ExcerptsRemoved {
23263        ids: Vec<ExcerptId>,
23264        removed_buffer_ids: Vec<BufferId>,
23265    },
23266    BufferFoldToggled {
23267        ids: Vec<ExcerptId>,
23268        folded: bool,
23269    },
23270    ExcerptsEdited {
23271        ids: Vec<ExcerptId>,
23272    },
23273    ExcerptsExpanded {
23274        ids: Vec<ExcerptId>,
23275    },
23276    BufferEdited,
23277    Edited {
23278        transaction_id: clock::Lamport,
23279    },
23280    Reparsed(BufferId),
23281    Focused,
23282    FocusedIn,
23283    Blurred,
23284    DirtyChanged,
23285    Saved,
23286    TitleChanged,
23287    SelectionsChanged {
23288        local: bool,
23289    },
23290    ScrollPositionChanged {
23291        local: bool,
23292        autoscroll: bool,
23293    },
23294    TransactionUndone {
23295        transaction_id: clock::Lamport,
23296    },
23297    TransactionBegun {
23298        transaction_id: clock::Lamport,
23299    },
23300    CursorShapeChanged,
23301    BreadcrumbsChanged,
23302    PushedToNavHistory {
23303        anchor: Anchor,
23304        is_deactivate: bool,
23305    },
23306}
23307
23308impl EventEmitter<EditorEvent> for Editor {}
23309
23310impl Focusable for Editor {
23311    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23312        self.focus_handle.clone()
23313    }
23314}
23315
23316impl Render for Editor {
23317    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23318        let settings = ThemeSettings::get_global(cx);
23319
23320        let mut text_style = match self.mode {
23321            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23322                color: cx.theme().colors().editor_foreground,
23323                font_family: settings.ui_font.family.clone(),
23324                font_features: settings.ui_font.features.clone(),
23325                font_fallbacks: settings.ui_font.fallbacks.clone(),
23326                font_size: rems(0.875).into(),
23327                font_weight: settings.ui_font.weight,
23328                line_height: relative(settings.buffer_line_height.value()),
23329                ..Default::default()
23330            },
23331            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23332                color: cx.theme().colors().editor_foreground,
23333                font_family: settings.buffer_font.family.clone(),
23334                font_features: settings.buffer_font.features.clone(),
23335                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23336                font_size: settings.buffer_font_size(cx).into(),
23337                font_weight: settings.buffer_font.weight,
23338                line_height: relative(settings.buffer_line_height.value()),
23339                ..Default::default()
23340            },
23341        };
23342        if let Some(text_style_refinement) = &self.text_style_refinement {
23343            text_style.refine(text_style_refinement)
23344        }
23345
23346        let background = match self.mode {
23347            EditorMode::SingleLine => cx.theme().system().transparent,
23348            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23349            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23350            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23351        };
23352
23353        EditorElement::new(
23354            &cx.entity(),
23355            EditorStyle {
23356                background,
23357                border: cx.theme().colors().border,
23358                local_player: cx.theme().players().local(),
23359                text: text_style,
23360                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23361                syntax: cx.theme().syntax().clone(),
23362                status: cx.theme().status().clone(),
23363                inlay_hints_style: make_inlay_hints_style(cx),
23364                edit_prediction_styles: make_suggestion_styles(cx),
23365                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23366                show_underlines: self.diagnostics_enabled(),
23367            },
23368        )
23369    }
23370}
23371
23372impl EntityInputHandler for Editor {
23373    fn text_for_range(
23374        &mut self,
23375        range_utf16: Range<usize>,
23376        adjusted_range: &mut Option<Range<usize>>,
23377        _: &mut Window,
23378        cx: &mut Context<Self>,
23379    ) -> Option<String> {
23380        let snapshot = self.buffer.read(cx).read(cx);
23381        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23382        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23383        if (start.0..end.0) != range_utf16 {
23384            adjusted_range.replace(start.0..end.0);
23385        }
23386        Some(snapshot.text_for_range(start..end).collect())
23387    }
23388
23389    fn selected_text_range(
23390        &mut self,
23391        ignore_disabled_input: bool,
23392        _: &mut Window,
23393        cx: &mut Context<Self>,
23394    ) -> Option<UTF16Selection> {
23395        // Prevent the IME menu from appearing when holding down an alphabetic key
23396        // while input is disabled.
23397        if !ignore_disabled_input && !self.input_enabled {
23398            return None;
23399        }
23400
23401        let selection = self.selections.newest::<OffsetUtf16>(cx);
23402        let range = selection.range();
23403
23404        Some(UTF16Selection {
23405            range: range.start.0..range.end.0,
23406            reversed: selection.reversed,
23407        })
23408    }
23409
23410    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23411        let snapshot = self.buffer.read(cx).read(cx);
23412        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23413        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23414    }
23415
23416    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23417        self.clear_highlights::<InputComposition>(cx);
23418        self.ime_transaction.take();
23419    }
23420
23421    fn replace_text_in_range(
23422        &mut self,
23423        range_utf16: Option<Range<usize>>,
23424        text: &str,
23425        window: &mut Window,
23426        cx: &mut Context<Self>,
23427    ) {
23428        if !self.input_enabled {
23429            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23430            return;
23431        }
23432
23433        self.transact(window, cx, |this, window, cx| {
23434            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23435                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23436                Some(this.selection_replacement_ranges(range_utf16, cx))
23437            } else {
23438                this.marked_text_ranges(cx)
23439            };
23440
23441            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23442                let newest_selection_id = this.selections.newest_anchor().id;
23443                this.selections
23444                    .all::<OffsetUtf16>(cx)
23445                    .iter()
23446                    .zip(ranges_to_replace.iter())
23447                    .find_map(|(selection, range)| {
23448                        if selection.id == newest_selection_id {
23449                            Some(
23450                                (range.start.0 as isize - selection.head().0 as isize)
23451                                    ..(range.end.0 as isize - selection.head().0 as isize),
23452                            )
23453                        } else {
23454                            None
23455                        }
23456                    })
23457            });
23458
23459            cx.emit(EditorEvent::InputHandled {
23460                utf16_range_to_replace: range_to_replace,
23461                text: text.into(),
23462            });
23463
23464            if let Some(new_selected_ranges) = new_selected_ranges {
23465                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23466                    selections.select_ranges(new_selected_ranges)
23467                });
23468                this.backspace(&Default::default(), window, cx);
23469            }
23470
23471            this.handle_input(text, window, cx);
23472        });
23473
23474        if let Some(transaction) = self.ime_transaction {
23475            self.buffer.update(cx, |buffer, cx| {
23476                buffer.group_until_transaction(transaction, cx);
23477            });
23478        }
23479
23480        self.unmark_text(window, cx);
23481    }
23482
23483    fn replace_and_mark_text_in_range(
23484        &mut self,
23485        range_utf16: Option<Range<usize>>,
23486        text: &str,
23487        new_selected_range_utf16: Option<Range<usize>>,
23488        window: &mut Window,
23489        cx: &mut Context<Self>,
23490    ) {
23491        if !self.input_enabled {
23492            return;
23493        }
23494
23495        let transaction = self.transact(window, cx, |this, window, cx| {
23496            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23497                let snapshot = this.buffer.read(cx).read(cx);
23498                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23499                    for marked_range in &mut marked_ranges {
23500                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23501                        marked_range.start.0 += relative_range_utf16.start;
23502                        marked_range.start =
23503                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23504                        marked_range.end =
23505                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23506                    }
23507                }
23508                Some(marked_ranges)
23509            } else if let Some(range_utf16) = range_utf16 {
23510                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23511                Some(this.selection_replacement_ranges(range_utf16, cx))
23512            } else {
23513                None
23514            };
23515
23516            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23517                let newest_selection_id = this.selections.newest_anchor().id;
23518                this.selections
23519                    .all::<OffsetUtf16>(cx)
23520                    .iter()
23521                    .zip(ranges_to_replace.iter())
23522                    .find_map(|(selection, range)| {
23523                        if selection.id == newest_selection_id {
23524                            Some(
23525                                (range.start.0 as isize - selection.head().0 as isize)
23526                                    ..(range.end.0 as isize - selection.head().0 as isize),
23527                            )
23528                        } else {
23529                            None
23530                        }
23531                    })
23532            });
23533
23534            cx.emit(EditorEvent::InputHandled {
23535                utf16_range_to_replace: range_to_replace,
23536                text: text.into(),
23537            });
23538
23539            if let Some(ranges) = ranges_to_replace {
23540                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23541                    s.select_ranges(ranges)
23542                });
23543            }
23544
23545            let marked_ranges = {
23546                let snapshot = this.buffer.read(cx).read(cx);
23547                this.selections
23548                    .disjoint_anchors()
23549                    .iter()
23550                    .map(|selection| {
23551                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23552                    })
23553                    .collect::<Vec<_>>()
23554            };
23555
23556            if text.is_empty() {
23557                this.unmark_text(window, cx);
23558            } else {
23559                this.highlight_text::<InputComposition>(
23560                    marked_ranges.clone(),
23561                    HighlightStyle {
23562                        underline: Some(UnderlineStyle {
23563                            thickness: px(1.),
23564                            color: None,
23565                            wavy: false,
23566                        }),
23567                        ..Default::default()
23568                    },
23569                    cx,
23570                );
23571            }
23572
23573            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23574            let use_autoclose = this.use_autoclose;
23575            let use_auto_surround = this.use_auto_surround;
23576            this.set_use_autoclose(false);
23577            this.set_use_auto_surround(false);
23578            this.handle_input(text, window, cx);
23579            this.set_use_autoclose(use_autoclose);
23580            this.set_use_auto_surround(use_auto_surround);
23581
23582            if let Some(new_selected_range) = new_selected_range_utf16 {
23583                let snapshot = this.buffer.read(cx).read(cx);
23584                let new_selected_ranges = marked_ranges
23585                    .into_iter()
23586                    .map(|marked_range| {
23587                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23588                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23589                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23590                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23591                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23592                    })
23593                    .collect::<Vec<_>>();
23594
23595                drop(snapshot);
23596                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23597                    selections.select_ranges(new_selected_ranges)
23598                });
23599            }
23600        });
23601
23602        self.ime_transaction = self.ime_transaction.or(transaction);
23603        if let Some(transaction) = self.ime_transaction {
23604            self.buffer.update(cx, |buffer, cx| {
23605                buffer.group_until_transaction(transaction, cx);
23606            });
23607        }
23608
23609        if self.text_highlights::<InputComposition>(cx).is_none() {
23610            self.ime_transaction.take();
23611        }
23612    }
23613
23614    fn bounds_for_range(
23615        &mut self,
23616        range_utf16: Range<usize>,
23617        element_bounds: gpui::Bounds<Pixels>,
23618        window: &mut Window,
23619        cx: &mut Context<Self>,
23620    ) -> Option<gpui::Bounds<Pixels>> {
23621        let text_layout_details = self.text_layout_details(window);
23622        let CharacterDimensions {
23623            em_width,
23624            em_advance,
23625            line_height,
23626        } = self.character_dimensions(window);
23627
23628        let snapshot = self.snapshot(window, cx);
23629        let scroll_position = snapshot.scroll_position();
23630        let scroll_left = scroll_position.x * em_advance;
23631
23632        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23633        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23634            + self.gutter_dimensions.full_width();
23635        let y = line_height * (start.row().as_f32() - scroll_position.y);
23636
23637        Some(Bounds {
23638            origin: element_bounds.origin + point(x, y),
23639            size: size(em_width, line_height),
23640        })
23641    }
23642
23643    fn character_index_for_point(
23644        &mut self,
23645        point: gpui::Point<Pixels>,
23646        _window: &mut Window,
23647        _cx: &mut Context<Self>,
23648    ) -> Option<usize> {
23649        let position_map = self.last_position_map.as_ref()?;
23650        if !position_map.text_hitbox.contains(&point) {
23651            return None;
23652        }
23653        let display_point = position_map.point_for_position(point).previous_valid;
23654        let anchor = position_map
23655            .snapshot
23656            .display_point_to_anchor(display_point, Bias::Left);
23657        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23658        Some(utf16_offset.0)
23659    }
23660}
23661
23662trait SelectionExt {
23663    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23664    fn spanned_rows(
23665        &self,
23666        include_end_if_at_line_start: bool,
23667        map: &DisplaySnapshot,
23668    ) -> Range<MultiBufferRow>;
23669}
23670
23671impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23672    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23673        let start = self
23674            .start
23675            .to_point(&map.buffer_snapshot)
23676            .to_display_point(map);
23677        let end = self
23678            .end
23679            .to_point(&map.buffer_snapshot)
23680            .to_display_point(map);
23681        if self.reversed {
23682            end..start
23683        } else {
23684            start..end
23685        }
23686    }
23687
23688    fn spanned_rows(
23689        &self,
23690        include_end_if_at_line_start: bool,
23691        map: &DisplaySnapshot,
23692    ) -> Range<MultiBufferRow> {
23693        let start = self.start.to_point(&map.buffer_snapshot);
23694        let mut end = self.end.to_point(&map.buffer_snapshot);
23695        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23696            end.row -= 1;
23697        }
23698
23699        let buffer_start = map.prev_line_boundary(start).0;
23700        let buffer_end = map.next_line_boundary(end).0;
23701        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23702    }
23703}
23704
23705impl<T: InvalidationRegion> InvalidationStack<T> {
23706    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23707    where
23708        S: Clone + ToOffset,
23709    {
23710        while let Some(region) = self.last() {
23711            let all_selections_inside_invalidation_ranges =
23712                if selections.len() == region.ranges().len() {
23713                    selections
23714                        .iter()
23715                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23716                        .all(|(selection, invalidation_range)| {
23717                            let head = selection.head().to_offset(buffer);
23718                            invalidation_range.start <= head && invalidation_range.end >= head
23719                        })
23720                } else {
23721                    false
23722                };
23723
23724            if all_selections_inside_invalidation_ranges {
23725                break;
23726            } else {
23727                self.pop();
23728            }
23729        }
23730    }
23731}
23732
23733impl<T> Default for InvalidationStack<T> {
23734    fn default() -> Self {
23735        Self(Default::default())
23736    }
23737}
23738
23739impl<T> Deref for InvalidationStack<T> {
23740    type Target = Vec<T>;
23741
23742    fn deref(&self) -> &Self::Target {
23743        &self.0
23744    }
23745}
23746
23747impl<T> DerefMut for InvalidationStack<T> {
23748    fn deref_mut(&mut self) -> &mut Self::Target {
23749        &mut self.0
23750    }
23751}
23752
23753impl InvalidationRegion for SnippetState {
23754    fn ranges(&self) -> &[Range<Anchor>] {
23755        &self.ranges[self.active_index]
23756    }
23757}
23758
23759fn edit_prediction_edit_text(
23760    current_snapshot: &BufferSnapshot,
23761    edits: &[(Range<Anchor>, String)],
23762    edit_preview: &EditPreview,
23763    include_deletions: bool,
23764    cx: &App,
23765) -> HighlightedText {
23766    let edits = edits
23767        .iter()
23768        .map(|(anchor, text)| {
23769            (
23770                anchor.start.text_anchor..anchor.end.text_anchor,
23771                text.clone(),
23772            )
23773        })
23774        .collect::<Vec<_>>();
23775
23776    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23777}
23778
23779fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23780    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23781    // Just show the raw edit text with basic styling
23782    let mut text = String::new();
23783    let mut highlights = Vec::new();
23784
23785    let insertion_highlight_style = HighlightStyle {
23786        color: Some(cx.theme().colors().text),
23787        ..Default::default()
23788    };
23789
23790    for (_, edit_text) in edits {
23791        let start_offset = text.len();
23792        text.push_str(edit_text);
23793        let end_offset = text.len();
23794
23795        if start_offset < end_offset {
23796            highlights.push((start_offset..end_offset, insertion_highlight_style));
23797        }
23798    }
23799
23800    HighlightedText {
23801        text: text.into(),
23802        highlights,
23803    }
23804}
23805
23806pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23807    match severity {
23808        lsp::DiagnosticSeverity::ERROR => colors.error,
23809        lsp::DiagnosticSeverity::WARNING => colors.warning,
23810        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23811        lsp::DiagnosticSeverity::HINT => colors.info,
23812        _ => colors.ignored,
23813    }
23814}
23815
23816pub fn styled_runs_for_code_label<'a>(
23817    label: &'a CodeLabel,
23818    syntax_theme: &'a theme::SyntaxTheme,
23819) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23820    let fade_out = HighlightStyle {
23821        fade_out: Some(0.35),
23822        ..Default::default()
23823    };
23824
23825    let mut prev_end = label.filter_range.end;
23826    label
23827        .runs
23828        .iter()
23829        .enumerate()
23830        .flat_map(move |(ix, (range, highlight_id))| {
23831            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23832                style
23833            } else {
23834                return Default::default();
23835            };
23836            let muted_style = style.highlight(fade_out);
23837
23838            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23839            if range.start >= label.filter_range.end {
23840                if range.start > prev_end {
23841                    runs.push((prev_end..range.start, fade_out));
23842                }
23843                runs.push((range.clone(), muted_style));
23844            } else if range.end <= label.filter_range.end {
23845                runs.push((range.clone(), style));
23846            } else {
23847                runs.push((range.start..label.filter_range.end, style));
23848                runs.push((label.filter_range.end..range.end, muted_style));
23849            }
23850            prev_end = cmp::max(prev_end, range.end);
23851
23852            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23853                runs.push((prev_end..label.text.len(), fade_out));
23854            }
23855
23856            runs
23857        })
23858}
23859
23860pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23861    let mut prev_index = 0;
23862    let mut prev_codepoint: Option<char> = None;
23863    text.char_indices()
23864        .chain([(text.len(), '\0')])
23865        .filter_map(move |(index, codepoint)| {
23866            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23867            let is_boundary = index == text.len()
23868                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23869                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23870            if is_boundary {
23871                let chunk = &text[prev_index..index];
23872                prev_index = index;
23873                Some(chunk)
23874            } else {
23875                None
23876            }
23877        })
23878}
23879
23880pub trait RangeToAnchorExt: Sized {
23881    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23882
23883    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23884        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23885        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23886    }
23887}
23888
23889impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23890    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23891        let start_offset = self.start.to_offset(snapshot);
23892        let end_offset = self.end.to_offset(snapshot);
23893        if start_offset == end_offset {
23894            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23895        } else {
23896            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23897        }
23898    }
23899}
23900
23901pub trait RowExt {
23902    fn as_f32(&self) -> f32;
23903
23904    fn next_row(&self) -> Self;
23905
23906    fn previous_row(&self) -> Self;
23907
23908    fn minus(&self, other: Self) -> u32;
23909}
23910
23911impl RowExt for DisplayRow {
23912    fn as_f32(&self) -> f32 {
23913        self.0 as f32
23914    }
23915
23916    fn next_row(&self) -> Self {
23917        Self(self.0 + 1)
23918    }
23919
23920    fn previous_row(&self) -> Self {
23921        Self(self.0.saturating_sub(1))
23922    }
23923
23924    fn minus(&self, other: Self) -> u32 {
23925        self.0 - other.0
23926    }
23927}
23928
23929impl RowExt for MultiBufferRow {
23930    fn as_f32(&self) -> f32 {
23931        self.0 as f32
23932    }
23933
23934    fn next_row(&self) -> Self {
23935        Self(self.0 + 1)
23936    }
23937
23938    fn previous_row(&self) -> Self {
23939        Self(self.0.saturating_sub(1))
23940    }
23941
23942    fn minus(&self, other: Self) -> u32 {
23943        self.0 - other.0
23944    }
23945}
23946
23947trait RowRangeExt {
23948    type Row;
23949
23950    fn len(&self) -> usize;
23951
23952    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23953}
23954
23955impl RowRangeExt for Range<MultiBufferRow> {
23956    type Row = MultiBufferRow;
23957
23958    fn len(&self) -> usize {
23959        (self.end.0 - self.start.0) as usize
23960    }
23961
23962    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23963        (self.start.0..self.end.0).map(MultiBufferRow)
23964    }
23965}
23966
23967impl RowRangeExt for Range<DisplayRow> {
23968    type Row = DisplayRow;
23969
23970    fn len(&self) -> usize {
23971        (self.end.0 - self.start.0) as usize
23972    }
23973
23974    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23975        (self.start.0..self.end.0).map(DisplayRow)
23976    }
23977}
23978
23979/// If select range has more than one line, we
23980/// just point the cursor to range.start.
23981fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23982    if range.start.row == range.end.row {
23983        range
23984    } else {
23985        range.start..range.start
23986    }
23987}
23988pub struct KillRing(ClipboardItem);
23989impl Global for KillRing {}
23990
23991const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23992
23993enum BreakpointPromptEditAction {
23994    Log,
23995    Condition,
23996    HitCondition,
23997}
23998
23999struct BreakpointPromptEditor {
24000    pub(crate) prompt: Entity<Editor>,
24001    editor: WeakEntity<Editor>,
24002    breakpoint_anchor: Anchor,
24003    breakpoint: Breakpoint,
24004    edit_action: BreakpointPromptEditAction,
24005    block_ids: HashSet<CustomBlockId>,
24006    editor_margins: Arc<Mutex<EditorMargins>>,
24007    _subscriptions: Vec<Subscription>,
24008}
24009
24010impl BreakpointPromptEditor {
24011    const MAX_LINES: u8 = 4;
24012
24013    fn new(
24014        editor: WeakEntity<Editor>,
24015        breakpoint_anchor: Anchor,
24016        breakpoint: Breakpoint,
24017        edit_action: BreakpointPromptEditAction,
24018        window: &mut Window,
24019        cx: &mut Context<Self>,
24020    ) -> Self {
24021        let base_text = match edit_action {
24022            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24023            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24024            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24025        }
24026        .map(|msg| msg.to_string())
24027        .unwrap_or_default();
24028
24029        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24030        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24031
24032        let prompt = cx.new(|cx| {
24033            let mut prompt = Editor::new(
24034                EditorMode::AutoHeight {
24035                    min_lines: 1,
24036                    max_lines: Some(Self::MAX_LINES as usize),
24037                },
24038                buffer,
24039                None,
24040                window,
24041                cx,
24042            );
24043            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24044            prompt.set_show_cursor_when_unfocused(false, cx);
24045            prompt.set_placeholder_text(
24046                match edit_action {
24047                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24048                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24049                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24050                },
24051                window,
24052                cx,
24053            );
24054
24055            prompt
24056        });
24057
24058        Self {
24059            prompt,
24060            editor,
24061            breakpoint_anchor,
24062            breakpoint,
24063            edit_action,
24064            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24065            block_ids: Default::default(),
24066            _subscriptions: vec![],
24067        }
24068    }
24069
24070    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24071        self.block_ids.extend(block_ids)
24072    }
24073
24074    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24075        if let Some(editor) = self.editor.upgrade() {
24076            let message = self
24077                .prompt
24078                .read(cx)
24079                .buffer
24080                .read(cx)
24081                .as_singleton()
24082                .expect("A multi buffer in breakpoint prompt isn't possible")
24083                .read(cx)
24084                .as_rope()
24085                .to_string();
24086
24087            editor.update(cx, |editor, cx| {
24088                editor.edit_breakpoint_at_anchor(
24089                    self.breakpoint_anchor,
24090                    self.breakpoint.clone(),
24091                    match self.edit_action {
24092                        BreakpointPromptEditAction::Log => {
24093                            BreakpointEditAction::EditLogMessage(message.into())
24094                        }
24095                        BreakpointPromptEditAction::Condition => {
24096                            BreakpointEditAction::EditCondition(message.into())
24097                        }
24098                        BreakpointPromptEditAction::HitCondition => {
24099                            BreakpointEditAction::EditHitCondition(message.into())
24100                        }
24101                    },
24102                    cx,
24103                );
24104
24105                editor.remove_blocks(self.block_ids.clone(), None, cx);
24106                cx.focus_self(window);
24107            });
24108        }
24109    }
24110
24111    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24112        self.editor
24113            .update(cx, |editor, cx| {
24114                editor.remove_blocks(self.block_ids.clone(), None, cx);
24115                window.focus(&editor.focus_handle);
24116            })
24117            .log_err();
24118    }
24119
24120    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24121        let settings = ThemeSettings::get_global(cx);
24122        let text_style = TextStyle {
24123            color: if self.prompt.read(cx).read_only(cx) {
24124                cx.theme().colors().text_disabled
24125            } else {
24126                cx.theme().colors().text
24127            },
24128            font_family: settings.buffer_font.family.clone(),
24129            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24130            font_size: settings.buffer_font_size(cx).into(),
24131            font_weight: settings.buffer_font.weight,
24132            line_height: relative(settings.buffer_line_height.value()),
24133            ..Default::default()
24134        };
24135        EditorElement::new(
24136            &self.prompt,
24137            EditorStyle {
24138                background: cx.theme().colors().editor_background,
24139                local_player: cx.theme().players().local(),
24140                text: text_style,
24141                ..Default::default()
24142            },
24143        )
24144    }
24145}
24146
24147impl Render for BreakpointPromptEditor {
24148    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24149        let editor_margins = *self.editor_margins.lock();
24150        let gutter_dimensions = editor_margins.gutter;
24151        h_flex()
24152            .key_context("Editor")
24153            .bg(cx.theme().colors().editor_background)
24154            .border_y_1()
24155            .border_color(cx.theme().status().info_border)
24156            .size_full()
24157            .py(window.line_height() / 2.5)
24158            .on_action(cx.listener(Self::confirm))
24159            .on_action(cx.listener(Self::cancel))
24160            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24161            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24162    }
24163}
24164
24165impl Focusable for BreakpointPromptEditor {
24166    fn focus_handle(&self, cx: &App) -> FocusHandle {
24167        self.prompt.focus_handle(cx)
24168    }
24169}
24170
24171fn all_edits_insertions_or_deletions(
24172    edits: &Vec<(Range<Anchor>, String)>,
24173    snapshot: &MultiBufferSnapshot,
24174) -> bool {
24175    let mut all_insertions = true;
24176    let mut all_deletions = true;
24177
24178    for (range, new_text) in edits.iter() {
24179        let range_is_empty = range.to_offset(snapshot).is_empty();
24180        let text_is_empty = new_text.is_empty();
24181
24182        if range_is_empty != text_is_empty {
24183            if range_is_empty {
24184                all_deletions = false;
24185            } else {
24186                all_insertions = false;
24187            }
24188        } else {
24189            return false;
24190        }
24191
24192        if !all_insertions && !all_deletions {
24193            return false;
24194        }
24195    }
24196    all_insertions || all_deletions
24197}
24198
24199struct MissingEditPredictionKeybindingTooltip;
24200
24201impl Render for MissingEditPredictionKeybindingTooltip {
24202    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24203        ui::tooltip_container(window, cx, |container, _, cx| {
24204            container
24205                .flex_shrink_0()
24206                .max_w_80()
24207                .min_h(rems_from_px(124.))
24208                .justify_between()
24209                .child(
24210                    v_flex()
24211                        .flex_1()
24212                        .text_ui_sm(cx)
24213                        .child(Label::new("Conflict with Accept Keybinding"))
24214                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24215                )
24216                .child(
24217                    h_flex()
24218                        .pb_1()
24219                        .gap_1()
24220                        .items_end()
24221                        .w_full()
24222                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24223                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24224                        }))
24225                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24226                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24227                        })),
24228                )
24229        })
24230    }
24231}
24232
24233#[derive(Debug, Clone, Copy, PartialEq)]
24234pub struct LineHighlight {
24235    pub background: Background,
24236    pub border: Option<gpui::Hsla>,
24237    pub include_gutter: bool,
24238    pub type_id: Option<TypeId>,
24239}
24240
24241struct LineManipulationResult {
24242    pub new_text: String,
24243    pub line_count_before: usize,
24244    pub line_count_after: usize,
24245}
24246
24247fn render_diff_hunk_controls(
24248    row: u32,
24249    status: &DiffHunkStatus,
24250    hunk_range: Range<Anchor>,
24251    is_created_file: bool,
24252    line_height: Pixels,
24253    editor: &Entity<Editor>,
24254    _window: &mut Window,
24255    cx: &mut App,
24256) -> AnyElement {
24257    h_flex()
24258        .h(line_height)
24259        .mr_1()
24260        .gap_1()
24261        .px_0p5()
24262        .pb_1()
24263        .border_x_1()
24264        .border_b_1()
24265        .border_color(cx.theme().colors().border_variant)
24266        .rounded_b_lg()
24267        .bg(cx.theme().colors().editor_background)
24268        .gap_1()
24269        .block_mouse_except_scroll()
24270        .shadow_md()
24271        .child(if status.has_secondary_hunk() {
24272            Button::new(("stage", row as u64), "Stage")
24273                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24274                .tooltip({
24275                    let focus_handle = editor.focus_handle(cx);
24276                    move |window, cx| {
24277                        Tooltip::for_action_in(
24278                            "Stage Hunk",
24279                            &::git::ToggleStaged,
24280                            &focus_handle,
24281                            window,
24282                            cx,
24283                        )
24284                    }
24285                })
24286                .on_click({
24287                    let editor = editor.clone();
24288                    move |_event, _window, cx| {
24289                        editor.update(cx, |editor, cx| {
24290                            editor.stage_or_unstage_diff_hunks(
24291                                true,
24292                                vec![hunk_range.start..hunk_range.start],
24293                                cx,
24294                            );
24295                        });
24296                    }
24297                })
24298        } else {
24299            Button::new(("unstage", row as u64), "Unstage")
24300                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24301                .tooltip({
24302                    let focus_handle = editor.focus_handle(cx);
24303                    move |window, cx| {
24304                        Tooltip::for_action_in(
24305                            "Unstage Hunk",
24306                            &::git::ToggleStaged,
24307                            &focus_handle,
24308                            window,
24309                            cx,
24310                        )
24311                    }
24312                })
24313                .on_click({
24314                    let editor = editor.clone();
24315                    move |_event, _window, cx| {
24316                        editor.update(cx, |editor, cx| {
24317                            editor.stage_or_unstage_diff_hunks(
24318                                false,
24319                                vec![hunk_range.start..hunk_range.start],
24320                                cx,
24321                            );
24322                        });
24323                    }
24324                })
24325        })
24326        .child(
24327            Button::new(("restore", row as u64), "Restore")
24328                .tooltip({
24329                    let focus_handle = editor.focus_handle(cx);
24330                    move |window, cx| {
24331                        Tooltip::for_action_in(
24332                            "Restore Hunk",
24333                            &::git::Restore,
24334                            &focus_handle,
24335                            window,
24336                            cx,
24337                        )
24338                    }
24339                })
24340                .on_click({
24341                    let editor = editor.clone();
24342                    move |_event, window, cx| {
24343                        editor.update(cx, |editor, cx| {
24344                            let snapshot = editor.snapshot(window, cx);
24345                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24346                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24347                        });
24348                    }
24349                })
24350                .disabled(is_created_file),
24351        )
24352        .when(
24353            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24354            |el| {
24355                el.child(
24356                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24357                        .shape(IconButtonShape::Square)
24358                        .icon_size(IconSize::Small)
24359                        // .disabled(!has_multiple_hunks)
24360                        .tooltip({
24361                            let focus_handle = editor.focus_handle(cx);
24362                            move |window, cx| {
24363                                Tooltip::for_action_in(
24364                                    "Next Hunk",
24365                                    &GoToHunk,
24366                                    &focus_handle,
24367                                    window,
24368                                    cx,
24369                                )
24370                            }
24371                        })
24372                        .on_click({
24373                            let editor = editor.clone();
24374                            move |_event, window, cx| {
24375                                editor.update(cx, |editor, cx| {
24376                                    let snapshot = editor.snapshot(window, cx);
24377                                    let position =
24378                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24379                                    editor.go_to_hunk_before_or_after_position(
24380                                        &snapshot,
24381                                        position,
24382                                        Direction::Next,
24383                                        window,
24384                                        cx,
24385                                    );
24386                                    editor.expand_selected_diff_hunks(cx);
24387                                });
24388                            }
24389                        }),
24390                )
24391                .child(
24392                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24393                        .shape(IconButtonShape::Square)
24394                        .icon_size(IconSize::Small)
24395                        // .disabled(!has_multiple_hunks)
24396                        .tooltip({
24397                            let focus_handle = editor.focus_handle(cx);
24398                            move |window, cx| {
24399                                Tooltip::for_action_in(
24400                                    "Previous Hunk",
24401                                    &GoToPreviousHunk,
24402                                    &focus_handle,
24403                                    window,
24404                                    cx,
24405                                )
24406                            }
24407                        })
24408                        .on_click({
24409                            let editor = editor.clone();
24410                            move |_event, window, cx| {
24411                                editor.update(cx, |editor, cx| {
24412                                    let snapshot = editor.snapshot(window, cx);
24413                                    let point =
24414                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24415                                    editor.go_to_hunk_before_or_after_position(
24416                                        &snapshot,
24417                                        point,
24418                                        Direction::Prev,
24419                                        window,
24420                                        cx,
24421                                    );
24422                                    editor.expand_selected_diff_hunks(cx);
24423                                });
24424                            }
24425                        }),
24426                )
24427            },
24428        )
24429        .into_any_element()
24430}
24431
24432pub fn multibuffer_context_lines(cx: &App) -> u32 {
24433    EditorSettings::try_get(cx)
24434        .map(|settings| settings.excerpt_context_lines)
24435        .unwrap_or(2)
24436        .min(32)
24437}