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 rem_size = window.rem_size();
18915            self.display_map.update(cx, |map, cx| {
18916                map.set_font(
18917                    style.text.font(),
18918                    style.text.font_size.to_pixels(rem_size),
18919                    cx,
18920                )
18921            });
18922        }
18923        self.style = Some(style);
18924    }
18925
18926    pub fn style(&self) -> Option<&EditorStyle> {
18927        self.style.as_ref()
18928    }
18929
18930    // Called by the element. This method is not designed to be called outside of the editor
18931    // element's layout code because it does not notify when rewrapping is computed synchronously.
18932    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18933        if self.is_empty(cx) {
18934            self.placeholder_display_map
18935                .as_ref()
18936                .map_or(false, |display_map| {
18937                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
18938                })
18939        } else {
18940            self.display_map
18941                .update(cx, |map, cx| map.set_wrap_width(width, cx))
18942        }
18943    }
18944
18945    pub fn set_soft_wrap(&mut self) {
18946        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18947    }
18948
18949    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18950        if self.soft_wrap_mode_override.is_some() {
18951            self.soft_wrap_mode_override.take();
18952        } else {
18953            let soft_wrap = match self.soft_wrap_mode(cx) {
18954                SoftWrap::GitDiff => return,
18955                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18956                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18957                    language_settings::SoftWrap::None
18958                }
18959            };
18960            self.soft_wrap_mode_override = Some(soft_wrap);
18961        }
18962        cx.notify();
18963    }
18964
18965    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18966        let Some(workspace) = self.workspace() else {
18967            return;
18968        };
18969        let fs = workspace.read(cx).app_state().fs.clone();
18970        let current_show = TabBarSettings::get_global(cx).show;
18971        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18972            setting.show = Some(!current_show);
18973        });
18974    }
18975
18976    pub fn toggle_indent_guides(
18977        &mut self,
18978        _: &ToggleIndentGuides,
18979        _: &mut Window,
18980        cx: &mut Context<Self>,
18981    ) {
18982        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18983            self.buffer
18984                .read(cx)
18985                .language_settings(cx)
18986                .indent_guides
18987                .enabled
18988        });
18989        self.show_indent_guides = Some(!currently_enabled);
18990        cx.notify();
18991    }
18992
18993    fn should_show_indent_guides(&self) -> Option<bool> {
18994        self.show_indent_guides
18995    }
18996
18997    pub fn toggle_line_numbers(
18998        &mut self,
18999        _: &ToggleLineNumbers,
19000        _: &mut Window,
19001        cx: &mut Context<Self>,
19002    ) {
19003        let mut editor_settings = EditorSettings::get_global(cx).clone();
19004        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19005        EditorSettings::override_global(editor_settings, cx);
19006    }
19007
19008    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19009        if let Some(show_line_numbers) = self.show_line_numbers {
19010            return show_line_numbers;
19011        }
19012        EditorSettings::get_global(cx).gutter.line_numbers
19013    }
19014
19015    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19016        self.use_relative_line_numbers
19017            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19018    }
19019
19020    pub fn toggle_relative_line_numbers(
19021        &mut self,
19022        _: &ToggleRelativeLineNumbers,
19023        _: &mut Window,
19024        cx: &mut Context<Self>,
19025    ) {
19026        let is_relative = self.should_use_relative_line_numbers(cx);
19027        self.set_relative_line_number(Some(!is_relative), cx)
19028    }
19029
19030    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19031        self.use_relative_line_numbers = is_relative;
19032        cx.notify();
19033    }
19034
19035    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19036        self.show_gutter = show_gutter;
19037        cx.notify();
19038    }
19039
19040    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19041        self.show_scrollbars = ScrollbarAxes {
19042            horizontal: show,
19043            vertical: show,
19044        };
19045        cx.notify();
19046    }
19047
19048    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19049        self.show_scrollbars.vertical = show;
19050        cx.notify();
19051    }
19052
19053    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19054        self.show_scrollbars.horizontal = show;
19055        cx.notify();
19056    }
19057
19058    pub fn set_minimap_visibility(
19059        &mut self,
19060        minimap_visibility: MinimapVisibility,
19061        window: &mut Window,
19062        cx: &mut Context<Self>,
19063    ) {
19064        if self.minimap_visibility != minimap_visibility {
19065            if minimap_visibility.visible() && self.minimap.is_none() {
19066                let minimap_settings = EditorSettings::get_global(cx).minimap;
19067                self.minimap =
19068                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19069            }
19070            self.minimap_visibility = minimap_visibility;
19071            cx.notify();
19072        }
19073    }
19074
19075    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19076        self.set_show_scrollbars(false, cx);
19077        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19078    }
19079
19080    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19081        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19082    }
19083
19084    /// Normally the text in full mode and auto height editors is padded on the
19085    /// left side by roughly half a character width for improved hit testing.
19086    ///
19087    /// Use this method to disable this for cases where this is not wanted (e.g.
19088    /// if you want to align the editor text with some other text above or below)
19089    /// or if you want to add this padding to single-line editors.
19090    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19091        self.offset_content = offset_content;
19092        cx.notify();
19093    }
19094
19095    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19096        self.show_line_numbers = Some(show_line_numbers);
19097        cx.notify();
19098    }
19099
19100    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19101        self.disable_expand_excerpt_buttons = true;
19102        cx.notify();
19103    }
19104
19105    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19106        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19107        cx.notify();
19108    }
19109
19110    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19111        self.show_code_actions = Some(show_code_actions);
19112        cx.notify();
19113    }
19114
19115    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19116        self.show_runnables = Some(show_runnables);
19117        cx.notify();
19118    }
19119
19120    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19121        self.show_breakpoints = Some(show_breakpoints);
19122        cx.notify();
19123    }
19124
19125    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19126        if self.display_map.read(cx).masked != masked {
19127            self.display_map.update(cx, |map, _| map.masked = masked);
19128        }
19129        cx.notify()
19130    }
19131
19132    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19133        self.show_wrap_guides = Some(show_wrap_guides);
19134        cx.notify();
19135    }
19136
19137    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19138        self.show_indent_guides = Some(show_indent_guides);
19139        cx.notify();
19140    }
19141
19142    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19143        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19144            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19145                && let Some(dir) = file.abs_path(cx).parent()
19146            {
19147                return Some(dir.to_owned());
19148            }
19149
19150            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19151                return Some(project_path.path.to_path_buf());
19152            }
19153        }
19154
19155        None
19156    }
19157
19158    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19159        self.active_excerpt(cx)?
19160            .1
19161            .read(cx)
19162            .file()
19163            .and_then(|f| f.as_local())
19164    }
19165
19166    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19167        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19168            let buffer = buffer.read(cx);
19169            if let Some(project_path) = buffer.project_path(cx) {
19170                let project = self.project()?.read(cx);
19171                project.absolute_path(&project_path, cx)
19172            } else {
19173                buffer
19174                    .file()
19175                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19176            }
19177        })
19178    }
19179
19180    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19181        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19182            let project_path = buffer.read(cx).project_path(cx)?;
19183            let project = self.project()?.read(cx);
19184            let entry = project.entry_for_path(&project_path, cx)?;
19185            let path = entry.path.to_path_buf();
19186            Some(path)
19187        })
19188    }
19189
19190    pub fn reveal_in_finder(
19191        &mut self,
19192        _: &RevealInFileManager,
19193        _window: &mut Window,
19194        cx: &mut Context<Self>,
19195    ) {
19196        if let Some(target) = self.target_file(cx) {
19197            cx.reveal_path(&target.abs_path(cx));
19198        }
19199    }
19200
19201    pub fn copy_path(
19202        &mut self,
19203        _: &zed_actions::workspace::CopyPath,
19204        _window: &mut Window,
19205        cx: &mut Context<Self>,
19206    ) {
19207        if let Some(path) = self.target_file_abs_path(cx)
19208            && let Some(path) = path.to_str()
19209        {
19210            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19211        }
19212    }
19213
19214    pub fn copy_relative_path(
19215        &mut self,
19216        _: &zed_actions::workspace::CopyRelativePath,
19217        _window: &mut Window,
19218        cx: &mut Context<Self>,
19219    ) {
19220        if let Some(path) = self.target_file_path(cx)
19221            && let Some(path) = path.to_str()
19222        {
19223            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19224        }
19225    }
19226
19227    /// Returns the project path for the editor's buffer, if any buffer is
19228    /// opened in the editor.
19229    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19230        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19231            buffer.read(cx).project_path(cx)
19232        } else {
19233            None
19234        }
19235    }
19236
19237    // Returns true if the editor handled a go-to-line request
19238    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19239        maybe!({
19240            let breakpoint_store = self.breakpoint_store.as_ref()?;
19241
19242            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19243            else {
19244                self.clear_row_highlights::<ActiveDebugLine>();
19245                return None;
19246            };
19247
19248            let position = active_stack_frame.position;
19249            let buffer_id = position.buffer_id?;
19250            let snapshot = self
19251                .project
19252                .as_ref()?
19253                .read(cx)
19254                .buffer_for_id(buffer_id, cx)?
19255                .read(cx)
19256                .snapshot();
19257
19258            let mut handled = false;
19259            for (id, ExcerptRange { context, .. }) in
19260                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19261            {
19262                if context.start.cmp(&position, &snapshot).is_ge()
19263                    || context.end.cmp(&position, &snapshot).is_lt()
19264                {
19265                    continue;
19266                }
19267                let snapshot = self.buffer.read(cx).snapshot(cx);
19268                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19269
19270                handled = true;
19271                self.clear_row_highlights::<ActiveDebugLine>();
19272
19273                self.go_to_line::<ActiveDebugLine>(
19274                    multibuffer_anchor,
19275                    Some(cx.theme().colors().editor_debugger_active_line_background),
19276                    window,
19277                    cx,
19278                );
19279
19280                cx.notify();
19281            }
19282
19283            handled.then_some(())
19284        })
19285        .is_some()
19286    }
19287
19288    pub fn copy_file_name_without_extension(
19289        &mut self,
19290        _: &CopyFileNameWithoutExtension,
19291        _: &mut Window,
19292        cx: &mut Context<Self>,
19293    ) {
19294        if let Some(file) = self.target_file(cx)
19295            && let Some(file_stem) = file.path().file_stem()
19296            && let Some(name) = file_stem.to_str()
19297        {
19298            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19299        }
19300    }
19301
19302    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19303        if let Some(file) = self.target_file(cx)
19304            && let Some(file_name) = file.path().file_name()
19305            && let Some(name) = file_name.to_str()
19306        {
19307            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19308        }
19309    }
19310
19311    pub fn toggle_git_blame(
19312        &mut self,
19313        _: &::git::Blame,
19314        window: &mut Window,
19315        cx: &mut Context<Self>,
19316    ) {
19317        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19318
19319        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19320            self.start_git_blame(true, window, cx);
19321        }
19322
19323        cx.notify();
19324    }
19325
19326    pub fn toggle_git_blame_inline(
19327        &mut self,
19328        _: &ToggleGitBlameInline,
19329        window: &mut Window,
19330        cx: &mut Context<Self>,
19331    ) {
19332        self.toggle_git_blame_inline_internal(true, window, cx);
19333        cx.notify();
19334    }
19335
19336    pub fn open_git_blame_commit(
19337        &mut self,
19338        _: &OpenGitBlameCommit,
19339        window: &mut Window,
19340        cx: &mut Context<Self>,
19341    ) {
19342        self.open_git_blame_commit_internal(window, cx);
19343    }
19344
19345    fn open_git_blame_commit_internal(
19346        &mut self,
19347        window: &mut Window,
19348        cx: &mut Context<Self>,
19349    ) -> Option<()> {
19350        let blame = self.blame.as_ref()?;
19351        let snapshot = self.snapshot(window, cx);
19352        let cursor = self.selections.newest::<Point>(cx).head();
19353        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19354        let (_, blame_entry) = blame
19355            .update(cx, |blame, cx| {
19356                blame
19357                    .blame_for_rows(
19358                        &[RowInfo {
19359                            buffer_id: Some(buffer.remote_id()),
19360                            buffer_row: Some(point.row),
19361                            ..Default::default()
19362                        }],
19363                        cx,
19364                    )
19365                    .next()
19366            })
19367            .flatten()?;
19368        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19369        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19370        let workspace = self.workspace()?.downgrade();
19371        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19372        None
19373    }
19374
19375    pub fn git_blame_inline_enabled(&self) -> bool {
19376        self.git_blame_inline_enabled
19377    }
19378
19379    pub fn toggle_selection_menu(
19380        &mut self,
19381        _: &ToggleSelectionMenu,
19382        _: &mut Window,
19383        cx: &mut Context<Self>,
19384    ) {
19385        self.show_selection_menu = self
19386            .show_selection_menu
19387            .map(|show_selections_menu| !show_selections_menu)
19388            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19389
19390        cx.notify();
19391    }
19392
19393    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19394        self.show_selection_menu
19395            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19396    }
19397
19398    fn start_git_blame(
19399        &mut self,
19400        user_triggered: bool,
19401        window: &mut Window,
19402        cx: &mut Context<Self>,
19403    ) {
19404        if let Some(project) = self.project() {
19405            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19406                && buffer.read(cx).file().is_none()
19407            {
19408                return;
19409            }
19410
19411            let focused = self.focus_handle(cx).contains_focused(window, cx);
19412
19413            let project = project.clone();
19414            let blame = cx
19415                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19416            self.blame_subscription =
19417                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19418            self.blame = Some(blame);
19419        }
19420    }
19421
19422    fn toggle_git_blame_inline_internal(
19423        &mut self,
19424        user_triggered: bool,
19425        window: &mut Window,
19426        cx: &mut Context<Self>,
19427    ) {
19428        if self.git_blame_inline_enabled {
19429            self.git_blame_inline_enabled = false;
19430            self.show_git_blame_inline = false;
19431            self.show_git_blame_inline_delay_task.take();
19432        } else {
19433            self.git_blame_inline_enabled = true;
19434            self.start_git_blame_inline(user_triggered, window, cx);
19435        }
19436
19437        cx.notify();
19438    }
19439
19440    fn start_git_blame_inline(
19441        &mut self,
19442        user_triggered: bool,
19443        window: &mut Window,
19444        cx: &mut Context<Self>,
19445    ) {
19446        self.start_git_blame(user_triggered, window, cx);
19447
19448        if ProjectSettings::get_global(cx)
19449            .git
19450            .inline_blame_delay()
19451            .is_some()
19452        {
19453            self.start_inline_blame_timer(window, cx);
19454        } else {
19455            self.show_git_blame_inline = true
19456        }
19457    }
19458
19459    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19460        self.blame.as_ref()
19461    }
19462
19463    pub fn show_git_blame_gutter(&self) -> bool {
19464        self.show_git_blame_gutter
19465    }
19466
19467    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19468        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19469    }
19470
19471    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19472        self.show_git_blame_inline
19473            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19474            && !self.newest_selection_head_on_empty_line(cx)
19475            && self.has_blame_entries(cx)
19476    }
19477
19478    fn has_blame_entries(&self, cx: &App) -> bool {
19479        self.blame()
19480            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19481    }
19482
19483    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19484        let cursor_anchor = self.selections.newest_anchor().head();
19485
19486        let snapshot = self.buffer.read(cx).snapshot(cx);
19487        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19488
19489        snapshot.line_len(buffer_row) == 0
19490    }
19491
19492    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19493        let buffer_and_selection = maybe!({
19494            let selection = self.selections.newest::<Point>(cx);
19495            let selection_range = selection.range();
19496
19497            let multi_buffer = self.buffer().read(cx);
19498            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19499            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19500
19501            let (buffer, range, _) = if selection.reversed {
19502                buffer_ranges.first()
19503            } else {
19504                buffer_ranges.last()
19505            }?;
19506
19507            let selection = text::ToPoint::to_point(&range.start, buffer).row
19508                ..text::ToPoint::to_point(&range.end, buffer).row;
19509            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19510        });
19511
19512        let Some((buffer, selection)) = buffer_and_selection else {
19513            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19514        };
19515
19516        let Some(project) = self.project() else {
19517            return Task::ready(Err(anyhow!("editor does not have project")));
19518        };
19519
19520        project.update(cx, |project, cx| {
19521            project.get_permalink_to_line(&buffer, selection, cx)
19522        })
19523    }
19524
19525    pub fn copy_permalink_to_line(
19526        &mut self,
19527        _: &CopyPermalinkToLine,
19528        window: &mut Window,
19529        cx: &mut Context<Self>,
19530    ) {
19531        let permalink_task = self.get_permalink_to_line(cx);
19532        let workspace = self.workspace();
19533
19534        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19535            Ok(permalink) => {
19536                cx.update(|_, cx| {
19537                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19538                })
19539                .ok();
19540            }
19541            Err(err) => {
19542                let message = format!("Failed to copy permalink: {err}");
19543
19544                anyhow::Result::<()>::Err(err).log_err();
19545
19546                if let Some(workspace) = workspace {
19547                    workspace
19548                        .update_in(cx, |workspace, _, cx| {
19549                            struct CopyPermalinkToLine;
19550
19551                            workspace.show_toast(
19552                                Toast::new(
19553                                    NotificationId::unique::<CopyPermalinkToLine>(),
19554                                    message,
19555                                ),
19556                                cx,
19557                            )
19558                        })
19559                        .ok();
19560                }
19561            }
19562        })
19563        .detach();
19564    }
19565
19566    pub fn copy_file_location(
19567        &mut self,
19568        _: &CopyFileLocation,
19569        _: &mut Window,
19570        cx: &mut Context<Self>,
19571    ) {
19572        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19573        if let Some(file) = self.target_file(cx)
19574            && let Some(path) = file.path().to_str()
19575        {
19576            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19577        }
19578    }
19579
19580    pub fn open_permalink_to_line(
19581        &mut self,
19582        _: &OpenPermalinkToLine,
19583        window: &mut Window,
19584        cx: &mut Context<Self>,
19585    ) {
19586        let permalink_task = self.get_permalink_to_line(cx);
19587        let workspace = self.workspace();
19588
19589        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19590            Ok(permalink) => {
19591                cx.update(|_, cx| {
19592                    cx.open_url(permalink.as_ref());
19593                })
19594                .ok();
19595            }
19596            Err(err) => {
19597                let message = format!("Failed to open permalink: {err}");
19598
19599                anyhow::Result::<()>::Err(err).log_err();
19600
19601                if let Some(workspace) = workspace {
19602                    workspace
19603                        .update(cx, |workspace, cx| {
19604                            struct OpenPermalinkToLine;
19605
19606                            workspace.show_toast(
19607                                Toast::new(
19608                                    NotificationId::unique::<OpenPermalinkToLine>(),
19609                                    message,
19610                                ),
19611                                cx,
19612                            )
19613                        })
19614                        .ok();
19615                }
19616            }
19617        })
19618        .detach();
19619    }
19620
19621    pub fn insert_uuid_v4(
19622        &mut self,
19623        _: &InsertUuidV4,
19624        window: &mut Window,
19625        cx: &mut Context<Self>,
19626    ) {
19627        self.insert_uuid(UuidVersion::V4, window, cx);
19628    }
19629
19630    pub fn insert_uuid_v7(
19631        &mut self,
19632        _: &InsertUuidV7,
19633        window: &mut Window,
19634        cx: &mut Context<Self>,
19635    ) {
19636        self.insert_uuid(UuidVersion::V7, window, cx);
19637    }
19638
19639    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19640        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19641        self.transact(window, cx, |this, window, cx| {
19642            let edits = this
19643                .selections
19644                .all::<Point>(cx)
19645                .into_iter()
19646                .map(|selection| {
19647                    let uuid = match version {
19648                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19649                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19650                    };
19651
19652                    (selection.range(), uuid.to_string())
19653                });
19654            this.edit(edits, cx);
19655            this.refresh_edit_prediction(true, false, window, cx);
19656        });
19657    }
19658
19659    pub fn open_selections_in_multibuffer(
19660        &mut self,
19661        _: &OpenSelectionsInMultibuffer,
19662        window: &mut Window,
19663        cx: &mut Context<Self>,
19664    ) {
19665        let multibuffer = self.buffer.read(cx);
19666
19667        let Some(buffer) = multibuffer.as_singleton() else {
19668            return;
19669        };
19670
19671        let Some(workspace) = self.workspace() else {
19672            return;
19673        };
19674
19675        let title = multibuffer.title(cx).to_string();
19676
19677        let locations = self
19678            .selections
19679            .all_anchors(cx)
19680            .iter()
19681            .map(|selection| Location {
19682                buffer: buffer.clone(),
19683                range: selection.start.text_anchor..selection.end.text_anchor,
19684            })
19685            .collect::<Vec<_>>();
19686
19687        cx.spawn_in(window, async move |_, cx| {
19688            workspace.update_in(cx, |workspace, window, cx| {
19689                Self::open_locations_in_multibuffer(
19690                    workspace,
19691                    locations,
19692                    format!("Selections for '{title}'"),
19693                    false,
19694                    MultibufferSelectionMode::All,
19695                    window,
19696                    cx,
19697                );
19698            })
19699        })
19700        .detach();
19701    }
19702
19703    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19704    /// last highlight added will be used.
19705    ///
19706    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19707    pub fn highlight_rows<T: 'static>(
19708        &mut self,
19709        range: Range<Anchor>,
19710        color: Hsla,
19711        options: RowHighlightOptions,
19712        cx: &mut Context<Self>,
19713    ) {
19714        let snapshot = self.buffer().read(cx).snapshot(cx);
19715        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19716        let ix = row_highlights.binary_search_by(|highlight| {
19717            Ordering::Equal
19718                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19719                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19720        });
19721
19722        if let Err(mut ix) = ix {
19723            let index = post_inc(&mut self.highlight_order);
19724
19725            // If this range intersects with the preceding highlight, then merge it with
19726            // the preceding highlight. Otherwise insert a new highlight.
19727            let mut merged = false;
19728            if ix > 0 {
19729                let prev_highlight = &mut row_highlights[ix - 1];
19730                if prev_highlight
19731                    .range
19732                    .end
19733                    .cmp(&range.start, &snapshot)
19734                    .is_ge()
19735                {
19736                    ix -= 1;
19737                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19738                        prev_highlight.range.end = range.end;
19739                    }
19740                    merged = true;
19741                    prev_highlight.index = index;
19742                    prev_highlight.color = color;
19743                    prev_highlight.options = options;
19744                }
19745            }
19746
19747            if !merged {
19748                row_highlights.insert(
19749                    ix,
19750                    RowHighlight {
19751                        range,
19752                        index,
19753                        color,
19754                        options,
19755                        type_id: TypeId::of::<T>(),
19756                    },
19757                );
19758            }
19759
19760            // If any of the following highlights intersect with this one, merge them.
19761            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19762                let highlight = &row_highlights[ix];
19763                if next_highlight
19764                    .range
19765                    .start
19766                    .cmp(&highlight.range.end, &snapshot)
19767                    .is_le()
19768                {
19769                    if next_highlight
19770                        .range
19771                        .end
19772                        .cmp(&highlight.range.end, &snapshot)
19773                        .is_gt()
19774                    {
19775                        row_highlights[ix].range.end = next_highlight.range.end;
19776                    }
19777                    row_highlights.remove(ix + 1);
19778                } else {
19779                    break;
19780                }
19781            }
19782        }
19783    }
19784
19785    /// Remove any highlighted row ranges of the given type that intersect the
19786    /// given ranges.
19787    pub fn remove_highlighted_rows<T: 'static>(
19788        &mut self,
19789        ranges_to_remove: Vec<Range<Anchor>>,
19790        cx: &mut Context<Self>,
19791    ) {
19792        let snapshot = self.buffer().read(cx).snapshot(cx);
19793        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19794        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19795        row_highlights.retain(|highlight| {
19796            while let Some(range_to_remove) = ranges_to_remove.peek() {
19797                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19798                    Ordering::Less | Ordering::Equal => {
19799                        ranges_to_remove.next();
19800                    }
19801                    Ordering::Greater => {
19802                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19803                            Ordering::Less | Ordering::Equal => {
19804                                return false;
19805                            }
19806                            Ordering::Greater => break,
19807                        }
19808                    }
19809                }
19810            }
19811
19812            true
19813        })
19814    }
19815
19816    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19817    pub fn clear_row_highlights<T: 'static>(&mut self) {
19818        self.highlighted_rows.remove(&TypeId::of::<T>());
19819    }
19820
19821    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19822    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19823        self.highlighted_rows
19824            .get(&TypeId::of::<T>())
19825            .map_or(&[] as &[_], |vec| vec.as_slice())
19826            .iter()
19827            .map(|highlight| (highlight.range.clone(), highlight.color))
19828    }
19829
19830    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19831    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19832    /// Allows to ignore certain kinds of highlights.
19833    pub fn highlighted_display_rows(
19834        &self,
19835        window: &mut Window,
19836        cx: &mut App,
19837    ) -> BTreeMap<DisplayRow, LineHighlight> {
19838        let snapshot = self.snapshot(window, cx);
19839        let mut used_highlight_orders = HashMap::default();
19840        self.highlighted_rows
19841            .iter()
19842            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19843            .fold(
19844                BTreeMap::<DisplayRow, LineHighlight>::new(),
19845                |mut unique_rows, highlight| {
19846                    let start = highlight.range.start.to_display_point(&snapshot);
19847                    let end = highlight.range.end.to_display_point(&snapshot);
19848                    let start_row = start.row().0;
19849                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19850                        && end.column() == 0
19851                    {
19852                        end.row().0.saturating_sub(1)
19853                    } else {
19854                        end.row().0
19855                    };
19856                    for row in start_row..=end_row {
19857                        let used_index =
19858                            used_highlight_orders.entry(row).or_insert(highlight.index);
19859                        if highlight.index >= *used_index {
19860                            *used_index = highlight.index;
19861                            unique_rows.insert(
19862                                DisplayRow(row),
19863                                LineHighlight {
19864                                    include_gutter: highlight.options.include_gutter,
19865                                    border: None,
19866                                    background: highlight.color.into(),
19867                                    type_id: Some(highlight.type_id),
19868                                },
19869                            );
19870                        }
19871                    }
19872                    unique_rows
19873                },
19874            )
19875    }
19876
19877    pub fn highlighted_display_row_for_autoscroll(
19878        &self,
19879        snapshot: &DisplaySnapshot,
19880    ) -> Option<DisplayRow> {
19881        self.highlighted_rows
19882            .values()
19883            .flat_map(|highlighted_rows| highlighted_rows.iter())
19884            .filter_map(|highlight| {
19885                if highlight.options.autoscroll {
19886                    Some(highlight.range.start.to_display_point(snapshot).row())
19887                } else {
19888                    None
19889                }
19890            })
19891            .min()
19892    }
19893
19894    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19895        self.highlight_background::<SearchWithinRange>(
19896            ranges,
19897            |colors| colors.colors().editor_document_highlight_read_background,
19898            cx,
19899        )
19900    }
19901
19902    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19903        self.breadcrumb_header = Some(new_header);
19904    }
19905
19906    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19907        self.clear_background_highlights::<SearchWithinRange>(cx);
19908    }
19909
19910    pub fn highlight_background<T: 'static>(
19911        &mut self,
19912        ranges: &[Range<Anchor>],
19913        color_fetcher: fn(&Theme) -> Hsla,
19914        cx: &mut Context<Self>,
19915    ) {
19916        self.background_highlights.insert(
19917            HighlightKey::Type(TypeId::of::<T>()),
19918            (color_fetcher, Arc::from(ranges)),
19919        );
19920        self.scrollbar_marker_state.dirty = true;
19921        cx.notify();
19922    }
19923
19924    pub fn highlight_background_key<T: 'static>(
19925        &mut self,
19926        key: usize,
19927        ranges: &[Range<Anchor>],
19928        color_fetcher: fn(&Theme) -> Hsla,
19929        cx: &mut Context<Self>,
19930    ) {
19931        self.background_highlights.insert(
19932            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19933            (color_fetcher, Arc::from(ranges)),
19934        );
19935        self.scrollbar_marker_state.dirty = true;
19936        cx.notify();
19937    }
19938
19939    pub fn clear_background_highlights<T: 'static>(
19940        &mut self,
19941        cx: &mut Context<Self>,
19942    ) -> Option<BackgroundHighlight> {
19943        let text_highlights = self
19944            .background_highlights
19945            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19946        if !text_highlights.1.is_empty() {
19947            self.scrollbar_marker_state.dirty = true;
19948            cx.notify();
19949        }
19950        Some(text_highlights)
19951    }
19952
19953    pub fn highlight_gutter<T: 'static>(
19954        &mut self,
19955        ranges: impl Into<Vec<Range<Anchor>>>,
19956        color_fetcher: fn(&App) -> Hsla,
19957        cx: &mut Context<Self>,
19958    ) {
19959        self.gutter_highlights
19960            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19961        cx.notify();
19962    }
19963
19964    pub fn clear_gutter_highlights<T: 'static>(
19965        &mut self,
19966        cx: &mut Context<Self>,
19967    ) -> Option<GutterHighlight> {
19968        cx.notify();
19969        self.gutter_highlights.remove(&TypeId::of::<T>())
19970    }
19971
19972    pub fn insert_gutter_highlight<T: 'static>(
19973        &mut self,
19974        range: Range<Anchor>,
19975        color_fetcher: fn(&App) -> Hsla,
19976        cx: &mut Context<Self>,
19977    ) {
19978        let snapshot = self.buffer().read(cx).snapshot(cx);
19979        let mut highlights = self
19980            .gutter_highlights
19981            .remove(&TypeId::of::<T>())
19982            .map(|(_, highlights)| highlights)
19983            .unwrap_or_default();
19984        let ix = highlights.binary_search_by(|highlight| {
19985            Ordering::Equal
19986                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19987                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19988        });
19989        if let Err(ix) = ix {
19990            highlights.insert(ix, range);
19991        }
19992        self.gutter_highlights
19993            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19994    }
19995
19996    pub fn remove_gutter_highlights<T: 'static>(
19997        &mut self,
19998        ranges_to_remove: Vec<Range<Anchor>>,
19999        cx: &mut Context<Self>,
20000    ) {
20001        let snapshot = self.buffer().read(cx).snapshot(cx);
20002        let Some((color_fetcher, mut gutter_highlights)) =
20003            self.gutter_highlights.remove(&TypeId::of::<T>())
20004        else {
20005            return;
20006        };
20007        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20008        gutter_highlights.retain(|highlight| {
20009            while let Some(range_to_remove) = ranges_to_remove.peek() {
20010                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20011                    Ordering::Less | Ordering::Equal => {
20012                        ranges_to_remove.next();
20013                    }
20014                    Ordering::Greater => {
20015                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20016                            Ordering::Less | Ordering::Equal => {
20017                                return false;
20018                            }
20019                            Ordering::Greater => break,
20020                        }
20021                    }
20022                }
20023            }
20024
20025            true
20026        });
20027        self.gutter_highlights
20028            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20029    }
20030
20031    #[cfg(feature = "test-support")]
20032    pub fn all_text_highlights(
20033        &self,
20034        window: &mut Window,
20035        cx: &mut Context<Self>,
20036    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20037        let snapshot = self.snapshot(window, cx);
20038        self.display_map.update(cx, |display_map, _| {
20039            display_map
20040                .all_text_highlights()
20041                .map(|highlight| {
20042                    let (style, ranges) = highlight.as_ref();
20043                    (
20044                        *style,
20045                        ranges
20046                            .iter()
20047                            .map(|range| range.clone().to_display_points(&snapshot))
20048                            .collect(),
20049                    )
20050                })
20051                .collect()
20052        })
20053    }
20054
20055    #[cfg(feature = "test-support")]
20056    pub fn all_text_background_highlights(
20057        &self,
20058        window: &mut Window,
20059        cx: &mut Context<Self>,
20060    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20061        let snapshot = self.snapshot(window, cx);
20062        let buffer = &snapshot.buffer_snapshot;
20063        let start = buffer.anchor_before(0);
20064        let end = buffer.anchor_after(buffer.len());
20065        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20066    }
20067
20068    #[cfg(any(test, feature = "test-support"))]
20069    pub fn sorted_background_highlights_in_range(
20070        &self,
20071        search_range: Range<Anchor>,
20072        display_snapshot: &DisplaySnapshot,
20073        theme: &Theme,
20074    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20075        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20076        res.sort_by(|a, b| {
20077            a.0.start
20078                .cmp(&b.0.start)
20079                .then_with(|| a.0.end.cmp(&b.0.end))
20080                .then_with(|| a.1.cmp(&b.1))
20081        });
20082        res
20083    }
20084
20085    #[cfg(feature = "test-support")]
20086    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20087        let snapshot = self.buffer().read(cx).snapshot(cx);
20088
20089        let highlights = self
20090            .background_highlights
20091            .get(&HighlightKey::Type(TypeId::of::<
20092                items::BufferSearchHighlights,
20093            >()));
20094
20095        if let Some((_color, ranges)) = highlights {
20096            ranges
20097                .iter()
20098                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20099                .collect_vec()
20100        } else {
20101            vec![]
20102        }
20103    }
20104
20105    fn document_highlights_for_position<'a>(
20106        &'a self,
20107        position: Anchor,
20108        buffer: &'a MultiBufferSnapshot,
20109    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20110        let read_highlights = self
20111            .background_highlights
20112            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20113            .map(|h| &h.1);
20114        let write_highlights = self
20115            .background_highlights
20116            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20117            .map(|h| &h.1);
20118        let left_position = position.bias_left(buffer);
20119        let right_position = position.bias_right(buffer);
20120        read_highlights
20121            .into_iter()
20122            .chain(write_highlights)
20123            .flat_map(move |ranges| {
20124                let start_ix = match ranges.binary_search_by(|probe| {
20125                    let cmp = probe.end.cmp(&left_position, buffer);
20126                    if cmp.is_ge() {
20127                        Ordering::Greater
20128                    } else {
20129                        Ordering::Less
20130                    }
20131                }) {
20132                    Ok(i) | Err(i) => i,
20133                };
20134
20135                ranges[start_ix..]
20136                    .iter()
20137                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20138            })
20139    }
20140
20141    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20142        self.background_highlights
20143            .get(&HighlightKey::Type(TypeId::of::<T>()))
20144            .is_some_and(|(_, highlights)| !highlights.is_empty())
20145    }
20146
20147    /// Returns all background highlights for a given range.
20148    ///
20149    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20150    pub fn background_highlights_in_range(
20151        &self,
20152        search_range: Range<Anchor>,
20153        display_snapshot: &DisplaySnapshot,
20154        theme: &Theme,
20155    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20156        let mut results = Vec::new();
20157        for (color_fetcher, ranges) in self.background_highlights.values() {
20158            let color = color_fetcher(theme);
20159            let start_ix = match ranges.binary_search_by(|probe| {
20160                let cmp = probe
20161                    .end
20162                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20163                if cmp.is_gt() {
20164                    Ordering::Greater
20165                } else {
20166                    Ordering::Less
20167                }
20168            }) {
20169                Ok(i) | Err(i) => i,
20170            };
20171            for range in &ranges[start_ix..] {
20172                if range
20173                    .start
20174                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20175                    .is_ge()
20176                {
20177                    break;
20178                }
20179
20180                let start = range.start.to_display_point(display_snapshot);
20181                let end = range.end.to_display_point(display_snapshot);
20182                results.push((start..end, color))
20183            }
20184        }
20185        results
20186    }
20187
20188    pub fn gutter_highlights_in_range(
20189        &self,
20190        search_range: Range<Anchor>,
20191        display_snapshot: &DisplaySnapshot,
20192        cx: &App,
20193    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20194        let mut results = Vec::new();
20195        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20196            let color = color_fetcher(cx);
20197            let start_ix = match ranges.binary_search_by(|probe| {
20198                let cmp = probe
20199                    .end
20200                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20201                if cmp.is_gt() {
20202                    Ordering::Greater
20203                } else {
20204                    Ordering::Less
20205                }
20206            }) {
20207                Ok(i) | Err(i) => i,
20208            };
20209            for range in &ranges[start_ix..] {
20210                if range
20211                    .start
20212                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20213                    .is_ge()
20214                {
20215                    break;
20216                }
20217
20218                let start = range.start.to_display_point(display_snapshot);
20219                let end = range.end.to_display_point(display_snapshot);
20220                results.push((start..end, color))
20221            }
20222        }
20223        results
20224    }
20225
20226    /// Get the text ranges corresponding to the redaction query
20227    pub fn redacted_ranges(
20228        &self,
20229        search_range: Range<Anchor>,
20230        display_snapshot: &DisplaySnapshot,
20231        cx: &App,
20232    ) -> Vec<Range<DisplayPoint>> {
20233        display_snapshot
20234            .buffer_snapshot
20235            .redacted_ranges(search_range, |file| {
20236                if let Some(file) = file {
20237                    file.is_private()
20238                        && EditorSettings::get(
20239                            Some(SettingsLocation {
20240                                worktree_id: file.worktree_id(cx),
20241                                path: file.path().as_ref(),
20242                            }),
20243                            cx,
20244                        )
20245                        .redact_private_values
20246                } else {
20247                    false
20248                }
20249            })
20250            .map(|range| {
20251                range.start.to_display_point(display_snapshot)
20252                    ..range.end.to_display_point(display_snapshot)
20253            })
20254            .collect()
20255    }
20256
20257    pub fn highlight_text_key<T: 'static>(
20258        &mut self,
20259        key: usize,
20260        ranges: Vec<Range<Anchor>>,
20261        style: HighlightStyle,
20262        cx: &mut Context<Self>,
20263    ) {
20264        self.display_map.update(cx, |map, _| {
20265            map.highlight_text(
20266                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20267                ranges,
20268                style,
20269            );
20270        });
20271        cx.notify();
20272    }
20273
20274    pub fn highlight_text<T: 'static>(
20275        &mut self,
20276        ranges: Vec<Range<Anchor>>,
20277        style: HighlightStyle,
20278        cx: &mut Context<Self>,
20279    ) {
20280        self.display_map.update(cx, |map, _| {
20281            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20282        });
20283        cx.notify();
20284    }
20285
20286    pub(crate) fn highlight_inlays<T: 'static>(
20287        &mut self,
20288        highlights: Vec<InlayHighlight>,
20289        style: HighlightStyle,
20290        cx: &mut Context<Self>,
20291    ) {
20292        self.display_map.update(cx, |map, _| {
20293            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20294        });
20295        cx.notify();
20296    }
20297
20298    pub fn text_highlights<'a, T: 'static>(
20299        &'a self,
20300        cx: &'a App,
20301    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20302        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20303    }
20304
20305    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20306        let cleared = self
20307            .display_map
20308            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20309        if cleared {
20310            cx.notify();
20311        }
20312    }
20313
20314    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20315        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20316            && self.focus_handle.is_focused(window)
20317    }
20318
20319    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20320        self.show_cursor_when_unfocused = is_enabled;
20321        cx.notify();
20322    }
20323
20324    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20325        cx.notify();
20326    }
20327
20328    fn on_debug_session_event(
20329        &mut self,
20330        _session: Entity<Session>,
20331        event: &SessionEvent,
20332        cx: &mut Context<Self>,
20333    ) {
20334        if let SessionEvent::InvalidateInlineValue = event {
20335            self.refresh_inline_values(cx);
20336        }
20337    }
20338
20339    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20340        let Some(project) = self.project.clone() else {
20341            return;
20342        };
20343
20344        if !self.inline_value_cache.enabled {
20345            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20346            self.splice_inlays(&inlays, Vec::new(), cx);
20347            return;
20348        }
20349
20350        let current_execution_position = self
20351            .highlighted_rows
20352            .get(&TypeId::of::<ActiveDebugLine>())
20353            .and_then(|lines| lines.last().map(|line| line.range.end));
20354
20355        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20356            let inline_values = editor
20357                .update(cx, |editor, cx| {
20358                    let Some(current_execution_position) = current_execution_position else {
20359                        return Some(Task::ready(Ok(Vec::new())));
20360                    };
20361
20362                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20363                        let snapshot = buffer.snapshot(cx);
20364
20365                        let excerpt = snapshot.excerpt_containing(
20366                            current_execution_position..current_execution_position,
20367                        )?;
20368
20369                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20370                    })?;
20371
20372                    let range =
20373                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20374
20375                    project.inline_values(buffer, range, cx)
20376                })
20377                .ok()
20378                .flatten()?
20379                .await
20380                .context("refreshing debugger inlays")
20381                .log_err()?;
20382
20383            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20384
20385            for (buffer_id, inline_value) in inline_values
20386                .into_iter()
20387                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20388            {
20389                buffer_inline_values
20390                    .entry(buffer_id)
20391                    .or_default()
20392                    .push(inline_value);
20393            }
20394
20395            editor
20396                .update(cx, |editor, cx| {
20397                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20398                    let mut new_inlays = Vec::default();
20399
20400                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20401                        let buffer_id = buffer_snapshot.remote_id();
20402                        buffer_inline_values
20403                            .get(&buffer_id)
20404                            .into_iter()
20405                            .flatten()
20406                            .for_each(|hint| {
20407                                let inlay = Inlay::debugger(
20408                                    post_inc(&mut editor.next_inlay_id),
20409                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20410                                    hint.text(),
20411                                );
20412                                if !inlay.text.chars().contains(&'\n') {
20413                                    new_inlays.push(inlay);
20414                                }
20415                            });
20416                    }
20417
20418                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20419                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20420
20421                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20422                })
20423                .ok()?;
20424            Some(())
20425        });
20426    }
20427
20428    fn on_buffer_event(
20429        &mut self,
20430        multibuffer: &Entity<MultiBuffer>,
20431        event: &multi_buffer::Event,
20432        window: &mut Window,
20433        cx: &mut Context<Self>,
20434    ) {
20435        match event {
20436            multi_buffer::Event::Edited {
20437                singleton_buffer_edited,
20438                edited_buffer,
20439            } => {
20440                self.scrollbar_marker_state.dirty = true;
20441                self.active_indent_guides_state.dirty = true;
20442                self.refresh_active_diagnostics(cx);
20443                self.refresh_code_actions(window, cx);
20444                self.refresh_selected_text_highlights(true, window, cx);
20445                self.refresh_single_line_folds(window, cx);
20446                refresh_matching_bracket_highlights(self, window, cx);
20447                if self.has_active_edit_prediction() {
20448                    self.update_visible_edit_prediction(window, cx);
20449                }
20450                if let Some(project) = self.project.as_ref()
20451                    && let Some(edited_buffer) = edited_buffer
20452                {
20453                    project.update(cx, |project, cx| {
20454                        self.registered_buffers
20455                            .entry(edited_buffer.read(cx).remote_id())
20456                            .or_insert_with(|| {
20457                                project.register_buffer_with_language_servers(edited_buffer, cx)
20458                            });
20459                    });
20460                }
20461                cx.emit(EditorEvent::BufferEdited);
20462                cx.emit(SearchEvent::MatchesInvalidated);
20463
20464                if let Some(buffer) = edited_buffer {
20465                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20466                }
20467
20468                if *singleton_buffer_edited {
20469                    if let Some(buffer) = edited_buffer
20470                        && buffer.read(cx).file().is_none()
20471                    {
20472                        cx.emit(EditorEvent::TitleChanged);
20473                    }
20474                    if let Some(project) = &self.project {
20475                        #[allow(clippy::mutable_key_type)]
20476                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20477                            multibuffer
20478                                .all_buffers()
20479                                .into_iter()
20480                                .filter_map(|buffer| {
20481                                    buffer.update(cx, |buffer, cx| {
20482                                        let language = buffer.language()?;
20483                                        let should_discard = project.update(cx, |project, cx| {
20484                                            project.is_local()
20485                                                && !project.has_language_servers_for(buffer, cx)
20486                                        });
20487                                        should_discard.not().then_some(language.clone())
20488                                    })
20489                                })
20490                                .collect::<HashSet<_>>()
20491                        });
20492                        if !languages_affected.is_empty() {
20493                            self.refresh_inlay_hints(
20494                                InlayHintRefreshReason::BufferEdited(languages_affected),
20495                                cx,
20496                            );
20497                        }
20498                    }
20499                }
20500
20501                let Some(project) = &self.project else { return };
20502                let (telemetry, is_via_ssh) = {
20503                    let project = project.read(cx);
20504                    let telemetry = project.client().telemetry().clone();
20505                    let is_via_ssh = project.is_via_remote_server();
20506                    (telemetry, is_via_ssh)
20507                };
20508                refresh_linked_ranges(self, window, cx);
20509                telemetry.log_edit_event("editor", is_via_ssh);
20510            }
20511            multi_buffer::Event::ExcerptsAdded {
20512                buffer,
20513                predecessor,
20514                excerpts,
20515            } => {
20516                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20517                let buffer_id = buffer.read(cx).remote_id();
20518                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20519                    && let Some(project) = &self.project
20520                {
20521                    update_uncommitted_diff_for_buffer(
20522                        cx.entity(),
20523                        project,
20524                        [buffer.clone()],
20525                        self.buffer.clone(),
20526                        cx,
20527                    )
20528                    .detach();
20529                }
20530                self.update_lsp_data(false, Some(buffer_id), window, cx);
20531                cx.emit(EditorEvent::ExcerptsAdded {
20532                    buffer: buffer.clone(),
20533                    predecessor: *predecessor,
20534                    excerpts: excerpts.clone(),
20535                });
20536                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20537            }
20538            multi_buffer::Event::ExcerptsRemoved {
20539                ids,
20540                removed_buffer_ids,
20541            } => {
20542                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20543                let buffer = self.buffer.read(cx);
20544                self.registered_buffers
20545                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20546                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20547                cx.emit(EditorEvent::ExcerptsRemoved {
20548                    ids: ids.clone(),
20549                    removed_buffer_ids: removed_buffer_ids.clone(),
20550                });
20551            }
20552            multi_buffer::Event::ExcerptsEdited {
20553                excerpt_ids,
20554                buffer_ids,
20555            } => {
20556                self.display_map.update(cx, |map, cx| {
20557                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20558                });
20559                cx.emit(EditorEvent::ExcerptsEdited {
20560                    ids: excerpt_ids.clone(),
20561                });
20562            }
20563            multi_buffer::Event::ExcerptsExpanded { ids } => {
20564                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20565                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20566            }
20567            multi_buffer::Event::Reparsed(buffer_id) => {
20568                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20569                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20570
20571                cx.emit(EditorEvent::Reparsed(*buffer_id));
20572            }
20573            multi_buffer::Event::DiffHunksToggled => {
20574                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20575            }
20576            multi_buffer::Event::LanguageChanged(buffer_id) => {
20577                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20578                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20579                cx.emit(EditorEvent::Reparsed(*buffer_id));
20580                cx.notify();
20581            }
20582            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20583            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20584            multi_buffer::Event::FileHandleChanged
20585            | multi_buffer::Event::Reloaded
20586            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20587            multi_buffer::Event::DiagnosticsUpdated => {
20588                self.update_diagnostics_state(window, cx);
20589            }
20590            _ => {}
20591        };
20592    }
20593
20594    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20595        if !self.diagnostics_enabled() {
20596            return;
20597        }
20598        self.refresh_active_diagnostics(cx);
20599        self.refresh_inline_diagnostics(true, window, cx);
20600        self.scrollbar_marker_state.dirty = true;
20601        cx.notify();
20602    }
20603
20604    pub fn start_temporary_diff_override(&mut self) {
20605        self.load_diff_task.take();
20606        self.temporary_diff_override = true;
20607    }
20608
20609    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20610        self.temporary_diff_override = false;
20611        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20612        self.buffer.update(cx, |buffer, cx| {
20613            buffer.set_all_diff_hunks_collapsed(cx);
20614        });
20615
20616        if let Some(project) = self.project.clone() {
20617            self.load_diff_task = Some(
20618                update_uncommitted_diff_for_buffer(
20619                    cx.entity(),
20620                    &project,
20621                    self.buffer.read(cx).all_buffers(),
20622                    self.buffer.clone(),
20623                    cx,
20624                )
20625                .shared(),
20626            );
20627        }
20628    }
20629
20630    fn on_display_map_changed(
20631        &mut self,
20632        _: Entity<DisplayMap>,
20633        _: &mut Window,
20634        cx: &mut Context<Self>,
20635    ) {
20636        cx.notify();
20637    }
20638
20639    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20640        if self.diagnostics_enabled() {
20641            let new_severity = EditorSettings::get_global(cx)
20642                .diagnostics_max_severity
20643                .unwrap_or(DiagnosticSeverity::Hint);
20644            self.set_max_diagnostics_severity(new_severity, cx);
20645        }
20646        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20647        self.update_edit_prediction_settings(cx);
20648        self.refresh_edit_prediction(true, false, window, cx);
20649        self.refresh_inline_values(cx);
20650        self.refresh_inlay_hints(
20651            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20652                self.selections.newest_anchor().head(),
20653                &self.buffer.read(cx).snapshot(cx),
20654                cx,
20655            )),
20656            cx,
20657        );
20658
20659        let old_cursor_shape = self.cursor_shape;
20660        let old_show_breadcrumbs = self.show_breadcrumbs;
20661
20662        {
20663            let editor_settings = EditorSettings::get_global(cx);
20664            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20665            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20666            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20667            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20668        }
20669
20670        if old_cursor_shape != self.cursor_shape {
20671            cx.emit(EditorEvent::CursorShapeChanged);
20672        }
20673
20674        if old_show_breadcrumbs != self.show_breadcrumbs {
20675            cx.emit(EditorEvent::BreadcrumbsChanged);
20676        }
20677
20678        let project_settings = ProjectSettings::get_global(cx);
20679        self.serialize_dirty_buffers =
20680            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20681
20682        if self.mode.is_full() {
20683            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20684            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20685            if self.show_inline_diagnostics != show_inline_diagnostics {
20686                self.show_inline_diagnostics = show_inline_diagnostics;
20687                self.refresh_inline_diagnostics(false, window, cx);
20688            }
20689
20690            if self.git_blame_inline_enabled != inline_blame_enabled {
20691                self.toggle_git_blame_inline_internal(false, window, cx);
20692            }
20693
20694            let minimap_settings = EditorSettings::get_global(cx).minimap;
20695            if self.minimap_visibility != MinimapVisibility::Disabled {
20696                if self.minimap_visibility.settings_visibility()
20697                    != minimap_settings.minimap_enabled()
20698                {
20699                    self.set_minimap_visibility(
20700                        MinimapVisibility::for_mode(self.mode(), cx),
20701                        window,
20702                        cx,
20703                    );
20704                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20705                    minimap_entity.update(cx, |minimap_editor, cx| {
20706                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20707                    })
20708                }
20709            }
20710        }
20711
20712        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20713            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20714        }) {
20715            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20716                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20717            }
20718            self.refresh_colors(false, None, window, cx);
20719        }
20720
20721        cx.notify();
20722    }
20723
20724    pub fn set_searchable(&mut self, searchable: bool) {
20725        self.searchable = searchable;
20726    }
20727
20728    pub fn searchable(&self) -> bool {
20729        self.searchable
20730    }
20731
20732    fn open_proposed_changes_editor(
20733        &mut self,
20734        _: &OpenProposedChangesEditor,
20735        window: &mut Window,
20736        cx: &mut Context<Self>,
20737    ) {
20738        let Some(workspace) = self.workspace() else {
20739            cx.propagate();
20740            return;
20741        };
20742
20743        let selections = self.selections.all::<usize>(cx);
20744        let multi_buffer = self.buffer.read(cx);
20745        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20746        let mut new_selections_by_buffer = HashMap::default();
20747        for selection in selections {
20748            for (buffer, range, _) in
20749                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20750            {
20751                let mut range = range.to_point(buffer);
20752                range.start.column = 0;
20753                range.end.column = buffer.line_len(range.end.row);
20754                new_selections_by_buffer
20755                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20756                    .or_insert(Vec::new())
20757                    .push(range)
20758            }
20759        }
20760
20761        let proposed_changes_buffers = new_selections_by_buffer
20762            .into_iter()
20763            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20764            .collect::<Vec<_>>();
20765        let proposed_changes_editor = cx.new(|cx| {
20766            ProposedChangesEditor::new(
20767                "Proposed changes",
20768                proposed_changes_buffers,
20769                self.project.clone(),
20770                window,
20771                cx,
20772            )
20773        });
20774
20775        window.defer(cx, move |window, cx| {
20776            workspace.update(cx, |workspace, cx| {
20777                workspace.active_pane().update(cx, |pane, cx| {
20778                    pane.add_item(
20779                        Box::new(proposed_changes_editor),
20780                        true,
20781                        true,
20782                        None,
20783                        window,
20784                        cx,
20785                    );
20786                });
20787            });
20788        });
20789    }
20790
20791    pub fn open_excerpts_in_split(
20792        &mut self,
20793        _: &OpenExcerptsSplit,
20794        window: &mut Window,
20795        cx: &mut Context<Self>,
20796    ) {
20797        self.open_excerpts_common(None, true, window, cx)
20798    }
20799
20800    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20801        self.open_excerpts_common(None, false, window, cx)
20802    }
20803
20804    fn open_excerpts_common(
20805        &mut self,
20806        jump_data: Option<JumpData>,
20807        split: bool,
20808        window: &mut Window,
20809        cx: &mut Context<Self>,
20810    ) {
20811        let Some(workspace) = self.workspace() else {
20812            cx.propagate();
20813            return;
20814        };
20815
20816        if self.buffer.read(cx).is_singleton() {
20817            cx.propagate();
20818            return;
20819        }
20820
20821        let mut new_selections_by_buffer = HashMap::default();
20822        match &jump_data {
20823            Some(JumpData::MultiBufferPoint {
20824                excerpt_id,
20825                position,
20826                anchor,
20827                line_offset_from_top,
20828            }) => {
20829                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20830                if let Some(buffer) = multi_buffer_snapshot
20831                    .buffer_id_for_excerpt(*excerpt_id)
20832                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20833                {
20834                    let buffer_snapshot = buffer.read(cx).snapshot();
20835                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20836                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20837                    } else {
20838                        buffer_snapshot.clip_point(*position, Bias::Left)
20839                    };
20840                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20841                    new_selections_by_buffer.insert(
20842                        buffer,
20843                        (
20844                            vec![jump_to_offset..jump_to_offset],
20845                            Some(*line_offset_from_top),
20846                        ),
20847                    );
20848                }
20849            }
20850            Some(JumpData::MultiBufferRow {
20851                row,
20852                line_offset_from_top,
20853            }) => {
20854                let point = MultiBufferPoint::new(row.0, 0);
20855                if let Some((buffer, buffer_point, _)) =
20856                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20857                {
20858                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20859                    new_selections_by_buffer
20860                        .entry(buffer)
20861                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20862                        .0
20863                        .push(buffer_offset..buffer_offset)
20864                }
20865            }
20866            None => {
20867                let selections = self.selections.all::<usize>(cx);
20868                let multi_buffer = self.buffer.read(cx);
20869                for selection in selections {
20870                    for (snapshot, range, _, anchor) in multi_buffer
20871                        .snapshot(cx)
20872                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20873                    {
20874                        if let Some(anchor) = anchor {
20875                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20876                            else {
20877                                continue;
20878                            };
20879                            let offset = text::ToOffset::to_offset(
20880                                &anchor.text_anchor,
20881                                &buffer_handle.read(cx).snapshot(),
20882                            );
20883                            let range = offset..offset;
20884                            new_selections_by_buffer
20885                                .entry(buffer_handle)
20886                                .or_insert((Vec::new(), None))
20887                                .0
20888                                .push(range)
20889                        } else {
20890                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20891                            else {
20892                                continue;
20893                            };
20894                            new_selections_by_buffer
20895                                .entry(buffer_handle)
20896                                .or_insert((Vec::new(), None))
20897                                .0
20898                                .push(range)
20899                        }
20900                    }
20901                }
20902            }
20903        }
20904
20905        new_selections_by_buffer
20906            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20907
20908        if new_selections_by_buffer.is_empty() {
20909            return;
20910        }
20911
20912        // We defer the pane interaction because we ourselves are a workspace item
20913        // and activating a new item causes the pane to call a method on us reentrantly,
20914        // which panics if we're on the stack.
20915        window.defer(cx, move |window, cx| {
20916            workspace.update(cx, |workspace, cx| {
20917                let pane = if split {
20918                    workspace.adjacent_pane(window, cx)
20919                } else {
20920                    workspace.active_pane().clone()
20921                };
20922
20923                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20924                    let editor = buffer
20925                        .read(cx)
20926                        .file()
20927                        .is_none()
20928                        .then(|| {
20929                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20930                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20931                            // Instead, we try to activate the existing editor in the pane first.
20932                            let (editor, pane_item_index) =
20933                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20934                                    let editor = item.downcast::<Editor>()?;
20935                                    let singleton_buffer =
20936                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20937                                    if singleton_buffer == buffer {
20938                                        Some((editor, i))
20939                                    } else {
20940                                        None
20941                                    }
20942                                })?;
20943                            pane.update(cx, |pane, cx| {
20944                                pane.activate_item(pane_item_index, true, true, window, cx)
20945                            });
20946                            Some(editor)
20947                        })
20948                        .flatten()
20949                        .unwrap_or_else(|| {
20950                            workspace.open_project_item::<Self>(
20951                                pane.clone(),
20952                                buffer,
20953                                true,
20954                                true,
20955                                window,
20956                                cx,
20957                            )
20958                        });
20959
20960                    editor.update(cx, |editor, cx| {
20961                        let autoscroll = match scroll_offset {
20962                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20963                            None => Autoscroll::newest(),
20964                        };
20965                        let nav_history = editor.nav_history.take();
20966                        editor.change_selections(
20967                            SelectionEffects::scroll(autoscroll),
20968                            window,
20969                            cx,
20970                            |s| {
20971                                s.select_ranges(ranges);
20972                            },
20973                        );
20974                        editor.nav_history = nav_history;
20975                    });
20976                }
20977            })
20978        });
20979    }
20980
20981    // For now, don't allow opening excerpts in buffers that aren't backed by
20982    // regular project files.
20983    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20984        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20985    }
20986
20987    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20988        let snapshot = self.buffer.read(cx).read(cx);
20989        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20990        Some(
20991            ranges
20992                .iter()
20993                .map(move |range| {
20994                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20995                })
20996                .collect(),
20997        )
20998    }
20999
21000    fn selection_replacement_ranges(
21001        &self,
21002        range: Range<OffsetUtf16>,
21003        cx: &mut App,
21004    ) -> Vec<Range<OffsetUtf16>> {
21005        let selections = self.selections.all::<OffsetUtf16>(cx);
21006        let newest_selection = selections
21007            .iter()
21008            .max_by_key(|selection| selection.id)
21009            .unwrap();
21010        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21011        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21012        let snapshot = self.buffer.read(cx).read(cx);
21013        selections
21014            .into_iter()
21015            .map(|mut selection| {
21016                selection.start.0 =
21017                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21018                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21019                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21020                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21021            })
21022            .collect()
21023    }
21024
21025    fn report_editor_event(
21026        &self,
21027        reported_event: ReportEditorEvent,
21028        file_extension: Option<String>,
21029        cx: &App,
21030    ) {
21031        if cfg!(any(test, feature = "test-support")) {
21032            return;
21033        }
21034
21035        let Some(project) = &self.project else { return };
21036
21037        // If None, we are in a file without an extension
21038        let file = self
21039            .buffer
21040            .read(cx)
21041            .as_singleton()
21042            .and_then(|b| b.read(cx).file());
21043        let file_extension = file_extension.or(file
21044            .as_ref()
21045            .and_then(|file| Path::new(file.file_name(cx)).extension())
21046            .and_then(|e| e.to_str())
21047            .map(|a| a.to_string()));
21048
21049        let vim_mode = vim_enabled(cx);
21050
21051        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21052        let copilot_enabled = edit_predictions_provider
21053            == language::language_settings::EditPredictionProvider::Copilot;
21054        let copilot_enabled_for_language = self
21055            .buffer
21056            .read(cx)
21057            .language_settings(cx)
21058            .show_edit_predictions;
21059
21060        let project = project.read(cx);
21061        let event_type = reported_event.event_type();
21062
21063        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21064            telemetry::event!(
21065                event_type,
21066                type = if auto_saved {"autosave"} else {"manual"},
21067                file_extension,
21068                vim_mode,
21069                copilot_enabled,
21070                copilot_enabled_for_language,
21071                edit_predictions_provider,
21072                is_via_ssh = project.is_via_remote_server(),
21073            );
21074        } else {
21075            telemetry::event!(
21076                event_type,
21077                file_extension,
21078                vim_mode,
21079                copilot_enabled,
21080                copilot_enabled_for_language,
21081                edit_predictions_provider,
21082                is_via_ssh = project.is_via_remote_server(),
21083            );
21084        };
21085    }
21086
21087    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21088    /// with each line being an array of {text, highlight} objects.
21089    fn copy_highlight_json(
21090        &mut self,
21091        _: &CopyHighlightJson,
21092        window: &mut Window,
21093        cx: &mut Context<Self>,
21094    ) {
21095        #[derive(Serialize)]
21096        struct Chunk<'a> {
21097            text: String,
21098            highlight: Option<&'a str>,
21099        }
21100
21101        let snapshot = self.buffer.read(cx).snapshot(cx);
21102        let range = self
21103            .selected_text_range(false, window, cx)
21104            .and_then(|selection| {
21105                if selection.range.is_empty() {
21106                    None
21107                } else {
21108                    Some(selection.range)
21109                }
21110            })
21111            .unwrap_or_else(|| 0..snapshot.len());
21112
21113        let chunks = snapshot.chunks(range, true);
21114        let mut lines = Vec::new();
21115        let mut line: VecDeque<Chunk> = VecDeque::new();
21116
21117        let Some(style) = self.style.as_ref() else {
21118            return;
21119        };
21120
21121        for chunk in chunks {
21122            let highlight = chunk
21123                .syntax_highlight_id
21124                .and_then(|id| id.name(&style.syntax));
21125            let mut chunk_lines = chunk.text.split('\n').peekable();
21126            while let Some(text) = chunk_lines.next() {
21127                let mut merged_with_last_token = false;
21128                if let Some(last_token) = line.back_mut()
21129                    && last_token.highlight == highlight
21130                {
21131                    last_token.text.push_str(text);
21132                    merged_with_last_token = true;
21133                }
21134
21135                if !merged_with_last_token {
21136                    line.push_back(Chunk {
21137                        text: text.into(),
21138                        highlight,
21139                    });
21140                }
21141
21142                if chunk_lines.peek().is_some() {
21143                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21144                        line.pop_front();
21145                    }
21146                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21147                        line.pop_back();
21148                    }
21149
21150                    lines.push(mem::take(&mut line));
21151                }
21152            }
21153        }
21154
21155        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21156            return;
21157        };
21158        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21159    }
21160
21161    pub fn open_context_menu(
21162        &mut self,
21163        _: &OpenContextMenu,
21164        window: &mut Window,
21165        cx: &mut Context<Self>,
21166    ) {
21167        self.request_autoscroll(Autoscroll::newest(), cx);
21168        let position = self.selections.newest_display(cx).start;
21169        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21170    }
21171
21172    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21173        &self.inlay_hint_cache
21174    }
21175
21176    pub fn replay_insert_event(
21177        &mut self,
21178        text: &str,
21179        relative_utf16_range: Option<Range<isize>>,
21180        window: &mut Window,
21181        cx: &mut Context<Self>,
21182    ) {
21183        if !self.input_enabled {
21184            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21185            return;
21186        }
21187        if let Some(relative_utf16_range) = relative_utf16_range {
21188            let selections = self.selections.all::<OffsetUtf16>(cx);
21189            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21190                let new_ranges = selections.into_iter().map(|range| {
21191                    let start = OffsetUtf16(
21192                        range
21193                            .head()
21194                            .0
21195                            .saturating_add_signed(relative_utf16_range.start),
21196                    );
21197                    let end = OffsetUtf16(
21198                        range
21199                            .head()
21200                            .0
21201                            .saturating_add_signed(relative_utf16_range.end),
21202                    );
21203                    start..end
21204                });
21205                s.select_ranges(new_ranges);
21206            });
21207        }
21208
21209        self.handle_input(text, window, cx);
21210    }
21211
21212    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21213        let Some(provider) = self.semantics_provider.as_ref() else {
21214            return false;
21215        };
21216
21217        let mut supports = false;
21218        self.buffer().update(cx, |this, cx| {
21219            this.for_each_buffer(|buffer| {
21220                supports |= provider.supports_inlay_hints(buffer, cx);
21221            });
21222        });
21223
21224        supports
21225    }
21226
21227    pub fn is_focused(&self, window: &Window) -> bool {
21228        self.focus_handle.is_focused(window)
21229    }
21230
21231    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21232        cx.emit(EditorEvent::Focused);
21233
21234        if let Some(descendant) = self
21235            .last_focused_descendant
21236            .take()
21237            .and_then(|descendant| descendant.upgrade())
21238        {
21239            window.focus(&descendant);
21240        } else {
21241            if let Some(blame) = self.blame.as_ref() {
21242                blame.update(cx, GitBlame::focus)
21243            }
21244
21245            self.blink_manager.update(cx, BlinkManager::enable);
21246            self.show_cursor_names(window, cx);
21247            self.buffer.update(cx, |buffer, cx| {
21248                buffer.finalize_last_transaction(cx);
21249                if self.leader_id.is_none() {
21250                    buffer.set_active_selections(
21251                        &self.selections.disjoint_anchors(),
21252                        self.selections.line_mode,
21253                        self.cursor_shape,
21254                        cx,
21255                    );
21256                }
21257            });
21258        }
21259    }
21260
21261    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21262        cx.emit(EditorEvent::FocusedIn)
21263    }
21264
21265    fn handle_focus_out(
21266        &mut self,
21267        event: FocusOutEvent,
21268        _window: &mut Window,
21269        cx: &mut Context<Self>,
21270    ) {
21271        if event.blurred != self.focus_handle {
21272            self.last_focused_descendant = Some(event.blurred);
21273        }
21274        self.selection_drag_state = SelectionDragState::None;
21275        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21276    }
21277
21278    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21279        self.blink_manager.update(cx, BlinkManager::disable);
21280        self.buffer
21281            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21282
21283        if let Some(blame) = self.blame.as_ref() {
21284            blame.update(cx, GitBlame::blur)
21285        }
21286        if !self.hover_state.focused(window, cx) {
21287            hide_hover(self, cx);
21288        }
21289        if !self
21290            .context_menu
21291            .borrow()
21292            .as_ref()
21293            .is_some_and(|context_menu| context_menu.focused(window, cx))
21294        {
21295            self.hide_context_menu(window, cx);
21296        }
21297        self.discard_edit_prediction(false, cx);
21298        cx.emit(EditorEvent::Blurred);
21299        cx.notify();
21300    }
21301
21302    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21303        let mut pending: String = window
21304            .pending_input_keystrokes()
21305            .into_iter()
21306            .flatten()
21307            .filter_map(|keystroke| {
21308                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21309                    keystroke.key_char.clone()
21310                } else {
21311                    None
21312                }
21313            })
21314            .collect();
21315
21316        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21317            pending = "".to_string();
21318        }
21319
21320        let existing_pending = self
21321            .text_highlights::<PendingInput>(cx)
21322            .map(|(_, ranges)| ranges.to_vec());
21323        if existing_pending.is_none() && pending.is_empty() {
21324            return;
21325        }
21326        let transaction =
21327            self.transact(window, cx, |this, window, cx| {
21328                let selections = this.selections.all::<usize>(cx);
21329                let edits = selections
21330                    .iter()
21331                    .map(|selection| (selection.end..selection.end, pending.clone()));
21332                this.edit(edits, cx);
21333                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21334                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21335                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21336                    }));
21337                });
21338                if let Some(existing_ranges) = existing_pending {
21339                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21340                    this.edit(edits, cx);
21341                }
21342            });
21343
21344        let snapshot = self.snapshot(window, cx);
21345        let ranges = self
21346            .selections
21347            .all::<usize>(cx)
21348            .into_iter()
21349            .map(|selection| {
21350                snapshot.buffer_snapshot.anchor_after(selection.end)
21351                    ..snapshot
21352                        .buffer_snapshot
21353                        .anchor_before(selection.end + pending.len())
21354            })
21355            .collect();
21356
21357        if pending.is_empty() {
21358            self.clear_highlights::<PendingInput>(cx);
21359        } else {
21360            self.highlight_text::<PendingInput>(
21361                ranges,
21362                HighlightStyle {
21363                    underline: Some(UnderlineStyle {
21364                        thickness: px(1.),
21365                        color: None,
21366                        wavy: false,
21367                    }),
21368                    ..Default::default()
21369                },
21370                cx,
21371            );
21372        }
21373
21374        self.ime_transaction = self.ime_transaction.or(transaction);
21375        if let Some(transaction) = self.ime_transaction {
21376            self.buffer.update(cx, |buffer, cx| {
21377                buffer.group_until_transaction(transaction, cx);
21378            });
21379        }
21380
21381        if self.text_highlights::<PendingInput>(cx).is_none() {
21382            self.ime_transaction.take();
21383        }
21384    }
21385
21386    pub fn register_action_renderer(
21387        &mut self,
21388        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21389    ) -> Subscription {
21390        let id = self.next_editor_action_id.post_inc();
21391        self.editor_actions
21392            .borrow_mut()
21393            .insert(id, Box::new(listener));
21394
21395        let editor_actions = self.editor_actions.clone();
21396        Subscription::new(move || {
21397            editor_actions.borrow_mut().remove(&id);
21398        })
21399    }
21400
21401    pub fn register_action<A: Action>(
21402        &mut self,
21403        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21404    ) -> Subscription {
21405        let id = self.next_editor_action_id.post_inc();
21406        let listener = Arc::new(listener);
21407        self.editor_actions.borrow_mut().insert(
21408            id,
21409            Box::new(move |_, window, _| {
21410                let listener = listener.clone();
21411                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21412                    let action = action.downcast_ref().unwrap();
21413                    if phase == DispatchPhase::Bubble {
21414                        listener(action, window, cx)
21415                    }
21416                })
21417            }),
21418        );
21419
21420        let editor_actions = self.editor_actions.clone();
21421        Subscription::new(move || {
21422            editor_actions.borrow_mut().remove(&id);
21423        })
21424    }
21425
21426    pub fn file_header_size(&self) -> u32 {
21427        FILE_HEADER_HEIGHT
21428    }
21429
21430    pub fn restore(
21431        &mut self,
21432        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21433        window: &mut Window,
21434        cx: &mut Context<Self>,
21435    ) {
21436        let workspace = self.workspace();
21437        let project = self.project();
21438        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21439            let mut tasks = Vec::new();
21440            for (buffer_id, changes) in revert_changes {
21441                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21442                    buffer.update(cx, |buffer, cx| {
21443                        buffer.edit(
21444                            changes
21445                                .into_iter()
21446                                .map(|(range, text)| (range, text.to_string())),
21447                            None,
21448                            cx,
21449                        );
21450                    });
21451
21452                    if let Some(project) =
21453                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21454                    {
21455                        project.update(cx, |project, cx| {
21456                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21457                        })
21458                    }
21459                }
21460            }
21461            tasks
21462        });
21463        cx.spawn_in(window, async move |_, cx| {
21464            for (buffer, task) in save_tasks {
21465                let result = task.await;
21466                if result.is_err() {
21467                    let Some(path) = buffer
21468                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21469                        .ok()
21470                    else {
21471                        continue;
21472                    };
21473                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21474                        let Some(task) = cx
21475                            .update_window_entity(workspace, |workspace, window, cx| {
21476                                workspace
21477                                    .open_path_preview(path, None, false, false, false, window, cx)
21478                            })
21479                            .ok()
21480                        else {
21481                            continue;
21482                        };
21483                        task.await.log_err();
21484                    }
21485                }
21486            }
21487        })
21488        .detach();
21489        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21490            selections.refresh()
21491        });
21492    }
21493
21494    pub fn to_pixel_point(
21495        &self,
21496        source: multi_buffer::Anchor,
21497        editor_snapshot: &EditorSnapshot,
21498        window: &mut Window,
21499    ) -> Option<gpui::Point<Pixels>> {
21500        let source_point = source.to_display_point(editor_snapshot);
21501        self.display_to_pixel_point(source_point, editor_snapshot, window)
21502    }
21503
21504    pub fn display_to_pixel_point(
21505        &self,
21506        source: DisplayPoint,
21507        editor_snapshot: &EditorSnapshot,
21508        window: &mut Window,
21509    ) -> Option<gpui::Point<Pixels>> {
21510        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21511        let text_layout_details = self.text_layout_details(window);
21512        let scroll_top = text_layout_details
21513            .scroll_anchor
21514            .scroll_position(editor_snapshot)
21515            .y;
21516
21517        if source.row().as_f32() < scroll_top.floor() {
21518            return None;
21519        }
21520        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21521        let source_y = line_height * (source.row().as_f32() - scroll_top);
21522        Some(gpui::Point::new(source_x, source_y))
21523    }
21524
21525    pub fn has_visible_completions_menu(&self) -> bool {
21526        !self.edit_prediction_preview_is_active()
21527            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21528                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21529            })
21530    }
21531
21532    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21533        if self.mode.is_minimap() {
21534            return;
21535        }
21536        self.addons
21537            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21538    }
21539
21540    pub fn unregister_addon<T: Addon>(&mut self) {
21541        self.addons.remove(&std::any::TypeId::of::<T>());
21542    }
21543
21544    pub fn addon<T: Addon>(&self) -> Option<&T> {
21545        let type_id = std::any::TypeId::of::<T>();
21546        self.addons
21547            .get(&type_id)
21548            .and_then(|item| item.to_any().downcast_ref::<T>())
21549    }
21550
21551    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21552        let type_id = std::any::TypeId::of::<T>();
21553        self.addons
21554            .get_mut(&type_id)
21555            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21556    }
21557
21558    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21559        let text_layout_details = self.text_layout_details(window);
21560        let style = &text_layout_details.editor_style;
21561        let font_id = window.text_system().resolve_font(&style.text.font());
21562        let font_size = style.text.font_size.to_pixels(window.rem_size());
21563        let line_height = style.text.line_height_in_pixels(window.rem_size());
21564        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21565        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21566
21567        CharacterDimensions {
21568            em_width,
21569            em_advance,
21570            line_height,
21571        }
21572    }
21573
21574    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21575        self.load_diff_task.clone()
21576    }
21577
21578    fn read_metadata_from_db(
21579        &mut self,
21580        item_id: u64,
21581        workspace_id: WorkspaceId,
21582        window: &mut Window,
21583        cx: &mut Context<Editor>,
21584    ) {
21585        if self.is_singleton(cx)
21586            && !self.mode.is_minimap()
21587            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21588        {
21589            let buffer_snapshot = OnceCell::new();
21590
21591            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21592                && !folds.is_empty()
21593            {
21594                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21595                self.fold_ranges(
21596                    folds
21597                        .into_iter()
21598                        .map(|(start, end)| {
21599                            snapshot.clip_offset(start, Bias::Left)
21600                                ..snapshot.clip_offset(end, Bias::Right)
21601                        })
21602                        .collect(),
21603                    false,
21604                    window,
21605                    cx,
21606                );
21607            }
21608
21609            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21610                && !selections.is_empty()
21611            {
21612                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21613                // skip adding the initial selection to selection history
21614                self.selection_history.mode = SelectionHistoryMode::Skipping;
21615                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21616                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21617                        snapshot.clip_offset(start, Bias::Left)
21618                            ..snapshot.clip_offset(end, Bias::Right)
21619                    }));
21620                });
21621                self.selection_history.mode = SelectionHistoryMode::Normal;
21622            };
21623        }
21624
21625        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21626    }
21627
21628    fn update_lsp_data(
21629        &mut self,
21630        ignore_cache: bool,
21631        for_buffer: Option<BufferId>,
21632        window: &mut Window,
21633        cx: &mut Context<'_, Self>,
21634    ) {
21635        self.pull_diagnostics(for_buffer, window, cx);
21636        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21637    }
21638}
21639
21640fn vim_enabled(cx: &App) -> bool {
21641    cx.global::<SettingsStore>()
21642        .raw_user_settings()
21643        .get("vim_mode")
21644        == Some(&serde_json::Value::Bool(true))
21645}
21646
21647fn process_completion_for_edit(
21648    completion: &Completion,
21649    intent: CompletionIntent,
21650    buffer: &Entity<Buffer>,
21651    cursor_position: &text::Anchor,
21652    cx: &mut Context<Editor>,
21653) -> CompletionEdit {
21654    let buffer = buffer.read(cx);
21655    let buffer_snapshot = buffer.snapshot();
21656    let (snippet, new_text) = if completion.is_snippet() {
21657        // Workaround for typescript language server issues so that methods don't expand within
21658        // strings and functions with type expressions. The previous point is used because the query
21659        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21660        let mut snippet_source = completion.new_text.clone();
21661        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21662        previous_point.column = previous_point.column.saturating_sub(1);
21663        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21664            && scope.prefers_label_for_snippet_in_completion()
21665            && let Some(label) = completion.label()
21666            && matches!(
21667                completion.kind(),
21668                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21669            )
21670        {
21671            snippet_source = label;
21672        }
21673        match Snippet::parse(&snippet_source).log_err() {
21674            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21675            None => (None, completion.new_text.clone()),
21676        }
21677    } else {
21678        (None, completion.new_text.clone())
21679    };
21680
21681    let mut range_to_replace = {
21682        let replace_range = &completion.replace_range;
21683        if let CompletionSource::Lsp {
21684            insert_range: Some(insert_range),
21685            ..
21686        } = &completion.source
21687        {
21688            debug_assert_eq!(
21689                insert_range.start, replace_range.start,
21690                "insert_range and replace_range should start at the same position"
21691            );
21692            debug_assert!(
21693                insert_range
21694                    .start
21695                    .cmp(cursor_position, &buffer_snapshot)
21696                    .is_le(),
21697                "insert_range should start before or at cursor position"
21698            );
21699            debug_assert!(
21700                replace_range
21701                    .start
21702                    .cmp(cursor_position, &buffer_snapshot)
21703                    .is_le(),
21704                "replace_range should start before or at cursor position"
21705            );
21706
21707            let should_replace = match intent {
21708                CompletionIntent::CompleteWithInsert => false,
21709                CompletionIntent::CompleteWithReplace => true,
21710                CompletionIntent::Complete | CompletionIntent::Compose => {
21711                    let insert_mode =
21712                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21713                            .completions
21714                            .lsp_insert_mode;
21715                    match insert_mode {
21716                        LspInsertMode::Insert => false,
21717                        LspInsertMode::Replace => true,
21718                        LspInsertMode::ReplaceSubsequence => {
21719                            let mut text_to_replace = buffer.chars_for_range(
21720                                buffer.anchor_before(replace_range.start)
21721                                    ..buffer.anchor_after(replace_range.end),
21722                            );
21723                            let mut current_needle = text_to_replace.next();
21724                            for haystack_ch in completion.label.text.chars() {
21725                                if let Some(needle_ch) = current_needle
21726                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21727                                {
21728                                    current_needle = text_to_replace.next();
21729                                }
21730                            }
21731                            current_needle.is_none()
21732                        }
21733                        LspInsertMode::ReplaceSuffix => {
21734                            if replace_range
21735                                .end
21736                                .cmp(cursor_position, &buffer_snapshot)
21737                                .is_gt()
21738                            {
21739                                let range_after_cursor = *cursor_position..replace_range.end;
21740                                let text_after_cursor = buffer
21741                                    .text_for_range(
21742                                        buffer.anchor_before(range_after_cursor.start)
21743                                            ..buffer.anchor_after(range_after_cursor.end),
21744                                    )
21745                                    .collect::<String>()
21746                                    .to_ascii_lowercase();
21747                                completion
21748                                    .label
21749                                    .text
21750                                    .to_ascii_lowercase()
21751                                    .ends_with(&text_after_cursor)
21752                            } else {
21753                                true
21754                            }
21755                        }
21756                    }
21757                }
21758            };
21759
21760            if should_replace {
21761                replace_range.clone()
21762            } else {
21763                insert_range.clone()
21764            }
21765        } else {
21766            replace_range.clone()
21767        }
21768    };
21769
21770    if range_to_replace
21771        .end
21772        .cmp(cursor_position, &buffer_snapshot)
21773        .is_lt()
21774    {
21775        range_to_replace.end = *cursor_position;
21776    }
21777
21778    CompletionEdit {
21779        new_text,
21780        replace_range: range_to_replace.to_offset(buffer),
21781        snippet,
21782    }
21783}
21784
21785struct CompletionEdit {
21786    new_text: String,
21787    replace_range: Range<usize>,
21788    snippet: Option<Snippet>,
21789}
21790
21791fn insert_extra_newline_brackets(
21792    buffer: &MultiBufferSnapshot,
21793    range: Range<usize>,
21794    language: &language::LanguageScope,
21795) -> bool {
21796    let leading_whitespace_len = buffer
21797        .reversed_chars_at(range.start)
21798        .take_while(|c| c.is_whitespace() && *c != '\n')
21799        .map(|c| c.len_utf8())
21800        .sum::<usize>();
21801    let trailing_whitespace_len = buffer
21802        .chars_at(range.end)
21803        .take_while(|c| c.is_whitespace() && *c != '\n')
21804        .map(|c| c.len_utf8())
21805        .sum::<usize>();
21806    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21807
21808    language.brackets().any(|(pair, enabled)| {
21809        let pair_start = pair.start.trim_end();
21810        let pair_end = pair.end.trim_start();
21811
21812        enabled
21813            && pair.newline
21814            && buffer.contains_str_at(range.end, pair_end)
21815            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21816    })
21817}
21818
21819fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21820    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21821        [(buffer, range, _)] => (*buffer, range.clone()),
21822        _ => return false,
21823    };
21824    let pair = {
21825        let mut result: Option<BracketMatch> = None;
21826
21827        for pair in buffer
21828            .all_bracket_ranges(range.clone())
21829            .filter(move |pair| {
21830                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21831            })
21832        {
21833            let len = pair.close_range.end - pair.open_range.start;
21834
21835            if let Some(existing) = &result {
21836                let existing_len = existing.close_range.end - existing.open_range.start;
21837                if len > existing_len {
21838                    continue;
21839                }
21840            }
21841
21842            result = Some(pair);
21843        }
21844
21845        result
21846    };
21847    let Some(pair) = pair else {
21848        return false;
21849    };
21850    pair.newline_only
21851        && buffer
21852            .chars_for_range(pair.open_range.end..range.start)
21853            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21854            .all(|c| c.is_whitespace() && c != '\n')
21855}
21856
21857fn update_uncommitted_diff_for_buffer(
21858    editor: Entity<Editor>,
21859    project: &Entity<Project>,
21860    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21861    buffer: Entity<MultiBuffer>,
21862    cx: &mut App,
21863) -> Task<()> {
21864    let mut tasks = Vec::new();
21865    project.update(cx, |project, cx| {
21866        for buffer in buffers {
21867            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21868                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21869            }
21870        }
21871    });
21872    cx.spawn(async move |cx| {
21873        let diffs = future::join_all(tasks).await;
21874        if editor
21875            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21876            .unwrap_or(false)
21877        {
21878            return;
21879        }
21880
21881        buffer
21882            .update(cx, |buffer, cx| {
21883                for diff in diffs.into_iter().flatten() {
21884                    buffer.add_diff(diff, cx);
21885                }
21886            })
21887            .ok();
21888    })
21889}
21890
21891fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21892    let tab_size = tab_size.get() as usize;
21893    let mut width = offset;
21894
21895    for ch in text.chars() {
21896        width += if ch == '\t' {
21897            tab_size - (width % tab_size)
21898        } else {
21899            1
21900        };
21901    }
21902
21903    width - offset
21904}
21905
21906#[cfg(test)]
21907mod tests {
21908    use super::*;
21909
21910    #[test]
21911    fn test_string_size_with_expanded_tabs() {
21912        let nz = |val| NonZeroU32::new(val).unwrap();
21913        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21914        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21915        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21916        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21917        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21918        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21919        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21920        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21921    }
21922}
21923
21924/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21925struct WordBreakingTokenizer<'a> {
21926    input: &'a str,
21927}
21928
21929impl<'a> WordBreakingTokenizer<'a> {
21930    fn new(input: &'a str) -> Self {
21931        Self { input }
21932    }
21933}
21934
21935fn is_char_ideographic(ch: char) -> bool {
21936    use unicode_script::Script::*;
21937    use unicode_script::UnicodeScript;
21938    matches!(ch.script(), Han | Tangut | Yi)
21939}
21940
21941fn is_grapheme_ideographic(text: &str) -> bool {
21942    text.chars().any(is_char_ideographic)
21943}
21944
21945fn is_grapheme_whitespace(text: &str) -> bool {
21946    text.chars().any(|x| x.is_whitespace())
21947}
21948
21949fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21950    text.chars()
21951        .next()
21952        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21953}
21954
21955#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21956enum WordBreakToken<'a> {
21957    Word { token: &'a str, grapheme_len: usize },
21958    InlineWhitespace { token: &'a str, grapheme_len: usize },
21959    Newline,
21960}
21961
21962impl<'a> Iterator for WordBreakingTokenizer<'a> {
21963    /// Yields a span, the count of graphemes in the token, and whether it was
21964    /// whitespace. Note that it also breaks at word boundaries.
21965    type Item = WordBreakToken<'a>;
21966
21967    fn next(&mut self) -> Option<Self::Item> {
21968        use unicode_segmentation::UnicodeSegmentation;
21969        if self.input.is_empty() {
21970            return None;
21971        }
21972
21973        let mut iter = self.input.graphemes(true).peekable();
21974        let mut offset = 0;
21975        let mut grapheme_len = 0;
21976        if let Some(first_grapheme) = iter.next() {
21977            let is_newline = first_grapheme == "\n";
21978            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21979            offset += first_grapheme.len();
21980            grapheme_len += 1;
21981            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21982                if let Some(grapheme) = iter.peek().copied()
21983                    && should_stay_with_preceding_ideograph(grapheme)
21984                {
21985                    offset += grapheme.len();
21986                    grapheme_len += 1;
21987                }
21988            } else {
21989                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21990                let mut next_word_bound = words.peek().copied();
21991                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21992                    next_word_bound = words.next();
21993                }
21994                while let Some(grapheme) = iter.peek().copied() {
21995                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21996                        break;
21997                    };
21998                    if is_grapheme_whitespace(grapheme) != is_whitespace
21999                        || (grapheme == "\n") != is_newline
22000                    {
22001                        break;
22002                    };
22003                    offset += grapheme.len();
22004                    grapheme_len += 1;
22005                    iter.next();
22006                }
22007            }
22008            let token = &self.input[..offset];
22009            self.input = &self.input[offset..];
22010            if token == "\n" {
22011                Some(WordBreakToken::Newline)
22012            } else if is_whitespace {
22013                Some(WordBreakToken::InlineWhitespace {
22014                    token,
22015                    grapheme_len,
22016                })
22017            } else {
22018                Some(WordBreakToken::Word {
22019                    token,
22020                    grapheme_len,
22021                })
22022            }
22023        } else {
22024            None
22025        }
22026    }
22027}
22028
22029#[test]
22030fn test_word_breaking_tokenizer() {
22031    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22032        ("", &[]),
22033        ("  ", &[whitespace("  ", 2)]),
22034        ("Ʒ", &[word("Ʒ", 1)]),
22035        ("Ǽ", &[word("Ǽ", 1)]),
22036        ("", &[word("", 1)]),
22037        ("⋑⋑", &[word("⋑⋑", 2)]),
22038        (
22039            "原理,进而",
22040            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22041        ),
22042        (
22043            "hello world",
22044            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22045        ),
22046        (
22047            "hello, world",
22048            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22049        ),
22050        (
22051            "  hello world",
22052            &[
22053                whitespace("  ", 2),
22054                word("hello", 5),
22055                whitespace(" ", 1),
22056                word("world", 5),
22057            ],
22058        ),
22059        (
22060            "这是什么 \n 钢笔",
22061            &[
22062                word("", 1),
22063                word("", 1),
22064                word("", 1),
22065                word("", 1),
22066                whitespace(" ", 1),
22067                newline(),
22068                whitespace(" ", 1),
22069                word("", 1),
22070                word("", 1),
22071            ],
22072        ),
22073        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22074    ];
22075
22076    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22077        WordBreakToken::Word {
22078            token,
22079            grapheme_len,
22080        }
22081    }
22082
22083    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22084        WordBreakToken::InlineWhitespace {
22085            token,
22086            grapheme_len,
22087        }
22088    }
22089
22090    fn newline() -> WordBreakToken<'static> {
22091        WordBreakToken::Newline
22092    }
22093
22094    for (input, result) in tests {
22095        assert_eq!(
22096            WordBreakingTokenizer::new(input)
22097                .collect::<Vec<_>>()
22098                .as_slice(),
22099            *result,
22100        );
22101    }
22102}
22103
22104fn wrap_with_prefix(
22105    first_line_prefix: String,
22106    subsequent_lines_prefix: String,
22107    unwrapped_text: String,
22108    wrap_column: usize,
22109    tab_size: NonZeroU32,
22110    preserve_existing_whitespace: bool,
22111) -> String {
22112    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22113    let subsequent_lines_prefix_len =
22114        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22115    let mut wrapped_text = String::new();
22116    let mut current_line = first_line_prefix;
22117    let mut is_first_line = true;
22118
22119    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22120    let mut current_line_len = first_line_prefix_len;
22121    let mut in_whitespace = false;
22122    for token in tokenizer {
22123        let have_preceding_whitespace = in_whitespace;
22124        match token {
22125            WordBreakToken::Word {
22126                token,
22127                grapheme_len,
22128            } => {
22129                in_whitespace = false;
22130                let current_prefix_len = if is_first_line {
22131                    first_line_prefix_len
22132                } else {
22133                    subsequent_lines_prefix_len
22134                };
22135                if current_line_len + grapheme_len > wrap_column
22136                    && current_line_len != current_prefix_len
22137                {
22138                    wrapped_text.push_str(current_line.trim_end());
22139                    wrapped_text.push('\n');
22140                    is_first_line = false;
22141                    current_line = subsequent_lines_prefix.clone();
22142                    current_line_len = subsequent_lines_prefix_len;
22143                }
22144                current_line.push_str(token);
22145                current_line_len += grapheme_len;
22146            }
22147            WordBreakToken::InlineWhitespace {
22148                mut token,
22149                mut grapheme_len,
22150            } => {
22151                in_whitespace = true;
22152                if have_preceding_whitespace && !preserve_existing_whitespace {
22153                    continue;
22154                }
22155                if !preserve_existing_whitespace {
22156                    token = " ";
22157                    grapheme_len = 1;
22158                }
22159                let current_prefix_len = if is_first_line {
22160                    first_line_prefix_len
22161                } else {
22162                    subsequent_lines_prefix_len
22163                };
22164                if current_line_len + grapheme_len > wrap_column {
22165                    wrapped_text.push_str(current_line.trim_end());
22166                    wrapped_text.push('\n');
22167                    is_first_line = false;
22168                    current_line = subsequent_lines_prefix.clone();
22169                    current_line_len = subsequent_lines_prefix_len;
22170                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22171                    current_line.push_str(token);
22172                    current_line_len += grapheme_len;
22173                }
22174            }
22175            WordBreakToken::Newline => {
22176                in_whitespace = true;
22177                let current_prefix_len = if is_first_line {
22178                    first_line_prefix_len
22179                } else {
22180                    subsequent_lines_prefix_len
22181                };
22182                if preserve_existing_whitespace {
22183                    wrapped_text.push_str(current_line.trim_end());
22184                    wrapped_text.push('\n');
22185                    is_first_line = false;
22186                    current_line = subsequent_lines_prefix.clone();
22187                    current_line_len = subsequent_lines_prefix_len;
22188                } else if have_preceding_whitespace {
22189                    continue;
22190                } else if current_line_len + 1 > wrap_column
22191                    && current_line_len != current_prefix_len
22192                {
22193                    wrapped_text.push_str(current_line.trim_end());
22194                    wrapped_text.push('\n');
22195                    is_first_line = false;
22196                    current_line = subsequent_lines_prefix.clone();
22197                    current_line_len = subsequent_lines_prefix_len;
22198                } else if current_line_len != current_prefix_len {
22199                    current_line.push(' ');
22200                    current_line_len += 1;
22201                }
22202            }
22203        }
22204    }
22205
22206    if !current_line.is_empty() {
22207        wrapped_text.push_str(&current_line);
22208    }
22209    wrapped_text
22210}
22211
22212#[test]
22213fn test_wrap_with_prefix() {
22214    assert_eq!(
22215        wrap_with_prefix(
22216            "# ".to_string(),
22217            "# ".to_string(),
22218            "abcdefg".to_string(),
22219            4,
22220            NonZeroU32::new(4).unwrap(),
22221            false,
22222        ),
22223        "# abcdefg"
22224    );
22225    assert_eq!(
22226        wrap_with_prefix(
22227            "".to_string(),
22228            "".to_string(),
22229            "\thello world".to_string(),
22230            8,
22231            NonZeroU32::new(4).unwrap(),
22232            false,
22233        ),
22234        "hello\nworld"
22235    );
22236    assert_eq!(
22237        wrap_with_prefix(
22238            "// ".to_string(),
22239            "// ".to_string(),
22240            "xx \nyy zz aa bb cc".to_string(),
22241            12,
22242            NonZeroU32::new(4).unwrap(),
22243            false,
22244        ),
22245        "// xx yy zz\n// aa bb cc"
22246    );
22247    assert_eq!(
22248        wrap_with_prefix(
22249            String::new(),
22250            String::new(),
22251            "这是什么 \n 钢笔".to_string(),
22252            3,
22253            NonZeroU32::new(4).unwrap(),
22254            false,
22255        ),
22256        "这是什\n么 钢\n"
22257    );
22258}
22259
22260pub trait CollaborationHub {
22261    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22262    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22263    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22264}
22265
22266impl CollaborationHub for Entity<Project> {
22267    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22268        self.read(cx).collaborators()
22269    }
22270
22271    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22272        self.read(cx).user_store().read(cx).participant_indices()
22273    }
22274
22275    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22276        let this = self.read(cx);
22277        let user_ids = this.collaborators().values().map(|c| c.user_id);
22278        this.user_store().read(cx).participant_names(user_ids, cx)
22279    }
22280}
22281
22282pub trait SemanticsProvider {
22283    fn hover(
22284        &self,
22285        buffer: &Entity<Buffer>,
22286        position: text::Anchor,
22287        cx: &mut App,
22288    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22289
22290    fn inline_values(
22291        &self,
22292        buffer_handle: Entity<Buffer>,
22293        range: Range<text::Anchor>,
22294        cx: &mut App,
22295    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22296
22297    fn inlay_hints(
22298        &self,
22299        buffer_handle: Entity<Buffer>,
22300        range: Range<text::Anchor>,
22301        cx: &mut App,
22302    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22303
22304    fn resolve_inlay_hint(
22305        &self,
22306        hint: InlayHint,
22307        buffer_handle: Entity<Buffer>,
22308        server_id: LanguageServerId,
22309        cx: &mut App,
22310    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22311
22312    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22313
22314    fn document_highlights(
22315        &self,
22316        buffer: &Entity<Buffer>,
22317        position: text::Anchor,
22318        cx: &mut App,
22319    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22320
22321    fn definitions(
22322        &self,
22323        buffer: &Entity<Buffer>,
22324        position: text::Anchor,
22325        kind: GotoDefinitionKind,
22326        cx: &mut App,
22327    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22328
22329    fn range_for_rename(
22330        &self,
22331        buffer: &Entity<Buffer>,
22332        position: text::Anchor,
22333        cx: &mut App,
22334    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22335
22336    fn perform_rename(
22337        &self,
22338        buffer: &Entity<Buffer>,
22339        position: text::Anchor,
22340        new_name: String,
22341        cx: &mut App,
22342    ) -> Option<Task<Result<ProjectTransaction>>>;
22343}
22344
22345pub trait CompletionProvider {
22346    fn completions(
22347        &self,
22348        excerpt_id: ExcerptId,
22349        buffer: &Entity<Buffer>,
22350        buffer_position: text::Anchor,
22351        trigger: CompletionContext,
22352        window: &mut Window,
22353        cx: &mut Context<Editor>,
22354    ) -> Task<Result<Vec<CompletionResponse>>>;
22355
22356    fn resolve_completions(
22357        &self,
22358        _buffer: Entity<Buffer>,
22359        _completion_indices: Vec<usize>,
22360        _completions: Rc<RefCell<Box<[Completion]>>>,
22361        _cx: &mut Context<Editor>,
22362    ) -> Task<Result<bool>> {
22363        Task::ready(Ok(false))
22364    }
22365
22366    fn apply_additional_edits_for_completion(
22367        &self,
22368        _buffer: Entity<Buffer>,
22369        _completions: Rc<RefCell<Box<[Completion]>>>,
22370        _completion_index: usize,
22371        _push_to_history: bool,
22372        _cx: &mut Context<Editor>,
22373    ) -> Task<Result<Option<language::Transaction>>> {
22374        Task::ready(Ok(None))
22375    }
22376
22377    fn is_completion_trigger(
22378        &self,
22379        buffer: &Entity<Buffer>,
22380        position: language::Anchor,
22381        text: &str,
22382        trigger_in_words: bool,
22383        menu_is_open: bool,
22384        cx: &mut Context<Editor>,
22385    ) -> bool;
22386
22387    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22388
22389    fn sort_completions(&self) -> bool {
22390        true
22391    }
22392
22393    fn filter_completions(&self) -> bool {
22394        true
22395    }
22396}
22397
22398pub trait CodeActionProvider {
22399    fn id(&self) -> Arc<str>;
22400
22401    fn code_actions(
22402        &self,
22403        buffer: &Entity<Buffer>,
22404        range: Range<text::Anchor>,
22405        window: &mut Window,
22406        cx: &mut App,
22407    ) -> Task<Result<Vec<CodeAction>>>;
22408
22409    fn apply_code_action(
22410        &self,
22411        buffer_handle: Entity<Buffer>,
22412        action: CodeAction,
22413        excerpt_id: ExcerptId,
22414        push_to_history: bool,
22415        window: &mut Window,
22416        cx: &mut App,
22417    ) -> Task<Result<ProjectTransaction>>;
22418}
22419
22420impl CodeActionProvider for Entity<Project> {
22421    fn id(&self) -> Arc<str> {
22422        "project".into()
22423    }
22424
22425    fn code_actions(
22426        &self,
22427        buffer: &Entity<Buffer>,
22428        range: Range<text::Anchor>,
22429        _window: &mut Window,
22430        cx: &mut App,
22431    ) -> Task<Result<Vec<CodeAction>>> {
22432        self.update(cx, |project, cx| {
22433            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22434            let code_actions = project.code_actions(buffer, range, None, cx);
22435            cx.background_spawn(async move {
22436                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22437                Ok(code_lens_actions
22438                    .context("code lens fetch")?
22439                    .into_iter()
22440                    .flatten()
22441                    .chain(
22442                        code_actions
22443                            .context("code action fetch")?
22444                            .into_iter()
22445                            .flatten(),
22446                    )
22447                    .collect())
22448            })
22449        })
22450    }
22451
22452    fn apply_code_action(
22453        &self,
22454        buffer_handle: Entity<Buffer>,
22455        action: CodeAction,
22456        _excerpt_id: ExcerptId,
22457        push_to_history: bool,
22458        _window: &mut Window,
22459        cx: &mut App,
22460    ) -> Task<Result<ProjectTransaction>> {
22461        self.update(cx, |project, cx| {
22462            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22463        })
22464    }
22465}
22466
22467fn snippet_completions(
22468    project: &Project,
22469    buffer: &Entity<Buffer>,
22470    buffer_position: text::Anchor,
22471    cx: &mut App,
22472) -> Task<Result<CompletionResponse>> {
22473    let languages = buffer.read(cx).languages_at(buffer_position);
22474    let snippet_store = project.snippets().read(cx);
22475
22476    let scopes: Vec<_> = languages
22477        .iter()
22478        .filter_map(|language| {
22479            let language_name = language.lsp_id();
22480            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22481
22482            if snippets.is_empty() {
22483                None
22484            } else {
22485                Some((language.default_scope(), snippets))
22486            }
22487        })
22488        .collect();
22489
22490    if scopes.is_empty() {
22491        return Task::ready(Ok(CompletionResponse {
22492            completions: vec![],
22493            display_options: CompletionDisplayOptions::default(),
22494            is_incomplete: false,
22495        }));
22496    }
22497
22498    let snapshot = buffer.read(cx).text_snapshot();
22499    let chars: String = snapshot
22500        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22501        .collect();
22502    let executor = cx.background_executor().clone();
22503
22504    cx.background_spawn(async move {
22505        let mut is_incomplete = false;
22506        let mut completions: Vec<Completion> = Vec::new();
22507        for (scope, snippets) in scopes.into_iter() {
22508            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22509            let mut last_word = chars
22510                .chars()
22511                .take_while(|c| classifier.is_word(*c))
22512                .collect::<String>();
22513            last_word = last_word.chars().rev().collect();
22514
22515            if last_word.is_empty() {
22516                return Ok(CompletionResponse {
22517                    completions: vec![],
22518                    display_options: CompletionDisplayOptions::default(),
22519                    is_incomplete: true,
22520                });
22521            }
22522
22523            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22524            let to_lsp = |point: &text::Anchor| {
22525                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22526                point_to_lsp(end)
22527            };
22528            let lsp_end = to_lsp(&buffer_position);
22529
22530            let candidates = snippets
22531                .iter()
22532                .enumerate()
22533                .flat_map(|(ix, snippet)| {
22534                    snippet
22535                        .prefix
22536                        .iter()
22537                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22538                })
22539                .collect::<Vec<StringMatchCandidate>>();
22540
22541            const MAX_RESULTS: usize = 100;
22542            let mut matches = fuzzy::match_strings(
22543                &candidates,
22544                &last_word,
22545                last_word.chars().any(|c| c.is_uppercase()),
22546                true,
22547                MAX_RESULTS,
22548                &Default::default(),
22549                executor.clone(),
22550            )
22551            .await;
22552
22553            if matches.len() >= MAX_RESULTS {
22554                is_incomplete = true;
22555            }
22556
22557            // Remove all candidates where the query's start does not match the start of any word in the candidate
22558            if let Some(query_start) = last_word.chars().next() {
22559                matches.retain(|string_match| {
22560                    split_words(&string_match.string).any(|word| {
22561                        // Check that the first codepoint of the word as lowercase matches the first
22562                        // codepoint of the query as lowercase
22563                        word.chars()
22564                            .flat_map(|codepoint| codepoint.to_lowercase())
22565                            .zip(query_start.to_lowercase())
22566                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22567                    })
22568                });
22569            }
22570
22571            let matched_strings = matches
22572                .into_iter()
22573                .map(|m| m.string)
22574                .collect::<HashSet<_>>();
22575
22576            completions.extend(snippets.iter().filter_map(|snippet| {
22577                let matching_prefix = snippet
22578                    .prefix
22579                    .iter()
22580                    .find(|prefix| matched_strings.contains(*prefix))?;
22581                let start = as_offset - last_word.len();
22582                let start = snapshot.anchor_before(start);
22583                let range = start..buffer_position;
22584                let lsp_start = to_lsp(&start);
22585                let lsp_range = lsp::Range {
22586                    start: lsp_start,
22587                    end: lsp_end,
22588                };
22589                Some(Completion {
22590                    replace_range: range,
22591                    new_text: snippet.body.clone(),
22592                    source: CompletionSource::Lsp {
22593                        insert_range: None,
22594                        server_id: LanguageServerId(usize::MAX),
22595                        resolved: true,
22596                        lsp_completion: Box::new(lsp::CompletionItem {
22597                            label: snippet.prefix.first().unwrap().clone(),
22598                            kind: Some(CompletionItemKind::SNIPPET),
22599                            label_details: snippet.description.as_ref().map(|description| {
22600                                lsp::CompletionItemLabelDetails {
22601                                    detail: Some(description.clone()),
22602                                    description: None,
22603                                }
22604                            }),
22605                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22606                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22607                                lsp::InsertReplaceEdit {
22608                                    new_text: snippet.body.clone(),
22609                                    insert: lsp_range,
22610                                    replace: lsp_range,
22611                                },
22612                            )),
22613                            filter_text: Some(snippet.body.clone()),
22614                            sort_text: Some(char::MAX.to_string()),
22615                            ..lsp::CompletionItem::default()
22616                        }),
22617                        lsp_defaults: None,
22618                    },
22619                    label: CodeLabel {
22620                        text: matching_prefix.clone(),
22621                        runs: Vec::new(),
22622                        filter_range: 0..matching_prefix.len(),
22623                    },
22624                    icon_path: None,
22625                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22626                        single_line: snippet.name.clone().into(),
22627                        plain_text: snippet
22628                            .description
22629                            .clone()
22630                            .map(|description| description.into()),
22631                    }),
22632                    insert_text_mode: None,
22633                    confirm: None,
22634                })
22635            }))
22636        }
22637
22638        Ok(CompletionResponse {
22639            completions,
22640            display_options: CompletionDisplayOptions::default(),
22641            is_incomplete,
22642        })
22643    })
22644}
22645
22646impl CompletionProvider for Entity<Project> {
22647    fn completions(
22648        &self,
22649        _excerpt_id: ExcerptId,
22650        buffer: &Entity<Buffer>,
22651        buffer_position: text::Anchor,
22652        options: CompletionContext,
22653        _window: &mut Window,
22654        cx: &mut Context<Editor>,
22655    ) -> Task<Result<Vec<CompletionResponse>>> {
22656        self.update(cx, |project, cx| {
22657            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22658            let project_completions = project.completions(buffer, buffer_position, options, cx);
22659            cx.background_spawn(async move {
22660                let mut responses = project_completions.await?;
22661                let snippets = snippets.await?;
22662                if !snippets.completions.is_empty() {
22663                    responses.push(snippets);
22664                }
22665                Ok(responses)
22666            })
22667        })
22668    }
22669
22670    fn resolve_completions(
22671        &self,
22672        buffer: Entity<Buffer>,
22673        completion_indices: Vec<usize>,
22674        completions: Rc<RefCell<Box<[Completion]>>>,
22675        cx: &mut Context<Editor>,
22676    ) -> Task<Result<bool>> {
22677        self.update(cx, |project, cx| {
22678            project.lsp_store().update(cx, |lsp_store, cx| {
22679                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22680            })
22681        })
22682    }
22683
22684    fn apply_additional_edits_for_completion(
22685        &self,
22686        buffer: Entity<Buffer>,
22687        completions: Rc<RefCell<Box<[Completion]>>>,
22688        completion_index: usize,
22689        push_to_history: bool,
22690        cx: &mut Context<Editor>,
22691    ) -> Task<Result<Option<language::Transaction>>> {
22692        self.update(cx, |project, cx| {
22693            project.lsp_store().update(cx, |lsp_store, cx| {
22694                lsp_store.apply_additional_edits_for_completion(
22695                    buffer,
22696                    completions,
22697                    completion_index,
22698                    push_to_history,
22699                    cx,
22700                )
22701            })
22702        })
22703    }
22704
22705    fn is_completion_trigger(
22706        &self,
22707        buffer: &Entity<Buffer>,
22708        position: language::Anchor,
22709        text: &str,
22710        trigger_in_words: bool,
22711        menu_is_open: bool,
22712        cx: &mut Context<Editor>,
22713    ) -> bool {
22714        let mut chars = text.chars();
22715        let char = if let Some(char) = chars.next() {
22716            char
22717        } else {
22718            return false;
22719        };
22720        if chars.next().is_some() {
22721            return false;
22722        }
22723
22724        let buffer = buffer.read(cx);
22725        let snapshot = buffer.snapshot();
22726        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22727            return false;
22728        }
22729        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22730        if trigger_in_words && classifier.is_word(char) {
22731            return true;
22732        }
22733
22734        buffer.completion_triggers().contains(text)
22735    }
22736}
22737
22738impl SemanticsProvider for Entity<Project> {
22739    fn hover(
22740        &self,
22741        buffer: &Entity<Buffer>,
22742        position: text::Anchor,
22743        cx: &mut App,
22744    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22745        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22746    }
22747
22748    fn document_highlights(
22749        &self,
22750        buffer: &Entity<Buffer>,
22751        position: text::Anchor,
22752        cx: &mut App,
22753    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22754        Some(self.update(cx, |project, cx| {
22755            project.document_highlights(buffer, position, cx)
22756        }))
22757    }
22758
22759    fn definitions(
22760        &self,
22761        buffer: &Entity<Buffer>,
22762        position: text::Anchor,
22763        kind: GotoDefinitionKind,
22764        cx: &mut App,
22765    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22766        Some(self.update(cx, |project, cx| match kind {
22767            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22768            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22769            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22770            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22771        }))
22772    }
22773
22774    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22775        self.update(cx, |project, cx| {
22776            if project
22777                .active_debug_session(cx)
22778                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22779            {
22780                return true;
22781            }
22782
22783            buffer.update(cx, |buffer, cx| {
22784                project.any_language_server_supports_inlay_hints(buffer, cx)
22785            })
22786        })
22787    }
22788
22789    fn inline_values(
22790        &self,
22791        buffer_handle: Entity<Buffer>,
22792        range: Range<text::Anchor>,
22793        cx: &mut App,
22794    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22795        self.update(cx, |project, cx| {
22796            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22797
22798            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22799        })
22800    }
22801
22802    fn inlay_hints(
22803        &self,
22804        buffer_handle: Entity<Buffer>,
22805        range: Range<text::Anchor>,
22806        cx: &mut App,
22807    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22808        Some(self.update(cx, |project, cx| {
22809            project.inlay_hints(buffer_handle, range, cx)
22810        }))
22811    }
22812
22813    fn resolve_inlay_hint(
22814        &self,
22815        hint: InlayHint,
22816        buffer_handle: Entity<Buffer>,
22817        server_id: LanguageServerId,
22818        cx: &mut App,
22819    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22820        Some(self.update(cx, |project, cx| {
22821            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22822        }))
22823    }
22824
22825    fn range_for_rename(
22826        &self,
22827        buffer: &Entity<Buffer>,
22828        position: text::Anchor,
22829        cx: &mut App,
22830    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22831        Some(self.update(cx, |project, cx| {
22832            let buffer = buffer.clone();
22833            let task = project.prepare_rename(buffer.clone(), position, cx);
22834            cx.spawn(async move |_, cx| {
22835                Ok(match task.await? {
22836                    PrepareRenameResponse::Success(range) => Some(range),
22837                    PrepareRenameResponse::InvalidPosition => None,
22838                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22839                        // Fallback on using TreeSitter info to determine identifier range
22840                        buffer.read_with(cx, |buffer, _| {
22841                            let snapshot = buffer.snapshot();
22842                            let (range, kind) = snapshot.surrounding_word(position, false);
22843                            if kind != Some(CharKind::Word) {
22844                                return None;
22845                            }
22846                            Some(
22847                                snapshot.anchor_before(range.start)
22848                                    ..snapshot.anchor_after(range.end),
22849                            )
22850                        })?
22851                    }
22852                })
22853            })
22854        }))
22855    }
22856
22857    fn perform_rename(
22858        &self,
22859        buffer: &Entity<Buffer>,
22860        position: text::Anchor,
22861        new_name: String,
22862        cx: &mut App,
22863    ) -> Option<Task<Result<ProjectTransaction>>> {
22864        Some(self.update(cx, |project, cx| {
22865            project.perform_rename(buffer.clone(), position, new_name, cx)
22866        }))
22867    }
22868}
22869
22870fn inlay_hint_settings(
22871    location: Anchor,
22872    snapshot: &MultiBufferSnapshot,
22873    cx: &mut Context<Editor>,
22874) -> InlayHintSettings {
22875    let file = snapshot.file_at(location);
22876    let language = snapshot.language_at(location).map(|l| l.name());
22877    language_settings(language, file, cx).inlay_hints
22878}
22879
22880fn consume_contiguous_rows(
22881    contiguous_row_selections: &mut Vec<Selection<Point>>,
22882    selection: &Selection<Point>,
22883    display_map: &DisplaySnapshot,
22884    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22885) -> (MultiBufferRow, MultiBufferRow) {
22886    contiguous_row_selections.push(selection.clone());
22887    let start_row = starting_row(selection, display_map);
22888    let mut end_row = ending_row(selection, display_map);
22889
22890    while let Some(next_selection) = selections.peek() {
22891        if next_selection.start.row <= end_row.0 {
22892            end_row = ending_row(next_selection, display_map);
22893            contiguous_row_selections.push(selections.next().unwrap().clone());
22894        } else {
22895            break;
22896        }
22897    }
22898    (start_row, end_row)
22899}
22900
22901fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22902    if selection.start.column > 0 {
22903        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22904    } else {
22905        MultiBufferRow(selection.start.row)
22906    }
22907}
22908
22909fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22910    if next_selection.end.column > 0 || next_selection.is_empty() {
22911        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22912    } else {
22913        MultiBufferRow(next_selection.end.row)
22914    }
22915}
22916
22917impl EditorSnapshot {
22918    pub fn remote_selections_in_range<'a>(
22919        &'a self,
22920        range: &'a Range<Anchor>,
22921        collaboration_hub: &dyn CollaborationHub,
22922        cx: &'a App,
22923    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22924        let participant_names = collaboration_hub.user_names(cx);
22925        let participant_indices = collaboration_hub.user_participant_indices(cx);
22926        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22927        let collaborators_by_replica_id = collaborators_by_peer_id
22928            .values()
22929            .map(|collaborator| (collaborator.replica_id, collaborator))
22930            .collect::<HashMap<_, _>>();
22931        self.buffer_snapshot
22932            .selections_in_range(range, false)
22933            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22934                if replica_id == AGENT_REPLICA_ID {
22935                    Some(RemoteSelection {
22936                        replica_id,
22937                        selection,
22938                        cursor_shape,
22939                        line_mode,
22940                        collaborator_id: CollaboratorId::Agent,
22941                        user_name: Some("Agent".into()),
22942                        color: cx.theme().players().agent(),
22943                    })
22944                } else {
22945                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22946                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22947                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22948                    Some(RemoteSelection {
22949                        replica_id,
22950                        selection,
22951                        cursor_shape,
22952                        line_mode,
22953                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22954                        user_name,
22955                        color: if let Some(index) = participant_index {
22956                            cx.theme().players().color_for_participant(index.0)
22957                        } else {
22958                            cx.theme().players().absent()
22959                        },
22960                    })
22961                }
22962            })
22963    }
22964
22965    pub fn hunks_for_ranges(
22966        &self,
22967        ranges: impl IntoIterator<Item = Range<Point>>,
22968    ) -> Vec<MultiBufferDiffHunk> {
22969        let mut hunks = Vec::new();
22970        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22971            HashMap::default();
22972        for query_range in ranges {
22973            let query_rows =
22974                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22975            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22976                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22977            ) {
22978                // Include deleted hunks that are adjacent to the query range, because
22979                // otherwise they would be missed.
22980                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22981                if hunk.status().is_deleted() {
22982                    intersects_range |= hunk.row_range.start == query_rows.end;
22983                    intersects_range |= hunk.row_range.end == query_rows.start;
22984                }
22985                if intersects_range {
22986                    if !processed_buffer_rows
22987                        .entry(hunk.buffer_id)
22988                        .or_default()
22989                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22990                    {
22991                        continue;
22992                    }
22993                    hunks.push(hunk);
22994                }
22995            }
22996        }
22997
22998        hunks
22999    }
23000
23001    fn display_diff_hunks_for_rows<'a>(
23002        &'a self,
23003        display_rows: Range<DisplayRow>,
23004        folded_buffers: &'a HashSet<BufferId>,
23005    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23006        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23007        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23008
23009        self.buffer_snapshot
23010            .diff_hunks_in_range(buffer_start..buffer_end)
23011            .filter_map(|hunk| {
23012                if folded_buffers.contains(&hunk.buffer_id) {
23013                    return None;
23014                }
23015
23016                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23017                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23018
23019                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23020                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23021
23022                let display_hunk = if hunk_display_start.column() != 0 {
23023                    DisplayDiffHunk::Folded {
23024                        display_row: hunk_display_start.row(),
23025                    }
23026                } else {
23027                    let mut end_row = hunk_display_end.row();
23028                    if hunk_display_end.column() > 0 {
23029                        end_row.0 += 1;
23030                    }
23031                    let is_created_file = hunk.is_created_file();
23032                    DisplayDiffHunk::Unfolded {
23033                        status: hunk.status(),
23034                        diff_base_byte_range: hunk.diff_base_byte_range,
23035                        display_row_range: hunk_display_start.row()..end_row,
23036                        multi_buffer_range: Anchor::range_in_buffer(
23037                            hunk.excerpt_id,
23038                            hunk.buffer_id,
23039                            hunk.buffer_range,
23040                        ),
23041                        is_created_file,
23042                    }
23043                };
23044
23045                Some(display_hunk)
23046            })
23047    }
23048
23049    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23050        self.display_snapshot.buffer_snapshot.language_at(position)
23051    }
23052
23053    pub fn is_focused(&self) -> bool {
23054        self.is_focused
23055    }
23056
23057    pub fn placeholder_text(&self) -> Option<String> {
23058        self.placeholder_display_snapshot
23059            .as_ref()
23060            .map(|display_map| display_map.text())
23061    }
23062
23063    pub fn scroll_position(&self) -> gpui::Point<f32> {
23064        self.scroll_anchor.scroll_position(&self.display_snapshot)
23065    }
23066
23067    fn gutter_dimensions(
23068        &self,
23069        font_id: FontId,
23070        font_size: Pixels,
23071        max_line_number_width: Pixels,
23072        cx: &App,
23073    ) -> Option<GutterDimensions> {
23074        if !self.show_gutter {
23075            return None;
23076        }
23077
23078        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23079        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23080
23081        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23082            matches!(
23083                ProjectSettings::get_global(cx).git.git_gutter,
23084                Some(GitGutterSetting::TrackedFiles)
23085            )
23086        });
23087        let gutter_settings = EditorSettings::get_global(cx).gutter;
23088        let show_line_numbers = self
23089            .show_line_numbers
23090            .unwrap_or(gutter_settings.line_numbers);
23091        let line_gutter_width = if show_line_numbers {
23092            // Avoid flicker-like gutter resizes when the line number gains another digit by
23093            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23094            let min_width_for_number_on_gutter =
23095                ch_advance * gutter_settings.min_line_number_digits as f32;
23096            max_line_number_width.max(min_width_for_number_on_gutter)
23097        } else {
23098            0.0.into()
23099        };
23100
23101        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23102        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23103
23104        let git_blame_entries_width =
23105            self.git_blame_gutter_max_author_length
23106                .map(|max_author_length| {
23107                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23108                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23109
23110                    /// The number of characters to dedicate to gaps and margins.
23111                    const SPACING_WIDTH: usize = 4;
23112
23113                    let max_char_count = max_author_length.min(renderer.max_author_length())
23114                        + ::git::SHORT_SHA_LENGTH
23115                        + MAX_RELATIVE_TIMESTAMP.len()
23116                        + SPACING_WIDTH;
23117
23118                    ch_advance * max_char_count
23119                });
23120
23121        let is_singleton = self.buffer_snapshot.is_singleton();
23122
23123        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23124        left_padding += if !is_singleton {
23125            ch_width * 4.0
23126        } else if show_runnables || show_breakpoints {
23127            ch_width * 3.0
23128        } else if show_git_gutter && show_line_numbers {
23129            ch_width * 2.0
23130        } else if show_git_gutter || show_line_numbers {
23131            ch_width
23132        } else {
23133            px(0.)
23134        };
23135
23136        let shows_folds = is_singleton && gutter_settings.folds;
23137
23138        let right_padding = if shows_folds && show_line_numbers {
23139            ch_width * 4.0
23140        } else if shows_folds || (!is_singleton && show_line_numbers) {
23141            ch_width * 3.0
23142        } else if show_line_numbers {
23143            ch_width
23144        } else {
23145            px(0.)
23146        };
23147
23148        Some(GutterDimensions {
23149            left_padding,
23150            right_padding,
23151            width: line_gutter_width + left_padding + right_padding,
23152            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23153            git_blame_entries_width,
23154        })
23155    }
23156
23157    pub fn render_crease_toggle(
23158        &self,
23159        buffer_row: MultiBufferRow,
23160        row_contains_cursor: bool,
23161        editor: Entity<Editor>,
23162        window: &mut Window,
23163        cx: &mut App,
23164    ) -> Option<AnyElement> {
23165        let folded = self.is_line_folded(buffer_row);
23166        let mut is_foldable = false;
23167
23168        if let Some(crease) = self
23169            .crease_snapshot
23170            .query_row(buffer_row, &self.buffer_snapshot)
23171        {
23172            is_foldable = true;
23173            match crease {
23174                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23175                    if let Some(render_toggle) = render_toggle {
23176                        let toggle_callback =
23177                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23178                                if folded {
23179                                    editor.update(cx, |editor, cx| {
23180                                        editor.fold_at(buffer_row, window, cx)
23181                                    });
23182                                } else {
23183                                    editor.update(cx, |editor, cx| {
23184                                        editor.unfold_at(buffer_row, window, cx)
23185                                    });
23186                                }
23187                            });
23188                        return Some((render_toggle)(
23189                            buffer_row,
23190                            folded,
23191                            toggle_callback,
23192                            window,
23193                            cx,
23194                        ));
23195                    }
23196                }
23197            }
23198        }
23199
23200        is_foldable |= self.starts_indent(buffer_row);
23201
23202        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23203            Some(
23204                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23205                    .toggle_state(folded)
23206                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23207                        if folded {
23208                            this.unfold_at(buffer_row, window, cx);
23209                        } else {
23210                            this.fold_at(buffer_row, window, cx);
23211                        }
23212                    }))
23213                    .into_any_element(),
23214            )
23215        } else {
23216            None
23217        }
23218    }
23219
23220    pub fn render_crease_trailer(
23221        &self,
23222        buffer_row: MultiBufferRow,
23223        window: &mut Window,
23224        cx: &mut App,
23225    ) -> Option<AnyElement> {
23226        let folded = self.is_line_folded(buffer_row);
23227        if let Crease::Inline { render_trailer, .. } = self
23228            .crease_snapshot
23229            .query_row(buffer_row, &self.buffer_snapshot)?
23230        {
23231            let render_trailer = render_trailer.as_ref()?;
23232            Some(render_trailer(buffer_row, folded, window, cx))
23233        } else {
23234            None
23235        }
23236    }
23237}
23238
23239impl Deref for EditorSnapshot {
23240    type Target = DisplaySnapshot;
23241
23242    fn deref(&self) -> &Self::Target {
23243        &self.display_snapshot
23244    }
23245}
23246
23247#[derive(Clone, Debug, PartialEq, Eq)]
23248pub enum EditorEvent {
23249    InputIgnored {
23250        text: Arc<str>,
23251    },
23252    InputHandled {
23253        utf16_range_to_replace: Option<Range<isize>>,
23254        text: Arc<str>,
23255    },
23256    ExcerptsAdded {
23257        buffer: Entity<Buffer>,
23258        predecessor: ExcerptId,
23259        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23260    },
23261    ExcerptsRemoved {
23262        ids: Vec<ExcerptId>,
23263        removed_buffer_ids: Vec<BufferId>,
23264    },
23265    BufferFoldToggled {
23266        ids: Vec<ExcerptId>,
23267        folded: bool,
23268    },
23269    ExcerptsEdited {
23270        ids: Vec<ExcerptId>,
23271    },
23272    ExcerptsExpanded {
23273        ids: Vec<ExcerptId>,
23274    },
23275    BufferEdited,
23276    Edited {
23277        transaction_id: clock::Lamport,
23278    },
23279    Reparsed(BufferId),
23280    Focused,
23281    FocusedIn,
23282    Blurred,
23283    DirtyChanged,
23284    Saved,
23285    TitleChanged,
23286    SelectionsChanged {
23287        local: bool,
23288    },
23289    ScrollPositionChanged {
23290        local: bool,
23291        autoscroll: bool,
23292    },
23293    TransactionUndone {
23294        transaction_id: clock::Lamport,
23295    },
23296    TransactionBegun {
23297        transaction_id: clock::Lamport,
23298    },
23299    CursorShapeChanged,
23300    BreadcrumbsChanged,
23301    PushedToNavHistory {
23302        anchor: Anchor,
23303        is_deactivate: bool,
23304    },
23305}
23306
23307impl EventEmitter<EditorEvent> for Editor {}
23308
23309impl Focusable for Editor {
23310    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23311        self.focus_handle.clone()
23312    }
23313}
23314
23315impl Render for Editor {
23316    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23317        let settings = ThemeSettings::get_global(cx);
23318
23319        let mut text_style = match self.mode {
23320            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23321                color: cx.theme().colors().editor_foreground,
23322                font_family: settings.ui_font.family.clone(),
23323                font_features: settings.ui_font.features.clone(),
23324                font_fallbacks: settings.ui_font.fallbacks.clone(),
23325                font_size: rems(0.875).into(),
23326                font_weight: settings.ui_font.weight,
23327                line_height: relative(settings.buffer_line_height.value()),
23328                ..Default::default()
23329            },
23330            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23331                color: cx.theme().colors().editor_foreground,
23332                font_family: settings.buffer_font.family.clone(),
23333                font_features: settings.buffer_font.features.clone(),
23334                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23335                font_size: settings.buffer_font_size(cx).into(),
23336                font_weight: settings.buffer_font.weight,
23337                line_height: relative(settings.buffer_line_height.value()),
23338                ..Default::default()
23339            },
23340        };
23341        if let Some(text_style_refinement) = &self.text_style_refinement {
23342            text_style.refine(text_style_refinement)
23343        }
23344
23345        let background = match self.mode {
23346            EditorMode::SingleLine => cx.theme().system().transparent,
23347            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23348            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23349            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23350        };
23351
23352        EditorElement::new(
23353            &cx.entity(),
23354            EditorStyle {
23355                background,
23356                border: cx.theme().colors().border,
23357                local_player: cx.theme().players().local(),
23358                text: text_style,
23359                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23360                syntax: cx.theme().syntax().clone(),
23361                status: cx.theme().status().clone(),
23362                inlay_hints_style: make_inlay_hints_style(cx),
23363                edit_prediction_styles: make_suggestion_styles(cx),
23364                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23365                show_underlines: self.diagnostics_enabled(),
23366            },
23367        )
23368    }
23369}
23370
23371impl EntityInputHandler for Editor {
23372    fn text_for_range(
23373        &mut self,
23374        range_utf16: Range<usize>,
23375        adjusted_range: &mut Option<Range<usize>>,
23376        _: &mut Window,
23377        cx: &mut Context<Self>,
23378    ) -> Option<String> {
23379        let snapshot = self.buffer.read(cx).read(cx);
23380        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23381        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23382        if (start.0..end.0) != range_utf16 {
23383            adjusted_range.replace(start.0..end.0);
23384        }
23385        Some(snapshot.text_for_range(start..end).collect())
23386    }
23387
23388    fn selected_text_range(
23389        &mut self,
23390        ignore_disabled_input: bool,
23391        _: &mut Window,
23392        cx: &mut Context<Self>,
23393    ) -> Option<UTF16Selection> {
23394        // Prevent the IME menu from appearing when holding down an alphabetic key
23395        // while input is disabled.
23396        if !ignore_disabled_input && !self.input_enabled {
23397            return None;
23398        }
23399
23400        let selection = self.selections.newest::<OffsetUtf16>(cx);
23401        let range = selection.range();
23402
23403        Some(UTF16Selection {
23404            range: range.start.0..range.end.0,
23405            reversed: selection.reversed,
23406        })
23407    }
23408
23409    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23410        let snapshot = self.buffer.read(cx).read(cx);
23411        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23412        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23413    }
23414
23415    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23416        self.clear_highlights::<InputComposition>(cx);
23417        self.ime_transaction.take();
23418    }
23419
23420    fn replace_text_in_range(
23421        &mut self,
23422        range_utf16: Option<Range<usize>>,
23423        text: &str,
23424        window: &mut Window,
23425        cx: &mut Context<Self>,
23426    ) {
23427        if !self.input_enabled {
23428            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23429            return;
23430        }
23431
23432        self.transact(window, cx, |this, window, cx| {
23433            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23434                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23435                Some(this.selection_replacement_ranges(range_utf16, cx))
23436            } else {
23437                this.marked_text_ranges(cx)
23438            };
23439
23440            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23441                let newest_selection_id = this.selections.newest_anchor().id;
23442                this.selections
23443                    .all::<OffsetUtf16>(cx)
23444                    .iter()
23445                    .zip(ranges_to_replace.iter())
23446                    .find_map(|(selection, range)| {
23447                        if selection.id == newest_selection_id {
23448                            Some(
23449                                (range.start.0 as isize - selection.head().0 as isize)
23450                                    ..(range.end.0 as isize - selection.head().0 as isize),
23451                            )
23452                        } else {
23453                            None
23454                        }
23455                    })
23456            });
23457
23458            cx.emit(EditorEvent::InputHandled {
23459                utf16_range_to_replace: range_to_replace,
23460                text: text.into(),
23461            });
23462
23463            if let Some(new_selected_ranges) = new_selected_ranges {
23464                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23465                    selections.select_ranges(new_selected_ranges)
23466                });
23467                this.backspace(&Default::default(), window, cx);
23468            }
23469
23470            this.handle_input(text, window, cx);
23471        });
23472
23473        if let Some(transaction) = self.ime_transaction {
23474            self.buffer.update(cx, |buffer, cx| {
23475                buffer.group_until_transaction(transaction, cx);
23476            });
23477        }
23478
23479        self.unmark_text(window, cx);
23480    }
23481
23482    fn replace_and_mark_text_in_range(
23483        &mut self,
23484        range_utf16: Option<Range<usize>>,
23485        text: &str,
23486        new_selected_range_utf16: Option<Range<usize>>,
23487        window: &mut Window,
23488        cx: &mut Context<Self>,
23489    ) {
23490        if !self.input_enabled {
23491            return;
23492        }
23493
23494        let transaction = self.transact(window, cx, |this, window, cx| {
23495            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23496                let snapshot = this.buffer.read(cx).read(cx);
23497                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23498                    for marked_range in &mut marked_ranges {
23499                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23500                        marked_range.start.0 += relative_range_utf16.start;
23501                        marked_range.start =
23502                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23503                        marked_range.end =
23504                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23505                    }
23506                }
23507                Some(marked_ranges)
23508            } else if let Some(range_utf16) = range_utf16 {
23509                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23510                Some(this.selection_replacement_ranges(range_utf16, cx))
23511            } else {
23512                None
23513            };
23514
23515            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23516                let newest_selection_id = this.selections.newest_anchor().id;
23517                this.selections
23518                    .all::<OffsetUtf16>(cx)
23519                    .iter()
23520                    .zip(ranges_to_replace.iter())
23521                    .find_map(|(selection, range)| {
23522                        if selection.id == newest_selection_id {
23523                            Some(
23524                                (range.start.0 as isize - selection.head().0 as isize)
23525                                    ..(range.end.0 as isize - selection.head().0 as isize),
23526                            )
23527                        } else {
23528                            None
23529                        }
23530                    })
23531            });
23532
23533            cx.emit(EditorEvent::InputHandled {
23534                utf16_range_to_replace: range_to_replace,
23535                text: text.into(),
23536            });
23537
23538            if let Some(ranges) = ranges_to_replace {
23539                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23540                    s.select_ranges(ranges)
23541                });
23542            }
23543
23544            let marked_ranges = {
23545                let snapshot = this.buffer.read(cx).read(cx);
23546                this.selections
23547                    .disjoint_anchors()
23548                    .iter()
23549                    .map(|selection| {
23550                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23551                    })
23552                    .collect::<Vec<_>>()
23553            };
23554
23555            if text.is_empty() {
23556                this.unmark_text(window, cx);
23557            } else {
23558                this.highlight_text::<InputComposition>(
23559                    marked_ranges.clone(),
23560                    HighlightStyle {
23561                        underline: Some(UnderlineStyle {
23562                            thickness: px(1.),
23563                            color: None,
23564                            wavy: false,
23565                        }),
23566                        ..Default::default()
23567                    },
23568                    cx,
23569                );
23570            }
23571
23572            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23573            let use_autoclose = this.use_autoclose;
23574            let use_auto_surround = this.use_auto_surround;
23575            this.set_use_autoclose(false);
23576            this.set_use_auto_surround(false);
23577            this.handle_input(text, window, cx);
23578            this.set_use_autoclose(use_autoclose);
23579            this.set_use_auto_surround(use_auto_surround);
23580
23581            if let Some(new_selected_range) = new_selected_range_utf16 {
23582                let snapshot = this.buffer.read(cx).read(cx);
23583                let new_selected_ranges = marked_ranges
23584                    .into_iter()
23585                    .map(|marked_range| {
23586                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23587                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23588                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23589                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23590                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23591                    })
23592                    .collect::<Vec<_>>();
23593
23594                drop(snapshot);
23595                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23596                    selections.select_ranges(new_selected_ranges)
23597                });
23598            }
23599        });
23600
23601        self.ime_transaction = self.ime_transaction.or(transaction);
23602        if let Some(transaction) = self.ime_transaction {
23603            self.buffer.update(cx, |buffer, cx| {
23604                buffer.group_until_transaction(transaction, cx);
23605            });
23606        }
23607
23608        if self.text_highlights::<InputComposition>(cx).is_none() {
23609            self.ime_transaction.take();
23610        }
23611    }
23612
23613    fn bounds_for_range(
23614        &mut self,
23615        range_utf16: Range<usize>,
23616        element_bounds: gpui::Bounds<Pixels>,
23617        window: &mut Window,
23618        cx: &mut Context<Self>,
23619    ) -> Option<gpui::Bounds<Pixels>> {
23620        let text_layout_details = self.text_layout_details(window);
23621        let CharacterDimensions {
23622            em_width,
23623            em_advance,
23624            line_height,
23625        } = self.character_dimensions(window);
23626
23627        let snapshot = self.snapshot(window, cx);
23628        let scroll_position = snapshot.scroll_position();
23629        let scroll_left = scroll_position.x * em_advance;
23630
23631        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23632        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23633            + self.gutter_dimensions.full_width();
23634        let y = line_height * (start.row().as_f32() - scroll_position.y);
23635
23636        Some(Bounds {
23637            origin: element_bounds.origin + point(x, y),
23638            size: size(em_width, line_height),
23639        })
23640    }
23641
23642    fn character_index_for_point(
23643        &mut self,
23644        point: gpui::Point<Pixels>,
23645        _window: &mut Window,
23646        _cx: &mut Context<Self>,
23647    ) -> Option<usize> {
23648        let position_map = self.last_position_map.as_ref()?;
23649        if !position_map.text_hitbox.contains(&point) {
23650            return None;
23651        }
23652        let display_point = position_map.point_for_position(point).previous_valid;
23653        let anchor = position_map
23654            .snapshot
23655            .display_point_to_anchor(display_point, Bias::Left);
23656        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23657        Some(utf16_offset.0)
23658    }
23659}
23660
23661trait SelectionExt {
23662    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23663    fn spanned_rows(
23664        &self,
23665        include_end_if_at_line_start: bool,
23666        map: &DisplaySnapshot,
23667    ) -> Range<MultiBufferRow>;
23668}
23669
23670impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23671    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23672        let start = self
23673            .start
23674            .to_point(&map.buffer_snapshot)
23675            .to_display_point(map);
23676        let end = self
23677            .end
23678            .to_point(&map.buffer_snapshot)
23679            .to_display_point(map);
23680        if self.reversed {
23681            end..start
23682        } else {
23683            start..end
23684        }
23685    }
23686
23687    fn spanned_rows(
23688        &self,
23689        include_end_if_at_line_start: bool,
23690        map: &DisplaySnapshot,
23691    ) -> Range<MultiBufferRow> {
23692        let start = self.start.to_point(&map.buffer_snapshot);
23693        let mut end = self.end.to_point(&map.buffer_snapshot);
23694        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23695            end.row -= 1;
23696        }
23697
23698        let buffer_start = map.prev_line_boundary(start).0;
23699        let buffer_end = map.next_line_boundary(end).0;
23700        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23701    }
23702}
23703
23704impl<T: InvalidationRegion> InvalidationStack<T> {
23705    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23706    where
23707        S: Clone + ToOffset,
23708    {
23709        while let Some(region) = self.last() {
23710            let all_selections_inside_invalidation_ranges =
23711                if selections.len() == region.ranges().len() {
23712                    selections
23713                        .iter()
23714                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23715                        .all(|(selection, invalidation_range)| {
23716                            let head = selection.head().to_offset(buffer);
23717                            invalidation_range.start <= head && invalidation_range.end >= head
23718                        })
23719                } else {
23720                    false
23721                };
23722
23723            if all_selections_inside_invalidation_ranges {
23724                break;
23725            } else {
23726                self.pop();
23727            }
23728        }
23729    }
23730}
23731
23732impl<T> Default for InvalidationStack<T> {
23733    fn default() -> Self {
23734        Self(Default::default())
23735    }
23736}
23737
23738impl<T> Deref for InvalidationStack<T> {
23739    type Target = Vec<T>;
23740
23741    fn deref(&self) -> &Self::Target {
23742        &self.0
23743    }
23744}
23745
23746impl<T> DerefMut for InvalidationStack<T> {
23747    fn deref_mut(&mut self) -> &mut Self::Target {
23748        &mut self.0
23749    }
23750}
23751
23752impl InvalidationRegion for SnippetState {
23753    fn ranges(&self) -> &[Range<Anchor>] {
23754        &self.ranges[self.active_index]
23755    }
23756}
23757
23758fn edit_prediction_edit_text(
23759    current_snapshot: &BufferSnapshot,
23760    edits: &[(Range<Anchor>, String)],
23761    edit_preview: &EditPreview,
23762    include_deletions: bool,
23763    cx: &App,
23764) -> HighlightedText {
23765    let edits = edits
23766        .iter()
23767        .map(|(anchor, text)| {
23768            (
23769                anchor.start.text_anchor..anchor.end.text_anchor,
23770                text.clone(),
23771            )
23772        })
23773        .collect::<Vec<_>>();
23774
23775    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23776}
23777
23778fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23779    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23780    // Just show the raw edit text with basic styling
23781    let mut text = String::new();
23782    let mut highlights = Vec::new();
23783
23784    let insertion_highlight_style = HighlightStyle {
23785        color: Some(cx.theme().colors().text),
23786        ..Default::default()
23787    };
23788
23789    for (_, edit_text) in edits {
23790        let start_offset = text.len();
23791        text.push_str(edit_text);
23792        let end_offset = text.len();
23793
23794        if start_offset < end_offset {
23795            highlights.push((start_offset..end_offset, insertion_highlight_style));
23796        }
23797    }
23798
23799    HighlightedText {
23800        text: text.into(),
23801        highlights,
23802    }
23803}
23804
23805pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23806    match severity {
23807        lsp::DiagnosticSeverity::ERROR => colors.error,
23808        lsp::DiagnosticSeverity::WARNING => colors.warning,
23809        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23810        lsp::DiagnosticSeverity::HINT => colors.info,
23811        _ => colors.ignored,
23812    }
23813}
23814
23815pub fn styled_runs_for_code_label<'a>(
23816    label: &'a CodeLabel,
23817    syntax_theme: &'a theme::SyntaxTheme,
23818) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23819    let fade_out = HighlightStyle {
23820        fade_out: Some(0.35),
23821        ..Default::default()
23822    };
23823
23824    let mut prev_end = label.filter_range.end;
23825    label
23826        .runs
23827        .iter()
23828        .enumerate()
23829        .flat_map(move |(ix, (range, highlight_id))| {
23830            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23831                style
23832            } else {
23833                return Default::default();
23834            };
23835            let muted_style = style.highlight(fade_out);
23836
23837            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23838            if range.start >= label.filter_range.end {
23839                if range.start > prev_end {
23840                    runs.push((prev_end..range.start, fade_out));
23841                }
23842                runs.push((range.clone(), muted_style));
23843            } else if range.end <= label.filter_range.end {
23844                runs.push((range.clone(), style));
23845            } else {
23846                runs.push((range.start..label.filter_range.end, style));
23847                runs.push((label.filter_range.end..range.end, muted_style));
23848            }
23849            prev_end = cmp::max(prev_end, range.end);
23850
23851            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23852                runs.push((prev_end..label.text.len(), fade_out));
23853            }
23854
23855            runs
23856        })
23857}
23858
23859pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23860    let mut prev_index = 0;
23861    let mut prev_codepoint: Option<char> = None;
23862    text.char_indices()
23863        .chain([(text.len(), '\0')])
23864        .filter_map(move |(index, codepoint)| {
23865            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23866            let is_boundary = index == text.len()
23867                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23868                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23869            if is_boundary {
23870                let chunk = &text[prev_index..index];
23871                prev_index = index;
23872                Some(chunk)
23873            } else {
23874                None
23875            }
23876        })
23877}
23878
23879pub trait RangeToAnchorExt: Sized {
23880    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23881
23882    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23883        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23884        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23885    }
23886}
23887
23888impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23889    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23890        let start_offset = self.start.to_offset(snapshot);
23891        let end_offset = self.end.to_offset(snapshot);
23892        if start_offset == end_offset {
23893            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23894        } else {
23895            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23896        }
23897    }
23898}
23899
23900pub trait RowExt {
23901    fn as_f32(&self) -> f32;
23902
23903    fn next_row(&self) -> Self;
23904
23905    fn previous_row(&self) -> Self;
23906
23907    fn minus(&self, other: Self) -> u32;
23908}
23909
23910impl RowExt for DisplayRow {
23911    fn as_f32(&self) -> f32 {
23912        self.0 as f32
23913    }
23914
23915    fn next_row(&self) -> Self {
23916        Self(self.0 + 1)
23917    }
23918
23919    fn previous_row(&self) -> Self {
23920        Self(self.0.saturating_sub(1))
23921    }
23922
23923    fn minus(&self, other: Self) -> u32 {
23924        self.0 - other.0
23925    }
23926}
23927
23928impl RowExt for MultiBufferRow {
23929    fn as_f32(&self) -> f32 {
23930        self.0 as f32
23931    }
23932
23933    fn next_row(&self) -> Self {
23934        Self(self.0 + 1)
23935    }
23936
23937    fn previous_row(&self) -> Self {
23938        Self(self.0.saturating_sub(1))
23939    }
23940
23941    fn minus(&self, other: Self) -> u32 {
23942        self.0 - other.0
23943    }
23944}
23945
23946trait RowRangeExt {
23947    type Row;
23948
23949    fn len(&self) -> usize;
23950
23951    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23952}
23953
23954impl RowRangeExt for Range<MultiBufferRow> {
23955    type Row = MultiBufferRow;
23956
23957    fn len(&self) -> usize {
23958        (self.end.0 - self.start.0) as usize
23959    }
23960
23961    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23962        (self.start.0..self.end.0).map(MultiBufferRow)
23963    }
23964}
23965
23966impl RowRangeExt for Range<DisplayRow> {
23967    type Row = DisplayRow;
23968
23969    fn len(&self) -> usize {
23970        (self.end.0 - self.start.0) as usize
23971    }
23972
23973    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23974        (self.start.0..self.end.0).map(DisplayRow)
23975    }
23976}
23977
23978/// If select range has more than one line, we
23979/// just point the cursor to range.start.
23980fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23981    if range.start.row == range.end.row {
23982        range
23983    } else {
23984        range.start..range.start
23985    }
23986}
23987pub struct KillRing(ClipboardItem);
23988impl Global for KillRing {}
23989
23990const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23991
23992enum BreakpointPromptEditAction {
23993    Log,
23994    Condition,
23995    HitCondition,
23996}
23997
23998struct BreakpointPromptEditor {
23999    pub(crate) prompt: Entity<Editor>,
24000    editor: WeakEntity<Editor>,
24001    breakpoint_anchor: Anchor,
24002    breakpoint: Breakpoint,
24003    edit_action: BreakpointPromptEditAction,
24004    block_ids: HashSet<CustomBlockId>,
24005    editor_margins: Arc<Mutex<EditorMargins>>,
24006    _subscriptions: Vec<Subscription>,
24007}
24008
24009impl BreakpointPromptEditor {
24010    const MAX_LINES: u8 = 4;
24011
24012    fn new(
24013        editor: WeakEntity<Editor>,
24014        breakpoint_anchor: Anchor,
24015        breakpoint: Breakpoint,
24016        edit_action: BreakpointPromptEditAction,
24017        window: &mut Window,
24018        cx: &mut Context<Self>,
24019    ) -> Self {
24020        let base_text = match edit_action {
24021            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24022            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24023            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24024        }
24025        .map(|msg| msg.to_string())
24026        .unwrap_or_default();
24027
24028        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24029        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24030
24031        let prompt = cx.new(|cx| {
24032            let mut prompt = Editor::new(
24033                EditorMode::AutoHeight {
24034                    min_lines: 1,
24035                    max_lines: Some(Self::MAX_LINES as usize),
24036                },
24037                buffer,
24038                None,
24039                window,
24040                cx,
24041            );
24042            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24043            prompt.set_show_cursor_when_unfocused(false, cx);
24044            prompt.set_placeholder_text(
24045                match edit_action {
24046                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24047                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24048                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24049                },
24050                window,
24051                cx,
24052            );
24053
24054            prompt
24055        });
24056
24057        Self {
24058            prompt,
24059            editor,
24060            breakpoint_anchor,
24061            breakpoint,
24062            edit_action,
24063            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24064            block_ids: Default::default(),
24065            _subscriptions: vec![],
24066        }
24067    }
24068
24069    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24070        self.block_ids.extend(block_ids)
24071    }
24072
24073    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24074        if let Some(editor) = self.editor.upgrade() {
24075            let message = self
24076                .prompt
24077                .read(cx)
24078                .buffer
24079                .read(cx)
24080                .as_singleton()
24081                .expect("A multi buffer in breakpoint prompt isn't possible")
24082                .read(cx)
24083                .as_rope()
24084                .to_string();
24085
24086            editor.update(cx, |editor, cx| {
24087                editor.edit_breakpoint_at_anchor(
24088                    self.breakpoint_anchor,
24089                    self.breakpoint.clone(),
24090                    match self.edit_action {
24091                        BreakpointPromptEditAction::Log => {
24092                            BreakpointEditAction::EditLogMessage(message.into())
24093                        }
24094                        BreakpointPromptEditAction::Condition => {
24095                            BreakpointEditAction::EditCondition(message.into())
24096                        }
24097                        BreakpointPromptEditAction::HitCondition => {
24098                            BreakpointEditAction::EditHitCondition(message.into())
24099                        }
24100                    },
24101                    cx,
24102                );
24103
24104                editor.remove_blocks(self.block_ids.clone(), None, cx);
24105                cx.focus_self(window);
24106            });
24107        }
24108    }
24109
24110    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24111        self.editor
24112            .update(cx, |editor, cx| {
24113                editor.remove_blocks(self.block_ids.clone(), None, cx);
24114                window.focus(&editor.focus_handle);
24115            })
24116            .log_err();
24117    }
24118
24119    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24120        let settings = ThemeSettings::get_global(cx);
24121        let text_style = TextStyle {
24122            color: if self.prompt.read(cx).read_only(cx) {
24123                cx.theme().colors().text_disabled
24124            } else {
24125                cx.theme().colors().text
24126            },
24127            font_family: settings.buffer_font.family.clone(),
24128            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24129            font_size: settings.buffer_font_size(cx).into(),
24130            font_weight: settings.buffer_font.weight,
24131            line_height: relative(settings.buffer_line_height.value()),
24132            ..Default::default()
24133        };
24134        EditorElement::new(
24135            &self.prompt,
24136            EditorStyle {
24137                background: cx.theme().colors().editor_background,
24138                local_player: cx.theme().players().local(),
24139                text: text_style,
24140                ..Default::default()
24141            },
24142        )
24143    }
24144}
24145
24146impl Render for BreakpointPromptEditor {
24147    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24148        let editor_margins = *self.editor_margins.lock();
24149        let gutter_dimensions = editor_margins.gutter;
24150        h_flex()
24151            .key_context("Editor")
24152            .bg(cx.theme().colors().editor_background)
24153            .border_y_1()
24154            .border_color(cx.theme().status().info_border)
24155            .size_full()
24156            .py(window.line_height() / 2.5)
24157            .on_action(cx.listener(Self::confirm))
24158            .on_action(cx.listener(Self::cancel))
24159            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24160            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24161    }
24162}
24163
24164impl Focusable for BreakpointPromptEditor {
24165    fn focus_handle(&self, cx: &App) -> FocusHandle {
24166        self.prompt.focus_handle(cx)
24167    }
24168}
24169
24170fn all_edits_insertions_or_deletions(
24171    edits: &Vec<(Range<Anchor>, String)>,
24172    snapshot: &MultiBufferSnapshot,
24173) -> bool {
24174    let mut all_insertions = true;
24175    let mut all_deletions = true;
24176
24177    for (range, new_text) in edits.iter() {
24178        let range_is_empty = range.to_offset(snapshot).is_empty();
24179        let text_is_empty = new_text.is_empty();
24180
24181        if range_is_empty != text_is_empty {
24182            if range_is_empty {
24183                all_deletions = false;
24184            } else {
24185                all_insertions = false;
24186            }
24187        } else {
24188            return false;
24189        }
24190
24191        if !all_insertions && !all_deletions {
24192            return false;
24193        }
24194    }
24195    all_insertions || all_deletions
24196}
24197
24198struct MissingEditPredictionKeybindingTooltip;
24199
24200impl Render for MissingEditPredictionKeybindingTooltip {
24201    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24202        ui::tooltip_container(window, cx, |container, _, cx| {
24203            container
24204                .flex_shrink_0()
24205                .max_w_80()
24206                .min_h(rems_from_px(124.))
24207                .justify_between()
24208                .child(
24209                    v_flex()
24210                        .flex_1()
24211                        .text_ui_sm(cx)
24212                        .child(Label::new("Conflict with Accept Keybinding"))
24213                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24214                )
24215                .child(
24216                    h_flex()
24217                        .pb_1()
24218                        .gap_1()
24219                        .items_end()
24220                        .w_full()
24221                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24222                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24223                        }))
24224                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24225                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24226                        })),
24227                )
24228        })
24229    }
24230}
24231
24232#[derive(Debug, Clone, Copy, PartialEq)]
24233pub struct LineHighlight {
24234    pub background: Background,
24235    pub border: Option<gpui::Hsla>,
24236    pub include_gutter: bool,
24237    pub type_id: Option<TypeId>,
24238}
24239
24240struct LineManipulationResult {
24241    pub new_text: String,
24242    pub line_count_before: usize,
24243    pub line_count_after: usize,
24244}
24245
24246fn render_diff_hunk_controls(
24247    row: u32,
24248    status: &DiffHunkStatus,
24249    hunk_range: Range<Anchor>,
24250    is_created_file: bool,
24251    line_height: Pixels,
24252    editor: &Entity<Editor>,
24253    _window: &mut Window,
24254    cx: &mut App,
24255) -> AnyElement {
24256    h_flex()
24257        .h(line_height)
24258        .mr_1()
24259        .gap_1()
24260        .px_0p5()
24261        .pb_1()
24262        .border_x_1()
24263        .border_b_1()
24264        .border_color(cx.theme().colors().border_variant)
24265        .rounded_b_lg()
24266        .bg(cx.theme().colors().editor_background)
24267        .gap_1()
24268        .block_mouse_except_scroll()
24269        .shadow_md()
24270        .child(if status.has_secondary_hunk() {
24271            Button::new(("stage", row as u64), "Stage")
24272                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24273                .tooltip({
24274                    let focus_handle = editor.focus_handle(cx);
24275                    move |window, cx| {
24276                        Tooltip::for_action_in(
24277                            "Stage Hunk",
24278                            &::git::ToggleStaged,
24279                            &focus_handle,
24280                            window,
24281                            cx,
24282                        )
24283                    }
24284                })
24285                .on_click({
24286                    let editor = editor.clone();
24287                    move |_event, _window, cx| {
24288                        editor.update(cx, |editor, cx| {
24289                            editor.stage_or_unstage_diff_hunks(
24290                                true,
24291                                vec![hunk_range.start..hunk_range.start],
24292                                cx,
24293                            );
24294                        });
24295                    }
24296                })
24297        } else {
24298            Button::new(("unstage", row as u64), "Unstage")
24299                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24300                .tooltip({
24301                    let focus_handle = editor.focus_handle(cx);
24302                    move |window, cx| {
24303                        Tooltip::for_action_in(
24304                            "Unstage Hunk",
24305                            &::git::ToggleStaged,
24306                            &focus_handle,
24307                            window,
24308                            cx,
24309                        )
24310                    }
24311                })
24312                .on_click({
24313                    let editor = editor.clone();
24314                    move |_event, _window, cx| {
24315                        editor.update(cx, |editor, cx| {
24316                            editor.stage_or_unstage_diff_hunks(
24317                                false,
24318                                vec![hunk_range.start..hunk_range.start],
24319                                cx,
24320                            );
24321                        });
24322                    }
24323                })
24324        })
24325        .child(
24326            Button::new(("restore", row as u64), "Restore")
24327                .tooltip({
24328                    let focus_handle = editor.focus_handle(cx);
24329                    move |window, cx| {
24330                        Tooltip::for_action_in(
24331                            "Restore Hunk",
24332                            &::git::Restore,
24333                            &focus_handle,
24334                            window,
24335                            cx,
24336                        )
24337                    }
24338                })
24339                .on_click({
24340                    let editor = editor.clone();
24341                    move |_event, window, cx| {
24342                        editor.update(cx, |editor, cx| {
24343                            let snapshot = editor.snapshot(window, cx);
24344                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24345                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24346                        });
24347                    }
24348                })
24349                .disabled(is_created_file),
24350        )
24351        .when(
24352            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24353            |el| {
24354                el.child(
24355                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24356                        .shape(IconButtonShape::Square)
24357                        .icon_size(IconSize::Small)
24358                        // .disabled(!has_multiple_hunks)
24359                        .tooltip({
24360                            let focus_handle = editor.focus_handle(cx);
24361                            move |window, cx| {
24362                                Tooltip::for_action_in(
24363                                    "Next Hunk",
24364                                    &GoToHunk,
24365                                    &focus_handle,
24366                                    window,
24367                                    cx,
24368                                )
24369                            }
24370                        })
24371                        .on_click({
24372                            let editor = editor.clone();
24373                            move |_event, window, cx| {
24374                                editor.update(cx, |editor, cx| {
24375                                    let snapshot = editor.snapshot(window, cx);
24376                                    let position =
24377                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24378                                    editor.go_to_hunk_before_or_after_position(
24379                                        &snapshot,
24380                                        position,
24381                                        Direction::Next,
24382                                        window,
24383                                        cx,
24384                                    );
24385                                    editor.expand_selected_diff_hunks(cx);
24386                                });
24387                            }
24388                        }),
24389                )
24390                .child(
24391                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24392                        .shape(IconButtonShape::Square)
24393                        .icon_size(IconSize::Small)
24394                        // .disabled(!has_multiple_hunks)
24395                        .tooltip({
24396                            let focus_handle = editor.focus_handle(cx);
24397                            move |window, cx| {
24398                                Tooltip::for_action_in(
24399                                    "Previous Hunk",
24400                                    &GoToPreviousHunk,
24401                                    &focus_handle,
24402                                    window,
24403                                    cx,
24404                                )
24405                            }
24406                        })
24407                        .on_click({
24408                            let editor = editor.clone();
24409                            move |_event, window, cx| {
24410                                editor.update(cx, |editor, cx| {
24411                                    let snapshot = editor.snapshot(window, cx);
24412                                    let point =
24413                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24414                                    editor.go_to_hunk_before_or_after_position(
24415                                        &snapshot,
24416                                        point,
24417                                        Direction::Prev,
24418                                        window,
24419                                        cx,
24420                                    );
24421                                    editor.expand_selected_diff_hunks(cx);
24422                                });
24423                            }
24424                        }),
24425                )
24426            },
24427        )
24428        .into_any_element()
24429}
24430
24431pub fn multibuffer_context_lines(cx: &App) -> u32 {
24432    EditorSettings::try_get(cx)
24433        .map(|settings| settings.excerpt_context_lines)
24434        .unwrap_or(2)
24435        .clamp(1, 32)
24436}