editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap, ShowScrollbar,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{
  164        DiagnosticSeverity, GitGutterSetting, GoToDiagnosticSeverityFilter, ProjectSettings,
  165    },
  166};
  167use rand::seq::SliceRandom;
  168use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  169use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  170use selections_collection::{
  171    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  172};
  173use serde::{Deserialize, Serialize};
  174use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  175use smallvec::{SmallVec, smallvec};
  176use snippet::Snippet;
  177use std::{
  178    any::TypeId,
  179    borrow::Cow,
  180    cell::OnceCell,
  181    cell::RefCell,
  182    cmp::{self, Ordering, Reverse},
  183    iter::Peekable,
  184    mem,
  185    num::NonZeroU32,
  186    ops::Not,
  187    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  188    path::{Path, PathBuf},
  189    rc::Rc,
  190    sync::Arc,
  191    time::{Duration, Instant},
  192};
  193use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  194use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  195use theme::{
  196    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  197    observe_buffer_font_size_adjustment,
  198};
  199use ui::{
  200    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  201    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  202};
  203use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  204use workspace::{
  205    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  206    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  207    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  208    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  209    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  210    searchable::SearchEvent,
  211};
  212
  213use crate::{
  214    code_context_menus::CompletionsMenuSource,
  215    editor_settings::MultiCursorModifier,
  216    hover_links::{find_url, find_url_from_range},
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  223const MAX_LINE_LEN: usize = 1024;
  224const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  225const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  226pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  227#[doc(hidden)]
  228pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  229pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  230
  231pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  234
  235pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  236pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  237pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  238
  239pub type RenderDiffHunkControlsFn = Arc<
  240    dyn Fn(
  241        u32,
  242        &DiffHunkStatus,
  243        Range<Anchor>,
  244        bool,
  245        Pixels,
  246        &Entity<Editor>,
  247        &mut Window,
  248        &mut App,
  249    ) -> AnyElement,
  250>;
  251
  252enum ReportEditorEvent {
  253    Saved { auto_saved: bool },
  254    EditorOpened,
  255    Closed,
  256}
  257
  258impl ReportEditorEvent {
  259    pub fn event_type(&self) -> &'static str {
  260        match self {
  261            Self::Saved { .. } => "Editor Saved",
  262            Self::EditorOpened => "Editor Opened",
  263            Self::Closed => "Editor Closed",
  264        }
  265    }
  266}
  267
  268struct InlineValueCache {
  269    enabled: bool,
  270    inlays: Vec<InlayId>,
  271    refresh_task: Task<Option<()>>,
  272}
  273
  274impl InlineValueCache {
  275    fn new(enabled: bool) -> Self {
  276        Self {
  277            enabled,
  278            inlays: Vec::new(),
  279            refresh_task: Task::ready(None),
  280        }
  281    }
  282}
  283
  284#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  285pub enum InlayId {
  286    EditPrediction(usize),
  287    DebuggerValue(usize),
  288    // LSP
  289    Hint(usize),
  290    Color(usize),
  291}
  292
  293impl InlayId {
  294    fn id(&self) -> usize {
  295        match self {
  296            Self::EditPrediction(id) => *id,
  297            Self::DebuggerValue(id) => *id,
  298            Self::Hint(id) => *id,
  299            Self::Color(id) => *id,
  300        }
  301    }
  302}
  303
  304pub enum ActiveDebugLine {}
  305pub enum DebugStackFrameLine {}
  306enum DocumentHighlightRead {}
  307enum DocumentHighlightWrite {}
  308enum InputComposition {}
  309pub enum PendingInput {}
  310enum SelectedTextHighlight {}
  311
  312pub enum ConflictsOuter {}
  313pub enum ConflictsOurs {}
  314pub enum ConflictsTheirs {}
  315pub enum ConflictsOursMarker {}
  316pub enum ConflictsTheirsMarker {}
  317
  318#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  319pub enum Navigated {
  320    Yes,
  321    No,
  322}
  323
  324impl Navigated {
  325    pub fn from_bool(yes: bool) -> Navigated {
  326        if yes { Navigated::Yes } else { Navigated::No }
  327    }
  328}
  329
  330#[derive(Debug, Clone, PartialEq, Eq)]
  331enum DisplayDiffHunk {
  332    Folded {
  333        display_row: DisplayRow,
  334    },
  335    Unfolded {
  336        is_created_file: bool,
  337        diff_base_byte_range: Range<usize>,
  338        display_row_range: Range<DisplayRow>,
  339        multi_buffer_range: Range<Anchor>,
  340        status: DiffHunkStatus,
  341    },
  342}
  343
  344pub enum HideMouseCursorOrigin {
  345    TypingAction,
  346    MovementAction,
  347}
  348
  349pub fn init_settings(cx: &mut App) {
  350    EditorSettings::register(cx);
  351}
  352
  353pub fn init(cx: &mut App) {
  354    init_settings(cx);
  355
  356    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  357
  358    workspace::register_project_item::<Editor>(cx);
  359    workspace::FollowableViewRegistry::register::<Editor>(cx);
  360    workspace::register_serializable_item::<Editor>(cx);
  361
  362    cx.observe_new(
  363        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  364            workspace.register_action(Editor::new_file);
  365            workspace.register_action(Editor::new_file_vertical);
  366            workspace.register_action(Editor::new_file_horizontal);
  367            workspace.register_action(Editor::cancel_language_server_work);
  368            workspace.register_action(Editor::toggle_focus);
  369        },
  370    )
  371    .detach();
  372
  373    cx.on_action(move |_: &workspace::NewFile, cx| {
  374        let app_state = workspace::AppState::global(cx);
  375        if let Some(app_state) = app_state.upgrade() {
  376            workspace::open_new(
  377                Default::default(),
  378                app_state,
  379                cx,
  380                |workspace, window, cx| {
  381                    Editor::new_file(workspace, &Default::default(), window, cx)
  382                },
  383            )
  384            .detach();
  385        }
  386    });
  387    cx.on_action(move |_: &workspace::NewWindow, cx| {
  388        let app_state = workspace::AppState::global(cx);
  389        if let Some(app_state) = app_state.upgrade() {
  390            workspace::open_new(
  391                Default::default(),
  392                app_state,
  393                cx,
  394                |workspace, window, cx| {
  395                    cx.activate(true);
  396                    Editor::new_file(workspace, &Default::default(), window, cx)
  397                },
  398            )
  399            .detach();
  400        }
  401    });
  402}
  403
  404pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  405    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  406}
  407
  408pub trait DiagnosticRenderer {
  409    fn render_group(
  410        &self,
  411        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  412        buffer_id: BufferId,
  413        snapshot: EditorSnapshot,
  414        editor: WeakEntity<Editor>,
  415        cx: &mut App,
  416    ) -> Vec<BlockProperties<Anchor>>;
  417
  418    fn render_hover(
  419        &self,
  420        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  421        range: Range<Point>,
  422        buffer_id: BufferId,
  423        cx: &mut App,
  424    ) -> Option<Entity<markdown::Markdown>>;
  425
  426    fn open_link(
  427        &self,
  428        editor: &mut Editor,
  429        link: SharedString,
  430        window: &mut Window,
  431        cx: &mut Context<Editor>,
  432    );
  433}
  434
  435pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  436
  437impl GlobalDiagnosticRenderer {
  438    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  439        cx.try_global::<Self>().map(|g| g.0.clone())
  440    }
  441}
  442
  443impl gpui::Global for GlobalDiagnosticRenderer {}
  444pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  445    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  446}
  447
  448pub struct SearchWithinRange;
  449
  450trait InvalidationRegion {
  451    fn ranges(&self) -> &[Range<Anchor>];
  452}
  453
  454#[derive(Clone, Debug, PartialEq)]
  455pub enum SelectPhase {
  456    Begin {
  457        position: DisplayPoint,
  458        add: bool,
  459        click_count: usize,
  460    },
  461    BeginColumnar {
  462        position: DisplayPoint,
  463        reset: bool,
  464        mode: ColumnarMode,
  465        goal_column: u32,
  466    },
  467    Extend {
  468        position: DisplayPoint,
  469        click_count: usize,
  470    },
  471    Update {
  472        position: DisplayPoint,
  473        goal_column: u32,
  474        scroll_delta: gpui::Point<f32>,
  475    },
  476    End,
  477}
  478
  479#[derive(Clone, Debug, PartialEq)]
  480pub enum ColumnarMode {
  481    FromMouse,
  482    FromSelection,
  483}
  484
  485#[derive(Clone, Debug)]
  486pub enum SelectMode {
  487    Character,
  488    Word(Range<Anchor>),
  489    Line(Range<Anchor>),
  490    All,
  491}
  492
  493#[derive(Clone, PartialEq, Eq, Debug)]
  494pub enum EditorMode {
  495    SingleLine,
  496    AutoHeight {
  497        min_lines: usize,
  498        max_lines: Option<usize>,
  499    },
  500    Full {
  501        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  502        scale_ui_elements_with_buffer_font_size: bool,
  503        /// When set to `true`, the editor will render a background for the active line.
  504        show_active_line_background: bool,
  505        /// When set to `true`, the editor's height will be determined by its content.
  506        sized_by_content: bool,
  507    },
  508    Minimap {
  509        parent: WeakEntity<Editor>,
  510    },
  511}
  512
  513impl EditorMode {
  514    pub fn full() -> Self {
  515        Self::Full {
  516            scale_ui_elements_with_buffer_font_size: true,
  517            show_active_line_background: true,
  518            sized_by_content: false,
  519        }
  520    }
  521
  522    #[inline]
  523    pub fn is_full(&self) -> bool {
  524        matches!(self, Self::Full { .. })
  525    }
  526
  527    #[inline]
  528    pub fn is_single_line(&self) -> bool {
  529        matches!(self, Self::SingleLine { .. })
  530    }
  531
  532    #[inline]
  533    fn is_minimap(&self) -> bool {
  534        matches!(self, Self::Minimap { .. })
  535    }
  536}
  537
  538#[derive(Copy, Clone, Debug)]
  539pub enum SoftWrap {
  540    /// Prefer not to wrap at all.
  541    ///
  542    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  543    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  544    GitDiff,
  545    /// Prefer a single line generally, unless an overly long line is encountered.
  546    None,
  547    /// Soft wrap lines that exceed the editor width.
  548    EditorWidth,
  549    /// Soft wrap lines at the preferred line length.
  550    Column(u32),
  551    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  552    Bounded(u32),
  553}
  554
  555#[derive(Clone)]
  556pub struct EditorStyle {
  557    pub background: Hsla,
  558    pub border: Hsla,
  559    pub local_player: PlayerColor,
  560    pub text: TextStyle,
  561    pub scrollbar_width: Pixels,
  562    pub syntax: Arc<SyntaxTheme>,
  563    pub status: StatusColors,
  564    pub inlay_hints_style: HighlightStyle,
  565    pub edit_prediction_styles: EditPredictionStyles,
  566    pub unnecessary_code_fade: f32,
  567    pub show_underlines: bool,
  568}
  569
  570impl Default for EditorStyle {
  571    fn default() -> Self {
  572        Self {
  573            background: Hsla::default(),
  574            border: Hsla::default(),
  575            local_player: PlayerColor::default(),
  576            text: TextStyle::default(),
  577            scrollbar_width: Pixels::default(),
  578            syntax: Default::default(),
  579            // HACK: Status colors don't have a real default.
  580            // We should look into removing the status colors from the editor
  581            // style and retrieve them directly from the theme.
  582            status: StatusColors::dark(),
  583            inlay_hints_style: HighlightStyle::default(),
  584            edit_prediction_styles: EditPredictionStyles {
  585                insertion: HighlightStyle::default(),
  586                whitespace: HighlightStyle::default(),
  587            },
  588            unnecessary_code_fade: Default::default(),
  589            show_underlines: true,
  590        }
  591    }
  592}
  593
  594pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  595    let show_background = language_settings::language_settings(None, None, cx)
  596        .inlay_hints
  597        .show_background;
  598
  599    HighlightStyle {
  600        color: Some(cx.theme().status().hint),
  601        background_color: show_background.then(|| cx.theme().status().hint_background),
  602        ..HighlightStyle::default()
  603    }
  604}
  605
  606pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  607    EditPredictionStyles {
  608        insertion: HighlightStyle {
  609            color: Some(cx.theme().status().predictive),
  610            ..HighlightStyle::default()
  611        },
  612        whitespace: HighlightStyle {
  613            background_color: Some(cx.theme().status().created_background),
  614            ..HighlightStyle::default()
  615        },
  616    }
  617}
  618
  619type CompletionId = usize;
  620
  621pub(crate) enum EditDisplayMode {
  622    TabAccept,
  623    DiffPopover,
  624    Inline,
  625}
  626
  627enum EditPrediction {
  628    Edit {
  629        edits: Vec<(Range<Anchor>, String)>,
  630        edit_preview: Option<EditPreview>,
  631        display_mode: EditDisplayMode,
  632        snapshot: BufferSnapshot,
  633    },
  634    Move {
  635        target: Anchor,
  636        snapshot: BufferSnapshot,
  637    },
  638}
  639
  640struct EditPredictionState {
  641    inlay_ids: Vec<InlayId>,
  642    completion: EditPrediction,
  643    completion_id: Option<SharedString>,
  644    invalidation_range: Range<Anchor>,
  645}
  646
  647enum EditPredictionSettings {
  648    Disabled,
  649    Enabled {
  650        show_in_menu: bool,
  651        preview_requires_modifier: bool,
  652    },
  653}
  654
  655enum EditPredictionHighlight {}
  656
  657#[derive(Debug, Clone)]
  658struct InlineDiagnostic {
  659    message: SharedString,
  660    group_id: usize,
  661    is_primary: bool,
  662    start: Point,
  663    severity: lsp::DiagnosticSeverity,
  664}
  665
  666pub enum MenuEditPredictionsPolicy {
  667    Never,
  668    ByProvider,
  669}
  670
  671pub enum EditPredictionPreview {
  672    /// Modifier is not pressed
  673    Inactive { released_too_fast: bool },
  674    /// Modifier pressed
  675    Active {
  676        since: Instant,
  677        previous_scroll_position: Option<ScrollAnchor>,
  678    },
  679}
  680
  681impl EditPredictionPreview {
  682    pub fn released_too_fast(&self) -> bool {
  683        match self {
  684            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  685            EditPredictionPreview::Active { .. } => false,
  686        }
  687    }
  688
  689    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  690        if let EditPredictionPreview::Active {
  691            previous_scroll_position,
  692            ..
  693        } = self
  694        {
  695            *previous_scroll_position = scroll_position;
  696        }
  697    }
  698}
  699
  700pub struct ContextMenuOptions {
  701    pub min_entries_visible: usize,
  702    pub max_entries_visible: usize,
  703    pub placement: Option<ContextMenuPlacement>,
  704}
  705
  706#[derive(Debug, Clone, PartialEq, Eq)]
  707pub enum ContextMenuPlacement {
  708    Above,
  709    Below,
  710}
  711
  712#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  713struct EditorActionId(usize);
  714
  715impl EditorActionId {
  716    pub fn post_inc(&mut self) -> Self {
  717        let answer = self.0;
  718
  719        *self = Self(answer + 1);
  720
  721        Self(answer)
  722    }
  723}
  724
  725// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  726// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  727
  728type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  729type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  730
  731#[derive(Default)]
  732struct ScrollbarMarkerState {
  733    scrollbar_size: Size<Pixels>,
  734    dirty: bool,
  735    markers: Arc<[PaintQuad]>,
  736    pending_refresh: Option<Task<Result<()>>>,
  737}
  738
  739impl ScrollbarMarkerState {
  740    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  741        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  742    }
  743}
  744
  745#[derive(Clone, Copy, PartialEq, Eq)]
  746pub enum MinimapVisibility {
  747    Disabled,
  748    Enabled {
  749        /// The configuration currently present in the users settings.
  750        setting_configuration: bool,
  751        /// Whether to override the currently set visibility from the users setting.
  752        toggle_override: bool,
  753    },
  754}
  755
  756impl MinimapVisibility {
  757    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  758        if mode.is_full() {
  759            Self::Enabled {
  760                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  761                toggle_override: false,
  762            }
  763        } else {
  764            Self::Disabled
  765        }
  766    }
  767
  768    fn hidden(&self) -> Self {
  769        match *self {
  770            Self::Enabled {
  771                setting_configuration,
  772                ..
  773            } => Self::Enabled {
  774                setting_configuration,
  775                toggle_override: setting_configuration,
  776            },
  777            Self::Disabled => Self::Disabled,
  778        }
  779    }
  780
  781    fn disabled(&self) -> bool {
  782        matches!(*self, Self::Disabled)
  783    }
  784
  785    fn settings_visibility(&self) -> bool {
  786        match *self {
  787            Self::Enabled {
  788                setting_configuration,
  789                ..
  790            } => setting_configuration,
  791            _ => false,
  792        }
  793    }
  794
  795    fn visible(&self) -> bool {
  796        match *self {
  797            Self::Enabled {
  798                setting_configuration,
  799                toggle_override,
  800            } => setting_configuration ^ toggle_override,
  801            _ => false,
  802        }
  803    }
  804
  805    fn toggle_visibility(&self) -> Self {
  806        match *self {
  807            Self::Enabled {
  808                toggle_override,
  809                setting_configuration,
  810            } => Self::Enabled {
  811                setting_configuration,
  812                toggle_override: !toggle_override,
  813            },
  814            Self::Disabled => Self::Disabled,
  815        }
  816    }
  817}
  818
  819#[derive(Clone, Debug)]
  820struct RunnableTasks {
  821    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  822    offset: multi_buffer::Anchor,
  823    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  824    column: u32,
  825    // Values of all named captures, including those starting with '_'
  826    extra_variables: HashMap<String, String>,
  827    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  828    context_range: Range<BufferOffset>,
  829}
  830
  831impl RunnableTasks {
  832    fn resolve<'a>(
  833        &'a self,
  834        cx: &'a task::TaskContext,
  835    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  836        self.templates.iter().filter_map(|(kind, template)| {
  837            template
  838                .resolve_task(&kind.to_id_base(), cx)
  839                .map(|task| (kind.clone(), task))
  840        })
  841    }
  842}
  843
  844#[derive(Clone)]
  845pub struct ResolvedTasks {
  846    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  847    position: Anchor,
  848}
  849
  850#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  851struct BufferOffset(usize);
  852
  853// Addons allow storing per-editor state in other crates (e.g. Vim)
  854pub trait Addon: 'static {
  855    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  856
  857    fn render_buffer_header_controls(
  858        &self,
  859        _: &ExcerptInfo,
  860        _: &Window,
  861        _: &App,
  862    ) -> Option<AnyElement> {
  863        None
  864    }
  865
  866    fn to_any(&self) -> &dyn std::any::Any;
  867
  868    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  869        None
  870    }
  871}
  872
  873struct ChangeLocation {
  874    current: Option<Vec<Anchor>>,
  875    original: Vec<Anchor>,
  876}
  877impl ChangeLocation {
  878    fn locations(&self) -> &[Anchor] {
  879        self.current.as_ref().unwrap_or(&self.original)
  880    }
  881}
  882
  883/// A set of caret positions, registered when the editor was edited.
  884pub struct ChangeList {
  885    changes: Vec<ChangeLocation>,
  886    /// Currently "selected" change.
  887    position: Option<usize>,
  888}
  889
  890impl ChangeList {
  891    pub fn new() -> Self {
  892        Self {
  893            changes: Vec::new(),
  894            position: None,
  895        }
  896    }
  897
  898    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  899    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  900    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  901        if self.changes.is_empty() {
  902            return None;
  903        }
  904
  905        let prev = self.position.unwrap_or(self.changes.len());
  906        let next = if direction == Direction::Prev {
  907            prev.saturating_sub(count)
  908        } else {
  909            (prev + count).min(self.changes.len() - 1)
  910        };
  911        self.position = Some(next);
  912        self.changes.get(next).map(|change| change.locations())
  913    }
  914
  915    /// Adds a new change to the list, resetting the change list position.
  916    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  917        self.position.take();
  918        if let Some(last) = self.changes.last_mut()
  919            && group
  920        {
  921            last.current = Some(new_positions)
  922        } else {
  923            self.changes.push(ChangeLocation {
  924                original: new_positions,
  925                current: None,
  926            });
  927        }
  928    }
  929
  930    pub fn last(&self) -> Option<&[Anchor]> {
  931        self.changes.last().map(|change| change.locations())
  932    }
  933
  934    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  935        self.changes.last().map(|change| change.original.as_slice())
  936    }
  937
  938    pub fn invert_last_group(&mut self) {
  939        if let Some(last) = self.changes.last_mut()
  940            && let Some(current) = last.current.as_mut()
  941        {
  942            mem::swap(&mut last.original, current);
  943        }
  944    }
  945}
  946
  947#[derive(Clone)]
  948struct InlineBlamePopoverState {
  949    scroll_handle: ScrollHandle,
  950    commit_message: Option<ParsedCommitMessage>,
  951    markdown: Entity<Markdown>,
  952}
  953
  954struct InlineBlamePopover {
  955    position: gpui::Point<Pixels>,
  956    hide_task: Option<Task<()>>,
  957    popover_bounds: Option<Bounds<Pixels>>,
  958    popover_state: InlineBlamePopoverState,
  959    keyboard_grace: bool,
  960}
  961
  962enum SelectionDragState {
  963    /// State when no drag related activity is detected.
  964    None,
  965    /// State when the mouse is down on a selection that is about to be dragged.
  966    ReadyToDrag {
  967        selection: Selection<Anchor>,
  968        click_position: gpui::Point<Pixels>,
  969        mouse_down_time: Instant,
  970    },
  971    /// State when the mouse is dragging the selection in the editor.
  972    Dragging {
  973        selection: Selection<Anchor>,
  974        drop_cursor: Selection<Anchor>,
  975        hide_drop_cursor: bool,
  976    },
  977}
  978
  979enum ColumnarSelectionState {
  980    FromMouse {
  981        selection_tail: Anchor,
  982        display_point: Option<DisplayPoint>,
  983    },
  984    FromSelection {
  985        selection_tail: Anchor,
  986    },
  987}
  988
  989/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  990/// a breakpoint on them.
  991#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  992struct PhantomBreakpointIndicator {
  993    display_row: DisplayRow,
  994    /// There's a small debounce between hovering over the line and showing the indicator.
  995    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  996    is_active: bool,
  997    collides_with_existing_breakpoint: bool,
  998}
  999
 1000/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1001///
 1002/// See the [module level documentation](self) for more information.
 1003pub struct Editor {
 1004    focus_handle: FocusHandle,
 1005    last_focused_descendant: Option<WeakFocusHandle>,
 1006    /// The text buffer being edited
 1007    buffer: Entity<MultiBuffer>,
 1008    /// Map of how text in the buffer should be displayed.
 1009    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1010    pub display_map: Entity<DisplayMap>,
 1011    pub selections: SelectionsCollection,
 1012    pub scroll_manager: ScrollManager,
 1013    /// When inline assist editors are linked, they all render cursors because
 1014    /// typing enters text into each of them, even the ones that aren't focused.
 1015    pub(crate) show_cursor_when_unfocused: bool,
 1016    columnar_selection_state: Option<ColumnarSelectionState>,
 1017    add_selections_state: Option<AddSelectionsState>,
 1018    select_next_state: Option<SelectNextState>,
 1019    select_prev_state: Option<SelectNextState>,
 1020    selection_history: SelectionHistory,
 1021    defer_selection_effects: bool,
 1022    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1023    autoclose_regions: Vec<AutocloseRegion>,
 1024    snippet_stack: InvalidationStack<SnippetState>,
 1025    select_syntax_node_history: SelectSyntaxNodeHistory,
 1026    ime_transaction: Option<TransactionId>,
 1027    pub diagnostics_max_severity: DiagnosticSeverity,
 1028    active_diagnostics: ActiveDiagnostic,
 1029    show_inline_diagnostics: bool,
 1030    inline_diagnostics_update: Task<()>,
 1031    inline_diagnostics_enabled: bool,
 1032    diagnostics_enabled: bool,
 1033    word_completions_enabled: bool,
 1034    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1035    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1036    hard_wrap: Option<usize>,
 1037    project: Option<Entity<Project>>,
 1038    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1039    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1040    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1041    blink_manager: Entity<BlinkManager>,
 1042    show_cursor_names: bool,
 1043    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1044    pub show_local_selections: bool,
 1045    mode: EditorMode,
 1046    show_breadcrumbs: bool,
 1047    show_gutter: bool,
 1048    show_scrollbars: ScrollbarAxes,
 1049    minimap_visibility: MinimapVisibility,
 1050    offset_content: bool,
 1051    disable_expand_excerpt_buttons: bool,
 1052    show_line_numbers: Option<bool>,
 1053    use_relative_line_numbers: Option<bool>,
 1054    show_git_diff_gutter: Option<bool>,
 1055    show_code_actions: Option<bool>,
 1056    show_runnables: Option<bool>,
 1057    show_breakpoints: Option<bool>,
 1058    show_wrap_guides: Option<bool>,
 1059    show_indent_guides: Option<bool>,
 1060    placeholder_text: Option<Arc<str>>,
 1061    highlight_order: usize,
 1062    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1063    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1064    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1065    scrollbar_marker_state: ScrollbarMarkerState,
 1066    active_indent_guides_state: ActiveIndentGuidesState,
 1067    nav_history: Option<ItemNavHistory>,
 1068    context_menu: RefCell<Option<CodeContextMenu>>,
 1069    context_menu_options: Option<ContextMenuOptions>,
 1070    mouse_context_menu: Option<MouseContextMenu>,
 1071    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1072    inline_blame_popover: Option<InlineBlamePopover>,
 1073    inline_blame_popover_show_task: Option<Task<()>>,
 1074    signature_help_state: SignatureHelpState,
 1075    auto_signature_help: Option<bool>,
 1076    find_all_references_task_sources: Vec<Anchor>,
 1077    next_completion_id: CompletionId,
 1078    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1079    code_actions_task: Option<Task<Result<()>>>,
 1080    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1081    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1082    document_highlights_task: Option<Task<()>>,
 1083    linked_editing_range_task: Option<Task<Option<()>>>,
 1084    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1085    pending_rename: Option<RenameState>,
 1086    searchable: bool,
 1087    cursor_shape: CursorShape,
 1088    current_line_highlight: Option<CurrentLineHighlight>,
 1089    collapse_matches: bool,
 1090    autoindent_mode: Option<AutoindentMode>,
 1091    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1092    input_enabled: bool,
 1093    use_modal_editing: bool,
 1094    read_only: bool,
 1095    leader_id: Option<CollaboratorId>,
 1096    remote_id: Option<ViewId>,
 1097    pub hover_state: HoverState,
 1098    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1099    gutter_hovered: bool,
 1100    hovered_link_state: Option<HoveredLinkState>,
 1101    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1102    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1103    active_edit_prediction: Option<EditPredictionState>,
 1104    /// Used to prevent flickering as the user types while the menu is open
 1105    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1106    edit_prediction_settings: EditPredictionSettings,
 1107    edit_predictions_hidden_for_vim_mode: bool,
 1108    show_edit_predictions_override: Option<bool>,
 1109    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1110    edit_prediction_preview: EditPredictionPreview,
 1111    edit_prediction_indent_conflict: bool,
 1112    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1113    inlay_hint_cache: InlayHintCache,
 1114    next_inlay_id: usize,
 1115    _subscriptions: Vec<Subscription>,
 1116    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1117    gutter_dimensions: GutterDimensions,
 1118    style: Option<EditorStyle>,
 1119    text_style_refinement: Option<TextStyleRefinement>,
 1120    next_editor_action_id: EditorActionId,
 1121    editor_actions: Rc<
 1122        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1123    >,
 1124    use_autoclose: bool,
 1125    use_auto_surround: bool,
 1126    auto_replace_emoji_shortcode: bool,
 1127    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1128    show_git_blame_gutter: bool,
 1129    show_git_blame_inline: bool,
 1130    show_git_blame_inline_delay_task: Option<Task<()>>,
 1131    git_blame_inline_enabled: bool,
 1132    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1133    serialize_dirty_buffers: bool,
 1134    show_selection_menu: Option<bool>,
 1135    blame: Option<Entity<GitBlame>>,
 1136    blame_subscription: Option<Subscription>,
 1137    custom_context_menu: Option<
 1138        Box<
 1139            dyn 'static
 1140                + Fn(
 1141                    &mut Self,
 1142                    DisplayPoint,
 1143                    &mut Window,
 1144                    &mut Context<Self>,
 1145                ) -> Option<Entity<ui::ContextMenu>>,
 1146        >,
 1147    >,
 1148    last_bounds: Option<Bounds<Pixels>>,
 1149    last_position_map: Option<Rc<PositionMap>>,
 1150    expect_bounds_change: Option<Bounds<Pixels>>,
 1151    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1152    tasks_update_task: Option<Task<()>>,
 1153    breakpoint_store: Option<Entity<BreakpointStore>>,
 1154    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1155    hovered_diff_hunk_row: Option<DisplayRow>,
 1156    pull_diagnostics_task: Task<()>,
 1157    in_project_search: bool,
 1158    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1159    breadcrumb_header: Option<String>,
 1160    focused_block: Option<FocusedBlock>,
 1161    next_scroll_position: NextScrollCursorCenterTopBottom,
 1162    addons: HashMap<TypeId, Box<dyn Addon>>,
 1163    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1164    load_diff_task: Option<Shared<Task<()>>>,
 1165    /// Whether we are temporarily displaying a diff other than git's
 1166    temporary_diff_override: bool,
 1167    selection_mark_mode: bool,
 1168    toggle_fold_multiple_buffers: Task<()>,
 1169    _scroll_cursor_center_top_bottom_task: Task<()>,
 1170    serialize_selections: Task<()>,
 1171    serialize_folds: Task<()>,
 1172    mouse_cursor_hidden: bool,
 1173    minimap: Option<Entity<Self>>,
 1174    hide_mouse_mode: HideMouseMode,
 1175    pub change_list: ChangeList,
 1176    inline_value_cache: InlineValueCache,
 1177    selection_drag_state: SelectionDragState,
 1178    next_color_inlay_id: usize,
 1179    colors: Option<LspColorData>,
 1180    folding_newlines: Task<()>,
 1181}
 1182
 1183#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1184enum NextScrollCursorCenterTopBottom {
 1185    #[default]
 1186    Center,
 1187    Top,
 1188    Bottom,
 1189}
 1190
 1191impl NextScrollCursorCenterTopBottom {
 1192    fn next(&self) -> Self {
 1193        match self {
 1194            Self::Center => Self::Top,
 1195            Self::Top => Self::Bottom,
 1196            Self::Bottom => Self::Center,
 1197        }
 1198    }
 1199}
 1200
 1201#[derive(Clone)]
 1202pub struct EditorSnapshot {
 1203    pub mode: EditorMode,
 1204    show_gutter: bool,
 1205    show_line_numbers: Option<bool>,
 1206    show_git_diff_gutter: Option<bool>,
 1207    show_code_actions: Option<bool>,
 1208    show_runnables: Option<bool>,
 1209    show_breakpoints: Option<bool>,
 1210    git_blame_gutter_max_author_length: Option<usize>,
 1211    pub display_snapshot: DisplaySnapshot,
 1212    pub placeholder_text: Option<Arc<str>>,
 1213    is_focused: bool,
 1214    scroll_anchor: ScrollAnchor,
 1215    ongoing_scroll: OngoingScroll,
 1216    current_line_highlight: CurrentLineHighlight,
 1217    gutter_hovered: bool,
 1218}
 1219
 1220#[derive(Default, Debug, Clone, Copy)]
 1221pub struct GutterDimensions {
 1222    pub left_padding: Pixels,
 1223    pub right_padding: Pixels,
 1224    pub width: Pixels,
 1225    pub margin: Pixels,
 1226    pub git_blame_entries_width: Option<Pixels>,
 1227}
 1228
 1229impl GutterDimensions {
 1230    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1231        Self {
 1232            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1233            ..Default::default()
 1234        }
 1235    }
 1236
 1237    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1238        -cx.text_system().descent(font_id, font_size)
 1239    }
 1240    /// The full width of the space taken up by the gutter.
 1241    pub fn full_width(&self) -> Pixels {
 1242        self.margin + self.width
 1243    }
 1244
 1245    /// The width of the space reserved for the fold indicators,
 1246    /// use alongside 'justify_end' and `gutter_width` to
 1247    /// right align content with the line numbers
 1248    pub fn fold_area_width(&self) -> Pixels {
 1249        self.margin + self.right_padding
 1250    }
 1251}
 1252
 1253struct CharacterDimensions {
 1254    em_width: Pixels,
 1255    em_advance: Pixels,
 1256    line_height: Pixels,
 1257}
 1258
 1259#[derive(Debug)]
 1260pub struct RemoteSelection {
 1261    pub replica_id: ReplicaId,
 1262    pub selection: Selection<Anchor>,
 1263    pub cursor_shape: CursorShape,
 1264    pub collaborator_id: CollaboratorId,
 1265    pub line_mode: bool,
 1266    pub user_name: Option<SharedString>,
 1267    pub color: PlayerColor,
 1268}
 1269
 1270#[derive(Clone, Debug)]
 1271struct SelectionHistoryEntry {
 1272    selections: Arc<[Selection<Anchor>]>,
 1273    select_next_state: Option<SelectNextState>,
 1274    select_prev_state: Option<SelectNextState>,
 1275    add_selections_state: Option<AddSelectionsState>,
 1276}
 1277
 1278#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1279enum SelectionHistoryMode {
 1280    Normal,
 1281    Undoing,
 1282    Redoing,
 1283    Skipping,
 1284}
 1285
 1286#[derive(Clone, PartialEq, Eq, Hash)]
 1287struct HoveredCursor {
 1288    replica_id: u16,
 1289    selection_id: usize,
 1290}
 1291
 1292impl Default for SelectionHistoryMode {
 1293    fn default() -> Self {
 1294        Self::Normal
 1295    }
 1296}
 1297
 1298#[derive(Debug)]
 1299/// SelectionEffects controls the side-effects of updating the selection.
 1300///
 1301/// The default behaviour does "what you mostly want":
 1302/// - it pushes to the nav history if the cursor moved by >10 lines
 1303/// - it re-triggers completion requests
 1304/// - it scrolls to fit
 1305///
 1306/// You might want to modify these behaviours. For example when doing a "jump"
 1307/// like go to definition, we always want to add to nav history; but when scrolling
 1308/// in vim mode we never do.
 1309///
 1310/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1311/// move.
 1312#[derive(Clone)]
 1313pub struct SelectionEffects {
 1314    nav_history: Option<bool>,
 1315    completions: bool,
 1316    scroll: Option<Autoscroll>,
 1317}
 1318
 1319impl Default for SelectionEffects {
 1320    fn default() -> Self {
 1321        Self {
 1322            nav_history: None,
 1323            completions: true,
 1324            scroll: Some(Autoscroll::fit()),
 1325        }
 1326    }
 1327}
 1328impl SelectionEffects {
 1329    pub fn scroll(scroll: Autoscroll) -> Self {
 1330        Self {
 1331            scroll: Some(scroll),
 1332            ..Default::default()
 1333        }
 1334    }
 1335
 1336    pub fn no_scroll() -> Self {
 1337        Self {
 1338            scroll: None,
 1339            ..Default::default()
 1340        }
 1341    }
 1342
 1343    pub fn completions(self, completions: bool) -> Self {
 1344        Self {
 1345            completions,
 1346            ..self
 1347        }
 1348    }
 1349
 1350    pub fn nav_history(self, nav_history: bool) -> Self {
 1351        Self {
 1352            nav_history: Some(nav_history),
 1353            ..self
 1354        }
 1355    }
 1356}
 1357
 1358struct DeferredSelectionEffectsState {
 1359    changed: bool,
 1360    effects: SelectionEffects,
 1361    old_cursor_position: Anchor,
 1362    history_entry: SelectionHistoryEntry,
 1363}
 1364
 1365#[derive(Default)]
 1366struct SelectionHistory {
 1367    #[allow(clippy::type_complexity)]
 1368    selections_by_transaction:
 1369        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1370    mode: SelectionHistoryMode,
 1371    undo_stack: VecDeque<SelectionHistoryEntry>,
 1372    redo_stack: VecDeque<SelectionHistoryEntry>,
 1373}
 1374
 1375impl SelectionHistory {
 1376    #[track_caller]
 1377    fn insert_transaction(
 1378        &mut self,
 1379        transaction_id: TransactionId,
 1380        selections: Arc<[Selection<Anchor>]>,
 1381    ) {
 1382        if selections.is_empty() {
 1383            log::error!(
 1384                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1385                std::panic::Location::caller()
 1386            );
 1387            return;
 1388        }
 1389        self.selections_by_transaction
 1390            .insert(transaction_id, (selections, None));
 1391    }
 1392
 1393    #[allow(clippy::type_complexity)]
 1394    fn transaction(
 1395        &self,
 1396        transaction_id: TransactionId,
 1397    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1398        self.selections_by_transaction.get(&transaction_id)
 1399    }
 1400
 1401    #[allow(clippy::type_complexity)]
 1402    fn transaction_mut(
 1403        &mut self,
 1404        transaction_id: TransactionId,
 1405    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1406        self.selections_by_transaction.get_mut(&transaction_id)
 1407    }
 1408
 1409    fn push(&mut self, entry: SelectionHistoryEntry) {
 1410        if !entry.selections.is_empty() {
 1411            match self.mode {
 1412                SelectionHistoryMode::Normal => {
 1413                    self.push_undo(entry);
 1414                    self.redo_stack.clear();
 1415                }
 1416                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1417                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1418                SelectionHistoryMode::Skipping => {}
 1419            }
 1420        }
 1421    }
 1422
 1423    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1424        if self
 1425            .undo_stack
 1426            .back()
 1427            .is_none_or(|e| e.selections != entry.selections)
 1428        {
 1429            self.undo_stack.push_back(entry);
 1430            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1431                self.undo_stack.pop_front();
 1432            }
 1433        }
 1434    }
 1435
 1436    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1437        if self
 1438            .redo_stack
 1439            .back()
 1440            .is_none_or(|e| e.selections != entry.selections)
 1441        {
 1442            self.redo_stack.push_back(entry);
 1443            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1444                self.redo_stack.pop_front();
 1445            }
 1446        }
 1447    }
 1448}
 1449
 1450#[derive(Clone, Copy)]
 1451pub struct RowHighlightOptions {
 1452    pub autoscroll: bool,
 1453    pub include_gutter: bool,
 1454}
 1455
 1456impl Default for RowHighlightOptions {
 1457    fn default() -> Self {
 1458        Self {
 1459            autoscroll: Default::default(),
 1460            include_gutter: true,
 1461        }
 1462    }
 1463}
 1464
 1465struct RowHighlight {
 1466    index: usize,
 1467    range: Range<Anchor>,
 1468    color: Hsla,
 1469    options: RowHighlightOptions,
 1470    type_id: TypeId,
 1471}
 1472
 1473#[derive(Clone, Debug)]
 1474struct AddSelectionsState {
 1475    groups: Vec<AddSelectionsGroup>,
 1476}
 1477
 1478#[derive(Clone, Debug)]
 1479struct AddSelectionsGroup {
 1480    above: bool,
 1481    stack: Vec<usize>,
 1482}
 1483
 1484#[derive(Clone)]
 1485struct SelectNextState {
 1486    query: AhoCorasick,
 1487    wordwise: bool,
 1488    done: bool,
 1489}
 1490
 1491impl std::fmt::Debug for SelectNextState {
 1492    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1493        f.debug_struct(std::any::type_name::<Self>())
 1494            .field("wordwise", &self.wordwise)
 1495            .field("done", &self.done)
 1496            .finish()
 1497    }
 1498}
 1499
 1500#[derive(Debug)]
 1501struct AutocloseRegion {
 1502    selection_id: usize,
 1503    range: Range<Anchor>,
 1504    pair: BracketPair,
 1505}
 1506
 1507#[derive(Debug)]
 1508struct SnippetState {
 1509    ranges: Vec<Vec<Range<Anchor>>>,
 1510    active_index: usize,
 1511    choices: Vec<Option<Vec<String>>>,
 1512}
 1513
 1514#[doc(hidden)]
 1515pub struct RenameState {
 1516    pub range: Range<Anchor>,
 1517    pub old_name: Arc<str>,
 1518    pub editor: Entity<Editor>,
 1519    block_id: CustomBlockId,
 1520}
 1521
 1522struct InvalidationStack<T>(Vec<T>);
 1523
 1524struct RegisteredEditPredictionProvider {
 1525    provider: Arc<dyn EditPredictionProviderHandle>,
 1526    _subscription: Subscription,
 1527}
 1528
 1529#[derive(Debug, PartialEq, Eq)]
 1530pub struct ActiveDiagnosticGroup {
 1531    pub active_range: Range<Anchor>,
 1532    pub active_message: String,
 1533    pub group_id: usize,
 1534    pub blocks: HashSet<CustomBlockId>,
 1535}
 1536
 1537#[derive(Debug, PartialEq, Eq)]
 1538
 1539pub(crate) enum ActiveDiagnostic {
 1540    None,
 1541    All,
 1542    Group(ActiveDiagnosticGroup),
 1543}
 1544
 1545#[derive(Serialize, Deserialize, Clone, Debug)]
 1546pub struct ClipboardSelection {
 1547    /// The number of bytes in this selection.
 1548    pub len: usize,
 1549    /// Whether this was a full-line selection.
 1550    pub is_entire_line: bool,
 1551    /// The indentation of the first line when this content was originally copied.
 1552    pub first_line_indent: u32,
 1553}
 1554
 1555// selections, scroll behavior, was newest selection reversed
 1556type SelectSyntaxNodeHistoryState = (
 1557    Box<[Selection<usize>]>,
 1558    SelectSyntaxNodeScrollBehavior,
 1559    bool,
 1560);
 1561
 1562#[derive(Default)]
 1563struct SelectSyntaxNodeHistory {
 1564    stack: Vec<SelectSyntaxNodeHistoryState>,
 1565    // disable temporarily to allow changing selections without losing the stack
 1566    pub disable_clearing: bool,
 1567}
 1568
 1569impl SelectSyntaxNodeHistory {
 1570    pub fn try_clear(&mut self) {
 1571        if !self.disable_clearing {
 1572            self.stack.clear();
 1573        }
 1574    }
 1575
 1576    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1577        self.stack.push(selection);
 1578    }
 1579
 1580    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1581        self.stack.pop()
 1582    }
 1583}
 1584
 1585enum SelectSyntaxNodeScrollBehavior {
 1586    CursorTop,
 1587    FitSelection,
 1588    CursorBottom,
 1589}
 1590
 1591#[derive(Debug)]
 1592pub(crate) struct NavigationData {
 1593    cursor_anchor: Anchor,
 1594    cursor_position: Point,
 1595    scroll_anchor: ScrollAnchor,
 1596    scroll_top_row: u32,
 1597}
 1598
 1599#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1600pub enum GotoDefinitionKind {
 1601    Symbol,
 1602    Declaration,
 1603    Type,
 1604    Implementation,
 1605}
 1606
 1607#[derive(Debug, Clone)]
 1608enum InlayHintRefreshReason {
 1609    ModifiersChanged(bool),
 1610    Toggle(bool),
 1611    SettingsChange(InlayHintSettings),
 1612    NewLinesShown,
 1613    BufferEdited(HashSet<Arc<Language>>),
 1614    RefreshRequested,
 1615    ExcerptsRemoved(Vec<ExcerptId>),
 1616}
 1617
 1618impl InlayHintRefreshReason {
 1619    fn description(&self) -> &'static str {
 1620        match self {
 1621            Self::ModifiersChanged(_) => "modifiers changed",
 1622            Self::Toggle(_) => "toggle",
 1623            Self::SettingsChange(_) => "settings change",
 1624            Self::NewLinesShown => "new lines shown",
 1625            Self::BufferEdited(_) => "buffer edited",
 1626            Self::RefreshRequested => "refresh requested",
 1627            Self::ExcerptsRemoved(_) => "excerpts removed",
 1628        }
 1629    }
 1630}
 1631
 1632pub enum FormatTarget {
 1633    Buffers(HashSet<Entity<Buffer>>),
 1634    Ranges(Vec<Range<MultiBufferPoint>>),
 1635}
 1636
 1637pub(crate) struct FocusedBlock {
 1638    id: BlockId,
 1639    focus_handle: WeakFocusHandle,
 1640}
 1641
 1642#[derive(Clone)]
 1643enum JumpData {
 1644    MultiBufferRow {
 1645        row: MultiBufferRow,
 1646        line_offset_from_top: u32,
 1647    },
 1648    MultiBufferPoint {
 1649        excerpt_id: ExcerptId,
 1650        position: Point,
 1651        anchor: text::Anchor,
 1652        line_offset_from_top: u32,
 1653    },
 1654}
 1655
 1656pub enum MultibufferSelectionMode {
 1657    First,
 1658    All,
 1659}
 1660
 1661#[derive(Clone, Copy, Debug, Default)]
 1662pub struct RewrapOptions {
 1663    pub override_language_settings: bool,
 1664    pub preserve_existing_whitespace: bool,
 1665}
 1666
 1667impl Editor {
 1668    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1669        let buffer = cx.new(|cx| Buffer::local("", cx));
 1670        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1671        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1672    }
 1673
 1674    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(EditorMode::full(), buffer, None, window, cx)
 1678    }
 1679
 1680    pub fn auto_height(
 1681        min_lines: usize,
 1682        max_lines: usize,
 1683        window: &mut Window,
 1684        cx: &mut Context<Self>,
 1685    ) -> Self {
 1686        let buffer = cx.new(|cx| Buffer::local("", cx));
 1687        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1688        Self::new(
 1689            EditorMode::AutoHeight {
 1690                min_lines,
 1691                max_lines: Some(max_lines),
 1692            },
 1693            buffer,
 1694            None,
 1695            window,
 1696            cx,
 1697        )
 1698    }
 1699
 1700    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1701    /// The editor grows as tall as needed to fit its content.
 1702    pub fn auto_height_unbounded(
 1703        min_lines: usize,
 1704        window: &mut Window,
 1705        cx: &mut Context<Self>,
 1706    ) -> Self {
 1707        let buffer = cx.new(|cx| Buffer::local("", cx));
 1708        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1709        Self::new(
 1710            EditorMode::AutoHeight {
 1711                min_lines,
 1712                max_lines: None,
 1713            },
 1714            buffer,
 1715            None,
 1716            window,
 1717            cx,
 1718        )
 1719    }
 1720
 1721    pub fn for_buffer(
 1722        buffer: Entity<Buffer>,
 1723        project: Option<Entity<Project>>,
 1724        window: &mut Window,
 1725        cx: &mut Context<Self>,
 1726    ) -> Self {
 1727        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1728        Self::new(EditorMode::full(), buffer, project, window, cx)
 1729    }
 1730
 1731    pub fn for_multibuffer(
 1732        buffer: Entity<MultiBuffer>,
 1733        project: Option<Entity<Project>>,
 1734        window: &mut Window,
 1735        cx: &mut Context<Self>,
 1736    ) -> Self {
 1737        Self::new(EditorMode::full(), buffer, project, window, cx)
 1738    }
 1739
 1740    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1741        let mut clone = Self::new(
 1742            self.mode.clone(),
 1743            self.buffer.clone(),
 1744            self.project.clone(),
 1745            window,
 1746            cx,
 1747        );
 1748        self.display_map.update(cx, |display_map, cx| {
 1749            let snapshot = display_map.snapshot(cx);
 1750            clone.display_map.update(cx, |display_map, cx| {
 1751                display_map.set_state(&snapshot, cx);
 1752            });
 1753        });
 1754        clone.folds_did_change(cx);
 1755        clone.selections.clone_state(&self.selections);
 1756        clone.scroll_manager.clone_state(&self.scroll_manager);
 1757        clone.searchable = self.searchable;
 1758        clone.read_only = self.read_only;
 1759        clone
 1760    }
 1761
 1762    pub fn new(
 1763        mode: EditorMode,
 1764        buffer: Entity<MultiBuffer>,
 1765        project: Option<Entity<Project>>,
 1766        window: &mut Window,
 1767        cx: &mut Context<Self>,
 1768    ) -> Self {
 1769        Editor::new_internal(mode, buffer, project, None, window, cx)
 1770    }
 1771
 1772    fn new_internal(
 1773        mode: EditorMode,
 1774        buffer: Entity<MultiBuffer>,
 1775        project: Option<Entity<Project>>,
 1776        display_map: Option<Entity<DisplayMap>>,
 1777        window: &mut Window,
 1778        cx: &mut Context<Self>,
 1779    ) -> Self {
 1780        debug_assert!(
 1781            display_map.is_none() || mode.is_minimap(),
 1782            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1783        );
 1784
 1785        let full_mode = mode.is_full();
 1786        let is_minimap = mode.is_minimap();
 1787        let diagnostics_max_severity = if full_mode {
 1788            EditorSettings::get_global(cx)
 1789                .diagnostics_max_severity
 1790                .unwrap_or(DiagnosticSeverity::Hint)
 1791        } else {
 1792            DiagnosticSeverity::Off
 1793        };
 1794        let style = window.text_style();
 1795        let font_size = style.font_size.to_pixels(window.rem_size());
 1796        let editor = cx.entity().downgrade();
 1797        let fold_placeholder = FoldPlaceholder {
 1798            constrain_width: false,
 1799            render: Arc::new(move |fold_id, fold_range, cx| {
 1800                let editor = editor.clone();
 1801                div()
 1802                    .id(fold_id)
 1803                    .bg(cx.theme().colors().ghost_element_background)
 1804                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1805                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1806                    .rounded_xs()
 1807                    .size_full()
 1808                    .cursor_pointer()
 1809                    .child("")
 1810                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1811                    .on_click(move |_, _window, cx| {
 1812                        editor
 1813                            .update(cx, |editor, cx| {
 1814                                editor.unfold_ranges(
 1815                                    &[fold_range.start..fold_range.end],
 1816                                    true,
 1817                                    false,
 1818                                    cx,
 1819                                );
 1820                                cx.stop_propagation();
 1821                            })
 1822                            .ok();
 1823                    })
 1824                    .into_any()
 1825            }),
 1826            merge_adjacent: true,
 1827            ..FoldPlaceholder::default()
 1828        };
 1829        let display_map = display_map.unwrap_or_else(|| {
 1830            cx.new(|cx| {
 1831                DisplayMap::new(
 1832                    buffer.clone(),
 1833                    style.font(),
 1834                    font_size,
 1835                    None,
 1836                    FILE_HEADER_HEIGHT,
 1837                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1838                    fold_placeholder,
 1839                    diagnostics_max_severity,
 1840                    cx,
 1841                )
 1842            })
 1843        });
 1844
 1845        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1846
 1847        let blink_manager = cx.new(|cx| {
 1848            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1849            if is_minimap {
 1850                blink_manager.disable(cx);
 1851            }
 1852            blink_manager
 1853        });
 1854
 1855        let soft_wrap_mode_override =
 1856            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1857
 1858        let mut project_subscriptions = Vec::new();
 1859        if full_mode && let Some(project) = project.as_ref() {
 1860            project_subscriptions.push(cx.subscribe_in(
 1861                project,
 1862                window,
 1863                |editor, _, event, window, cx| match event {
 1864                    project::Event::RefreshCodeLens => {
 1865                        // we always query lens with actions, without storing them, always refreshing them
 1866                    }
 1867                    project::Event::RefreshInlayHints => {
 1868                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1869                    }
 1870                    project::Event::LanguageServerAdded(..)
 1871                    | project::Event::LanguageServerRemoved(..) => {
 1872                        if editor.tasks_update_task.is_none() {
 1873                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1874                        }
 1875                    }
 1876                    project::Event::SnippetEdit(id, snippet_edits) => {
 1877                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1878                            let focus_handle = editor.focus_handle(cx);
 1879                            if focus_handle.is_focused(window) {
 1880                                let snapshot = buffer.read(cx).snapshot();
 1881                                for (range, snippet) in snippet_edits {
 1882                                    let editor_range =
 1883                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1884                                    editor
 1885                                        .insert_snippet(
 1886                                            &[editor_range],
 1887                                            snippet.clone(),
 1888                                            window,
 1889                                            cx,
 1890                                        )
 1891                                        .ok();
 1892                                }
 1893                            }
 1894                        }
 1895                    }
 1896                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1897                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1898                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1899                        }
 1900                    }
 1901
 1902                    project::Event::EntryRenamed(transaction) => {
 1903                        let Some(workspace) = editor.workspace() else {
 1904                            return;
 1905                        };
 1906                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1907                        else {
 1908                            return;
 1909                        };
 1910                        if active_editor.entity_id() == cx.entity_id() {
 1911                            let edited_buffers_already_open = {
 1912                                let other_editors: Vec<Entity<Editor>> = workspace
 1913                                    .read(cx)
 1914                                    .panes()
 1915                                    .iter()
 1916                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1917                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1918                                    .collect();
 1919
 1920                                transaction.0.keys().all(|buffer| {
 1921                                    other_editors.iter().any(|editor| {
 1922                                        let multi_buffer = editor.read(cx).buffer();
 1923                                        multi_buffer.read(cx).is_singleton()
 1924                                            && multi_buffer.read(cx).as_singleton().map_or(
 1925                                                false,
 1926                                                |singleton| {
 1927                                                    singleton.entity_id() == buffer.entity_id()
 1928                                                },
 1929                                            )
 1930                                    })
 1931                                })
 1932                            };
 1933
 1934                            if !edited_buffers_already_open {
 1935                                let workspace = workspace.downgrade();
 1936                                let transaction = transaction.clone();
 1937                                cx.defer_in(window, move |_, window, cx| {
 1938                                    cx.spawn_in(window, async move |editor, cx| {
 1939                                        Self::open_project_transaction(
 1940                                            &editor,
 1941                                            workspace,
 1942                                            transaction,
 1943                                            "Rename".to_string(),
 1944                                            cx,
 1945                                        )
 1946                                        .await
 1947                                        .ok()
 1948                                    })
 1949                                    .detach();
 1950                                });
 1951                            }
 1952                        }
 1953                    }
 1954
 1955                    _ => {}
 1956                },
 1957            ));
 1958            if let Some(task_inventory) = project
 1959                .read(cx)
 1960                .task_store()
 1961                .read(cx)
 1962                .task_inventory()
 1963                .cloned()
 1964            {
 1965                project_subscriptions.push(cx.observe_in(
 1966                    &task_inventory,
 1967                    window,
 1968                    |editor, _, window, cx| {
 1969                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1970                    },
 1971                ));
 1972            };
 1973
 1974            project_subscriptions.push(cx.subscribe_in(
 1975                &project.read(cx).breakpoint_store(),
 1976                window,
 1977                |editor, _, event, window, cx| match event {
 1978                    BreakpointStoreEvent::ClearDebugLines => {
 1979                        editor.clear_row_highlights::<ActiveDebugLine>();
 1980                        editor.refresh_inline_values(cx);
 1981                    }
 1982                    BreakpointStoreEvent::SetDebugLine => {
 1983                        if editor.go_to_active_debug_line(window, cx) {
 1984                            cx.stop_propagation();
 1985                        }
 1986
 1987                        editor.refresh_inline_values(cx);
 1988                    }
 1989                    _ => {}
 1990                },
 1991            ));
 1992            let git_store = project.read(cx).git_store().clone();
 1993            let project = project.clone();
 1994            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1995                if let GitStoreEvent::RepositoryUpdated(
 1996                    _,
 1997                    RepositoryEvent::Updated {
 1998                        new_instance: true, ..
 1999                    },
 2000                    _,
 2001                ) = event
 2002                {
 2003                    this.load_diff_task = Some(
 2004                        update_uncommitted_diff_for_buffer(
 2005                            cx.entity(),
 2006                            &project,
 2007                            this.buffer.read(cx).all_buffers(),
 2008                            this.buffer.clone(),
 2009                            cx,
 2010                        )
 2011                        .shared(),
 2012                    );
 2013                }
 2014            }));
 2015        }
 2016
 2017        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2018
 2019        let inlay_hint_settings =
 2020            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2021        let focus_handle = cx.focus_handle();
 2022        if !is_minimap {
 2023            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2024                .detach();
 2025            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2026                .detach();
 2027            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2028                .detach();
 2029            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2030                .detach();
 2031            cx.observe_pending_input(window, Self::observe_pending_input)
 2032                .detach();
 2033        }
 2034
 2035        let show_indent_guides =
 2036            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2037                Some(false)
 2038            } else {
 2039                None
 2040            };
 2041
 2042        let breakpoint_store = match (&mode, project.as_ref()) {
 2043            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2044            _ => None,
 2045        };
 2046
 2047        let mut code_action_providers = Vec::new();
 2048        let mut load_uncommitted_diff = None;
 2049        if let Some(project) = project.clone() {
 2050            load_uncommitted_diff = Some(
 2051                update_uncommitted_diff_for_buffer(
 2052                    cx.entity(),
 2053                    &project,
 2054                    buffer.read(cx).all_buffers(),
 2055                    buffer.clone(),
 2056                    cx,
 2057                )
 2058                .shared(),
 2059            );
 2060            code_action_providers.push(Rc::new(project) as Rc<_>);
 2061        }
 2062
 2063        let mut editor = Self {
 2064            focus_handle,
 2065            show_cursor_when_unfocused: false,
 2066            last_focused_descendant: None,
 2067            buffer: buffer.clone(),
 2068            display_map: display_map.clone(),
 2069            selections,
 2070            scroll_manager: ScrollManager::new(cx),
 2071            columnar_selection_state: None,
 2072            add_selections_state: None,
 2073            select_next_state: None,
 2074            select_prev_state: None,
 2075            selection_history: SelectionHistory::default(),
 2076            defer_selection_effects: false,
 2077            deferred_selection_effects_state: None,
 2078            autoclose_regions: Vec::new(),
 2079            snippet_stack: InvalidationStack::default(),
 2080            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2081            ime_transaction: None,
 2082            active_diagnostics: ActiveDiagnostic::None,
 2083            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2084            inline_diagnostics_update: Task::ready(()),
 2085            inline_diagnostics: Vec::new(),
 2086            soft_wrap_mode_override,
 2087            diagnostics_max_severity,
 2088            hard_wrap: None,
 2089            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2090            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2091            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2092            project,
 2093            blink_manager: blink_manager.clone(),
 2094            show_local_selections: true,
 2095            show_scrollbars: ScrollbarAxes {
 2096                horizontal: full_mode,
 2097                vertical: full_mode,
 2098            },
 2099            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2100            offset_content: !matches!(mode, EditorMode::SingleLine),
 2101            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2102            show_gutter: full_mode,
 2103            show_line_numbers: (!full_mode).then_some(false),
 2104            use_relative_line_numbers: None,
 2105            disable_expand_excerpt_buttons: !full_mode,
 2106            show_git_diff_gutter: None,
 2107            show_code_actions: None,
 2108            show_runnables: None,
 2109            show_breakpoints: None,
 2110            show_wrap_guides: None,
 2111            show_indent_guides,
 2112            placeholder_text: None,
 2113            highlight_order: 0,
 2114            highlighted_rows: HashMap::default(),
 2115            background_highlights: HashMap::default(),
 2116            gutter_highlights: HashMap::default(),
 2117            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2118            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2119            nav_history: None,
 2120            context_menu: RefCell::new(None),
 2121            context_menu_options: None,
 2122            mouse_context_menu: None,
 2123            completion_tasks: Vec::new(),
 2124            inline_blame_popover: None,
 2125            inline_blame_popover_show_task: None,
 2126            signature_help_state: SignatureHelpState::default(),
 2127            auto_signature_help: None,
 2128            find_all_references_task_sources: Vec::new(),
 2129            next_completion_id: 0,
 2130            next_inlay_id: 0,
 2131            code_action_providers,
 2132            available_code_actions: None,
 2133            code_actions_task: None,
 2134            quick_selection_highlight_task: None,
 2135            debounced_selection_highlight_task: None,
 2136            document_highlights_task: None,
 2137            linked_editing_range_task: None,
 2138            pending_rename: None,
 2139            searchable: !is_minimap,
 2140            cursor_shape: EditorSettings::get_global(cx)
 2141                .cursor_shape
 2142                .unwrap_or_default(),
 2143            current_line_highlight: None,
 2144            autoindent_mode: Some(AutoindentMode::EachLine),
 2145            collapse_matches: false,
 2146            workspace: None,
 2147            input_enabled: !is_minimap,
 2148            use_modal_editing: full_mode,
 2149            read_only: is_minimap,
 2150            use_autoclose: true,
 2151            use_auto_surround: true,
 2152            auto_replace_emoji_shortcode: false,
 2153            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2154            leader_id: None,
 2155            remote_id: None,
 2156            hover_state: HoverState::default(),
 2157            pending_mouse_down: None,
 2158            hovered_link_state: None,
 2159            edit_prediction_provider: None,
 2160            active_edit_prediction: None,
 2161            stale_edit_prediction_in_menu: None,
 2162            edit_prediction_preview: EditPredictionPreview::Inactive {
 2163                released_too_fast: false,
 2164            },
 2165            inline_diagnostics_enabled: full_mode,
 2166            diagnostics_enabled: full_mode,
 2167            word_completions_enabled: full_mode,
 2168            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2169            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2170            gutter_hovered: false,
 2171            pixel_position_of_newest_cursor: None,
 2172            last_bounds: None,
 2173            last_position_map: None,
 2174            expect_bounds_change: None,
 2175            gutter_dimensions: GutterDimensions::default(),
 2176            style: None,
 2177            show_cursor_names: false,
 2178            hovered_cursors: HashMap::default(),
 2179            next_editor_action_id: EditorActionId::default(),
 2180            editor_actions: Rc::default(),
 2181            edit_predictions_hidden_for_vim_mode: false,
 2182            show_edit_predictions_override: None,
 2183            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2184            edit_prediction_settings: EditPredictionSettings::Disabled,
 2185            edit_prediction_indent_conflict: false,
 2186            edit_prediction_requires_modifier_in_indent_conflict: true,
 2187            custom_context_menu: None,
 2188            show_git_blame_gutter: false,
 2189            show_git_blame_inline: false,
 2190            show_selection_menu: None,
 2191            show_git_blame_inline_delay_task: None,
 2192            git_blame_inline_enabled: full_mode
 2193                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2194            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2195            serialize_dirty_buffers: !is_minimap
 2196                && ProjectSettings::get_global(cx)
 2197                    .session
 2198                    .restore_unsaved_buffers,
 2199            blame: None,
 2200            blame_subscription: None,
 2201            tasks: BTreeMap::default(),
 2202
 2203            breakpoint_store,
 2204            gutter_breakpoint_indicator: (None, None),
 2205            hovered_diff_hunk_row: None,
 2206            _subscriptions: (!is_minimap)
 2207                .then(|| {
 2208                    vec![
 2209                        cx.observe(&buffer, Self::on_buffer_changed),
 2210                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2211                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2212                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2213                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2214                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2215                        cx.observe_window_activation(window, |editor, window, cx| {
 2216                            let active = window.is_window_active();
 2217                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2218                                if active {
 2219                                    blink_manager.enable(cx);
 2220                                } else {
 2221                                    blink_manager.disable(cx);
 2222                                }
 2223                            });
 2224                            if active {
 2225                                editor.show_mouse_cursor(cx);
 2226                            }
 2227                        }),
 2228                    ]
 2229                })
 2230                .unwrap_or_default(),
 2231            tasks_update_task: None,
 2232            pull_diagnostics_task: Task::ready(()),
 2233            colors: None,
 2234            next_color_inlay_id: 0,
 2235            linked_edit_ranges: Default::default(),
 2236            in_project_search: false,
 2237            previous_search_ranges: None,
 2238            breadcrumb_header: None,
 2239            focused_block: None,
 2240            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2241            addons: HashMap::default(),
 2242            registered_buffers: HashMap::default(),
 2243            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2244            selection_mark_mode: false,
 2245            toggle_fold_multiple_buffers: Task::ready(()),
 2246            serialize_selections: Task::ready(()),
 2247            serialize_folds: Task::ready(()),
 2248            text_style_refinement: None,
 2249            load_diff_task: load_uncommitted_diff,
 2250            temporary_diff_override: false,
 2251            mouse_cursor_hidden: false,
 2252            minimap: None,
 2253            hide_mouse_mode: EditorSettings::get_global(cx)
 2254                .hide_mouse
 2255                .unwrap_or_default(),
 2256            change_list: ChangeList::new(),
 2257            mode,
 2258            selection_drag_state: SelectionDragState::None,
 2259            folding_newlines: Task::ready(()),
 2260        };
 2261
 2262        if is_minimap {
 2263            return editor;
 2264        }
 2265
 2266        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2267            editor
 2268                ._subscriptions
 2269                .push(cx.observe(breakpoints, |_, _, cx| {
 2270                    cx.notify();
 2271                }));
 2272        }
 2273        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2274        editor._subscriptions.extend(project_subscriptions);
 2275
 2276        editor._subscriptions.push(cx.subscribe_in(
 2277            &cx.entity(),
 2278            window,
 2279            |editor, _, e: &EditorEvent, window, cx| match e {
 2280                EditorEvent::ScrollPositionChanged { local, .. } => {
 2281                    if *local {
 2282                        let new_anchor = editor.scroll_manager.anchor();
 2283                        let snapshot = editor.snapshot(window, cx);
 2284                        editor.update_restoration_data(cx, move |data| {
 2285                            data.scroll_position = (
 2286                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2287                                new_anchor.offset,
 2288                            );
 2289                        });
 2290                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2291                        editor.inline_blame_popover.take();
 2292                    }
 2293                }
 2294                EditorEvent::Edited { .. } => {
 2295                    if !vim_enabled(cx) {
 2296                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2297                        let pop_state = editor
 2298                            .change_list
 2299                            .last()
 2300                            .map(|previous| {
 2301                                previous.len() == selections.len()
 2302                                    && previous.iter().enumerate().all(|(ix, p)| {
 2303                                        p.to_display_point(&map).row()
 2304                                            == selections[ix].head().row()
 2305                                    })
 2306                            })
 2307                            .unwrap_or(false);
 2308                        let new_positions = selections
 2309                            .into_iter()
 2310                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2311                            .collect();
 2312                        editor
 2313                            .change_list
 2314                            .push_to_change_list(pop_state, new_positions);
 2315                    }
 2316                }
 2317                _ => (),
 2318            },
 2319        ));
 2320
 2321        if let Some(dap_store) = editor
 2322            .project
 2323            .as_ref()
 2324            .map(|project| project.read(cx).dap_store())
 2325        {
 2326            let weak_editor = cx.weak_entity();
 2327
 2328            editor
 2329                ._subscriptions
 2330                .push(
 2331                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2332                        let session_entity = cx.entity();
 2333                        weak_editor
 2334                            .update(cx, |editor, cx| {
 2335                                editor._subscriptions.push(
 2336                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2337                                );
 2338                            })
 2339                            .ok();
 2340                    }),
 2341                );
 2342
 2343            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2344                editor
 2345                    ._subscriptions
 2346                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2347            }
 2348        }
 2349
 2350        // skip adding the initial selection to selection history
 2351        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2352        editor.end_selection(window, cx);
 2353        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2354
 2355        editor.scroll_manager.show_scrollbars(window, cx);
 2356        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2357
 2358        if full_mode {
 2359            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2360            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2361
 2362            if editor.git_blame_inline_enabled {
 2363                editor.start_git_blame_inline(false, window, cx);
 2364            }
 2365
 2366            editor.go_to_active_debug_line(window, cx);
 2367
 2368            if let Some(buffer) = buffer.read(cx).as_singleton()
 2369                && let Some(project) = editor.project()
 2370            {
 2371                let handle = project.update(cx, |project, cx| {
 2372                    project.register_buffer_with_language_servers(&buffer, cx)
 2373                });
 2374                editor
 2375                    .registered_buffers
 2376                    .insert(buffer.read(cx).remote_id(), handle);
 2377            }
 2378
 2379            editor.minimap =
 2380                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2381            editor.colors = Some(LspColorData::new(cx));
 2382            editor.update_lsp_data(false, None, window, cx);
 2383        }
 2384
 2385        if editor.mode.is_full() {
 2386            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2387        }
 2388
 2389        editor
 2390    }
 2391
 2392    pub fn deploy_mouse_context_menu(
 2393        &mut self,
 2394        position: gpui::Point<Pixels>,
 2395        context_menu: Entity<ContextMenu>,
 2396        window: &mut Window,
 2397        cx: &mut Context<Self>,
 2398    ) {
 2399        self.mouse_context_menu = Some(MouseContextMenu::new(
 2400            self,
 2401            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2402            context_menu,
 2403            window,
 2404            cx,
 2405        ));
 2406    }
 2407
 2408    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2409        self.mouse_context_menu
 2410            .as_ref()
 2411            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2412    }
 2413
 2414    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2415        if self
 2416            .selections
 2417            .pending
 2418            .as_ref()
 2419            .is_some_and(|pending_selection| {
 2420                let snapshot = self.buffer().read(cx).snapshot(cx);
 2421                pending_selection
 2422                    .selection
 2423                    .range()
 2424                    .includes(range, &snapshot)
 2425            })
 2426        {
 2427            return true;
 2428        }
 2429
 2430        self.selections
 2431            .disjoint_in_range::<usize>(range.clone(), cx)
 2432            .into_iter()
 2433            .any(|selection| {
 2434                // This is needed to cover a corner case, if we just check for an existing
 2435                // selection in the fold range, having a cursor at the start of the fold
 2436                // marks it as selected. Non-empty selections don't cause this.
 2437                let length = selection.end - selection.start;
 2438                length > 0
 2439            })
 2440    }
 2441
 2442    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2443        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2444    }
 2445
 2446    fn key_context_internal(
 2447        &self,
 2448        has_active_edit_prediction: bool,
 2449        window: &Window,
 2450        cx: &App,
 2451    ) -> KeyContext {
 2452        let mut key_context = KeyContext::new_with_defaults();
 2453        key_context.add("Editor");
 2454        let mode = match self.mode {
 2455            EditorMode::SingleLine => "single_line",
 2456            EditorMode::AutoHeight { .. } => "auto_height",
 2457            EditorMode::Minimap { .. } => "minimap",
 2458            EditorMode::Full { .. } => "full",
 2459        };
 2460
 2461        if EditorSettings::jupyter_enabled(cx) {
 2462            key_context.add("jupyter");
 2463        }
 2464
 2465        key_context.set("mode", mode);
 2466        if self.pending_rename.is_some() {
 2467            key_context.add("renaming");
 2468        }
 2469
 2470        match self.context_menu.borrow().as_ref() {
 2471            Some(CodeContextMenu::Completions(menu)) => {
 2472                if menu.visible() {
 2473                    key_context.add("menu");
 2474                    key_context.add("showing_completions");
 2475                }
 2476            }
 2477            Some(CodeContextMenu::CodeActions(menu)) => {
 2478                if menu.visible() {
 2479                    key_context.add("menu");
 2480                    key_context.add("showing_code_actions")
 2481                }
 2482            }
 2483            None => {}
 2484        }
 2485
 2486        if self.signature_help_state.has_multiple_signatures() {
 2487            key_context.add("showing_signature_help");
 2488        }
 2489
 2490        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2491        if !self.focus_handle(cx).contains_focused(window, cx)
 2492            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2493        {
 2494            for addon in self.addons.values() {
 2495                addon.extend_key_context(&mut key_context, cx)
 2496            }
 2497        }
 2498
 2499        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2500            if let Some(extension) = singleton_buffer
 2501                .read(cx)
 2502                .file()
 2503                .and_then(|file| file.path().extension()?.to_str())
 2504            {
 2505                key_context.set("extension", extension.to_string());
 2506            }
 2507        } else {
 2508            key_context.add("multibuffer");
 2509        }
 2510
 2511        if has_active_edit_prediction {
 2512            if self.edit_prediction_in_conflict() {
 2513                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2514            } else {
 2515                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2516                key_context.add("copilot_suggestion");
 2517            }
 2518        }
 2519
 2520        if self.selection_mark_mode {
 2521            key_context.add("selection_mode");
 2522        }
 2523
 2524        key_context
 2525    }
 2526
 2527    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2528        if self.mouse_cursor_hidden {
 2529            self.mouse_cursor_hidden = false;
 2530            cx.notify();
 2531        }
 2532    }
 2533
 2534    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2535        let hide_mouse_cursor = match origin {
 2536            HideMouseCursorOrigin::TypingAction => {
 2537                matches!(
 2538                    self.hide_mouse_mode,
 2539                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2540                )
 2541            }
 2542            HideMouseCursorOrigin::MovementAction => {
 2543                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2544            }
 2545        };
 2546        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2547            self.mouse_cursor_hidden = hide_mouse_cursor;
 2548            cx.notify();
 2549        }
 2550    }
 2551
 2552    pub fn edit_prediction_in_conflict(&self) -> bool {
 2553        if !self.show_edit_predictions_in_menu() {
 2554            return false;
 2555        }
 2556
 2557        let showing_completions = self
 2558            .context_menu
 2559            .borrow()
 2560            .as_ref()
 2561            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2562
 2563        showing_completions
 2564            || self.edit_prediction_requires_modifier()
 2565            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2566            // bindings to insert tab characters.
 2567            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2568    }
 2569
 2570    pub fn accept_edit_prediction_keybind(
 2571        &self,
 2572        accept_partial: bool,
 2573        window: &Window,
 2574        cx: &App,
 2575    ) -> AcceptEditPredictionBinding {
 2576        let key_context = self.key_context_internal(true, window, cx);
 2577        let in_conflict = self.edit_prediction_in_conflict();
 2578
 2579        let bindings = if accept_partial {
 2580            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2581        } else {
 2582            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2583        };
 2584
 2585        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2586        // just the first one.
 2587        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2588            !in_conflict
 2589                || binding
 2590                    .keystrokes()
 2591                    .first()
 2592                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2593        }))
 2594    }
 2595
 2596    pub fn new_file(
 2597        workspace: &mut Workspace,
 2598        _: &workspace::NewFile,
 2599        window: &mut Window,
 2600        cx: &mut Context<Workspace>,
 2601    ) {
 2602        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2603            "Failed to create buffer",
 2604            window,
 2605            cx,
 2606            |e, _, _| match e.error_code() {
 2607                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2608                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2609                e.error_tag("required").unwrap_or("the latest version")
 2610            )),
 2611                _ => None,
 2612            },
 2613        );
 2614    }
 2615
 2616    pub fn new_in_workspace(
 2617        workspace: &mut Workspace,
 2618        window: &mut Window,
 2619        cx: &mut Context<Workspace>,
 2620    ) -> Task<Result<Entity<Editor>>> {
 2621        let project = workspace.project().clone();
 2622        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2623
 2624        cx.spawn_in(window, async move |workspace, cx| {
 2625            let buffer = create.await?;
 2626            workspace.update_in(cx, |workspace, window, cx| {
 2627                let editor =
 2628                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2629                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2630                editor
 2631            })
 2632        })
 2633    }
 2634
 2635    fn new_file_vertical(
 2636        workspace: &mut Workspace,
 2637        _: &workspace::NewFileSplitVertical,
 2638        window: &mut Window,
 2639        cx: &mut Context<Workspace>,
 2640    ) {
 2641        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2642    }
 2643
 2644    fn new_file_horizontal(
 2645        workspace: &mut Workspace,
 2646        _: &workspace::NewFileSplitHorizontal,
 2647        window: &mut Window,
 2648        cx: &mut Context<Workspace>,
 2649    ) {
 2650        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2651    }
 2652
 2653    fn new_file_in_direction(
 2654        workspace: &mut Workspace,
 2655        direction: SplitDirection,
 2656        window: &mut Window,
 2657        cx: &mut Context<Workspace>,
 2658    ) {
 2659        let project = workspace.project().clone();
 2660        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2661
 2662        cx.spawn_in(window, async move |workspace, cx| {
 2663            let buffer = create.await?;
 2664            workspace.update_in(cx, move |workspace, window, cx| {
 2665                workspace.split_item(
 2666                    direction,
 2667                    Box::new(
 2668                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2669                    ),
 2670                    window,
 2671                    cx,
 2672                )
 2673            })?;
 2674            anyhow::Ok(())
 2675        })
 2676        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2677            match e.error_code() {
 2678                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2679                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2680                e.error_tag("required").unwrap_or("the latest version")
 2681            )),
 2682                _ => None,
 2683            }
 2684        });
 2685    }
 2686
 2687    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2688        self.leader_id
 2689    }
 2690
 2691    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2692        &self.buffer
 2693    }
 2694
 2695    pub fn project(&self) -> Option<&Entity<Project>> {
 2696        self.project.as_ref()
 2697    }
 2698
 2699    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2700        self.workspace.as_ref()?.0.upgrade()
 2701    }
 2702
 2703    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2704        self.buffer().read(cx).title(cx)
 2705    }
 2706
 2707    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2708        let git_blame_gutter_max_author_length = self
 2709            .render_git_blame_gutter(cx)
 2710            .then(|| {
 2711                if let Some(blame) = self.blame.as_ref() {
 2712                    let max_author_length =
 2713                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2714                    Some(max_author_length)
 2715                } else {
 2716                    None
 2717                }
 2718            })
 2719            .flatten();
 2720
 2721        EditorSnapshot {
 2722            mode: self.mode.clone(),
 2723            show_gutter: self.show_gutter,
 2724            show_line_numbers: self.show_line_numbers,
 2725            show_git_diff_gutter: self.show_git_diff_gutter,
 2726            show_code_actions: self.show_code_actions,
 2727            show_runnables: self.show_runnables,
 2728            show_breakpoints: self.show_breakpoints,
 2729            git_blame_gutter_max_author_length,
 2730            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2731            scroll_anchor: self.scroll_manager.anchor(),
 2732            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2733            placeholder_text: self.placeholder_text.clone(),
 2734            is_focused: self.focus_handle.is_focused(window),
 2735            current_line_highlight: self
 2736                .current_line_highlight
 2737                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2738            gutter_hovered: self.gutter_hovered,
 2739        }
 2740    }
 2741
 2742    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2743        self.buffer.read(cx).language_at(point, cx)
 2744    }
 2745
 2746    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2747        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2748    }
 2749
 2750    pub fn active_excerpt(
 2751        &self,
 2752        cx: &App,
 2753    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2754        self.buffer
 2755            .read(cx)
 2756            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2757    }
 2758
 2759    pub fn mode(&self) -> &EditorMode {
 2760        &self.mode
 2761    }
 2762
 2763    pub fn set_mode(&mut self, mode: EditorMode) {
 2764        self.mode = mode;
 2765    }
 2766
 2767    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2768        self.collaboration_hub.as_deref()
 2769    }
 2770
 2771    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2772        self.collaboration_hub = Some(hub);
 2773    }
 2774
 2775    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2776        self.in_project_search = in_project_search;
 2777    }
 2778
 2779    pub fn set_custom_context_menu(
 2780        &mut self,
 2781        f: impl 'static
 2782        + Fn(
 2783            &mut Self,
 2784            DisplayPoint,
 2785            &mut Window,
 2786            &mut Context<Self>,
 2787        ) -> Option<Entity<ui::ContextMenu>>,
 2788    ) {
 2789        self.custom_context_menu = Some(Box::new(f))
 2790    }
 2791
 2792    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2793        self.completion_provider = provider;
 2794    }
 2795
 2796    #[cfg(any(test, feature = "test-support"))]
 2797    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2798        self.completion_provider.clone()
 2799    }
 2800
 2801    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2802        self.semantics_provider.clone()
 2803    }
 2804
 2805    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2806        self.semantics_provider = provider;
 2807    }
 2808
 2809    pub fn set_edit_prediction_provider<T>(
 2810        &mut self,
 2811        provider: Option<Entity<T>>,
 2812        window: &mut Window,
 2813        cx: &mut Context<Self>,
 2814    ) where
 2815        T: EditPredictionProvider,
 2816    {
 2817        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2818            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2819                if this.focus_handle.is_focused(window) {
 2820                    this.update_visible_edit_prediction(window, cx);
 2821                }
 2822            }),
 2823            provider: Arc::new(provider),
 2824        });
 2825        self.update_edit_prediction_settings(cx);
 2826        self.refresh_edit_prediction(false, false, window, cx);
 2827    }
 2828
 2829    pub fn placeholder_text(&self) -> Option<&str> {
 2830        self.placeholder_text.as_deref()
 2831    }
 2832
 2833    pub fn set_placeholder_text(
 2834        &mut self,
 2835        placeholder_text: impl Into<Arc<str>>,
 2836        cx: &mut Context<Self>,
 2837    ) {
 2838        let placeholder_text = Some(placeholder_text.into());
 2839        if self.placeholder_text != placeholder_text {
 2840            self.placeholder_text = placeholder_text;
 2841            cx.notify();
 2842        }
 2843    }
 2844
 2845    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2846        self.cursor_shape = cursor_shape;
 2847
 2848        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2849        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2850
 2851        cx.notify();
 2852    }
 2853
 2854    pub fn set_current_line_highlight(
 2855        &mut self,
 2856        current_line_highlight: Option<CurrentLineHighlight>,
 2857    ) {
 2858        self.current_line_highlight = current_line_highlight;
 2859    }
 2860
 2861    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2862        self.collapse_matches = collapse_matches;
 2863    }
 2864
 2865    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2866        let buffers = self.buffer.read(cx).all_buffers();
 2867        let Some(project) = self.project.as_ref() else {
 2868            return;
 2869        };
 2870        project.update(cx, |project, cx| {
 2871            for buffer in buffers {
 2872                self.registered_buffers
 2873                    .entry(buffer.read(cx).remote_id())
 2874                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2875            }
 2876        })
 2877    }
 2878
 2879    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2880        if self.collapse_matches {
 2881            return range.start..range.start;
 2882        }
 2883        range.clone()
 2884    }
 2885
 2886    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2887        if self.display_map.read(cx).clip_at_line_ends != clip {
 2888            self.display_map
 2889                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2890        }
 2891    }
 2892
 2893    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2894        self.input_enabled = input_enabled;
 2895    }
 2896
 2897    pub fn set_edit_predictions_hidden_for_vim_mode(
 2898        &mut self,
 2899        hidden: bool,
 2900        window: &mut Window,
 2901        cx: &mut Context<Self>,
 2902    ) {
 2903        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2904            self.edit_predictions_hidden_for_vim_mode = hidden;
 2905            if hidden {
 2906                self.update_visible_edit_prediction(window, cx);
 2907            } else {
 2908                self.refresh_edit_prediction(true, false, window, cx);
 2909            }
 2910        }
 2911    }
 2912
 2913    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2914        self.menu_edit_predictions_policy = value;
 2915    }
 2916
 2917    pub fn set_autoindent(&mut self, autoindent: bool) {
 2918        if autoindent {
 2919            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2920        } else {
 2921            self.autoindent_mode = None;
 2922        }
 2923    }
 2924
 2925    pub fn read_only(&self, cx: &App) -> bool {
 2926        self.read_only || self.buffer.read(cx).read_only()
 2927    }
 2928
 2929    pub fn set_read_only(&mut self, read_only: bool) {
 2930        self.read_only = read_only;
 2931    }
 2932
 2933    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2934        self.use_autoclose = autoclose;
 2935    }
 2936
 2937    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2938        self.use_auto_surround = auto_surround;
 2939    }
 2940
 2941    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2942        self.auto_replace_emoji_shortcode = auto_replace;
 2943    }
 2944
 2945    pub fn toggle_edit_predictions(
 2946        &mut self,
 2947        _: &ToggleEditPrediction,
 2948        window: &mut Window,
 2949        cx: &mut Context<Self>,
 2950    ) {
 2951        if self.show_edit_predictions_override.is_some() {
 2952            self.set_show_edit_predictions(None, window, cx);
 2953        } else {
 2954            let show_edit_predictions = !self.edit_predictions_enabled();
 2955            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2956        }
 2957    }
 2958
 2959    pub fn set_show_edit_predictions(
 2960        &mut self,
 2961        show_edit_predictions: Option<bool>,
 2962        window: &mut Window,
 2963        cx: &mut Context<Self>,
 2964    ) {
 2965        self.show_edit_predictions_override = show_edit_predictions;
 2966        self.update_edit_prediction_settings(cx);
 2967
 2968        if let Some(false) = show_edit_predictions {
 2969            self.discard_edit_prediction(false, cx);
 2970        } else {
 2971            self.refresh_edit_prediction(false, true, window, cx);
 2972        }
 2973    }
 2974
 2975    fn edit_predictions_disabled_in_scope(
 2976        &self,
 2977        buffer: &Entity<Buffer>,
 2978        buffer_position: language::Anchor,
 2979        cx: &App,
 2980    ) -> bool {
 2981        let snapshot = buffer.read(cx).snapshot();
 2982        let settings = snapshot.settings_at(buffer_position, cx);
 2983
 2984        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2985            return false;
 2986        };
 2987
 2988        scope.override_name().is_some_and(|scope_name| {
 2989            settings
 2990                .edit_predictions_disabled_in
 2991                .iter()
 2992                .any(|s| s == scope_name)
 2993        })
 2994    }
 2995
 2996    pub fn set_use_modal_editing(&mut self, to: bool) {
 2997        self.use_modal_editing = to;
 2998    }
 2999
 3000    pub fn use_modal_editing(&self) -> bool {
 3001        self.use_modal_editing
 3002    }
 3003
 3004    fn selections_did_change(
 3005        &mut self,
 3006        local: bool,
 3007        old_cursor_position: &Anchor,
 3008        effects: SelectionEffects,
 3009        window: &mut Window,
 3010        cx: &mut Context<Self>,
 3011    ) {
 3012        window.invalidate_character_coordinates();
 3013
 3014        // Copy selections to primary selection buffer
 3015        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3016        if local {
 3017            let selections = self.selections.all::<usize>(cx);
 3018            let buffer_handle = self.buffer.read(cx).read(cx);
 3019
 3020            let mut text = String::new();
 3021            for (index, selection) in selections.iter().enumerate() {
 3022                let text_for_selection = buffer_handle
 3023                    .text_for_range(selection.start..selection.end)
 3024                    .collect::<String>();
 3025
 3026                text.push_str(&text_for_selection);
 3027                if index != selections.len() - 1 {
 3028                    text.push('\n');
 3029                }
 3030            }
 3031
 3032            if !text.is_empty() {
 3033                cx.write_to_primary(ClipboardItem::new_string(text));
 3034            }
 3035        }
 3036
 3037        let selection_anchors = self.selections.disjoint_anchors();
 3038
 3039        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3040            self.buffer.update(cx, |buffer, cx| {
 3041                buffer.set_active_selections(
 3042                    &selection_anchors,
 3043                    self.selections.line_mode,
 3044                    self.cursor_shape,
 3045                    cx,
 3046                )
 3047            });
 3048        }
 3049        let display_map = self
 3050            .display_map
 3051            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3052        let buffer = &display_map.buffer_snapshot;
 3053        if self.selections.count() == 1 {
 3054            self.add_selections_state = None;
 3055        }
 3056        self.select_next_state = None;
 3057        self.select_prev_state = None;
 3058        self.select_syntax_node_history.try_clear();
 3059        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3060        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3061        self.take_rename(false, window, cx);
 3062
 3063        let newest_selection = self.selections.newest_anchor();
 3064        let new_cursor_position = newest_selection.head();
 3065        let selection_start = newest_selection.start;
 3066
 3067        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3068            self.push_to_nav_history(
 3069                *old_cursor_position,
 3070                Some(new_cursor_position.to_point(buffer)),
 3071                false,
 3072                effects.nav_history == Some(true),
 3073                cx,
 3074            );
 3075        }
 3076
 3077        if local {
 3078            if let Some(buffer_id) = new_cursor_position.buffer_id
 3079                && !self.registered_buffers.contains_key(&buffer_id)
 3080                && let Some(project) = self.project.as_ref()
 3081            {
 3082                project.update(cx, |project, cx| {
 3083                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3084                        return;
 3085                    };
 3086                    self.registered_buffers.insert(
 3087                        buffer_id,
 3088                        project.register_buffer_with_language_servers(&buffer, cx),
 3089                    );
 3090                })
 3091            }
 3092
 3093            let mut context_menu = self.context_menu.borrow_mut();
 3094            let completion_menu = match context_menu.as_ref() {
 3095                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3096                Some(CodeContextMenu::CodeActions(_)) => {
 3097                    *context_menu = None;
 3098                    None
 3099                }
 3100                None => None,
 3101            };
 3102            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3103            drop(context_menu);
 3104
 3105            if effects.completions
 3106                && let Some(completion_position) = completion_position
 3107            {
 3108                let start_offset = selection_start.to_offset(buffer);
 3109                let position_matches = start_offset == completion_position.to_offset(buffer);
 3110                let continue_showing = if position_matches {
 3111                    if self.snippet_stack.is_empty() {
 3112                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3113                    } else {
 3114                        // Snippet choices can be shown even when the cursor is in whitespace.
 3115                        // Dismissing the menu with actions like backspace is handled by
 3116                        // invalidation regions.
 3117                        true
 3118                    }
 3119                } else {
 3120                    false
 3121                };
 3122
 3123                if continue_showing {
 3124                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3125                } else {
 3126                    self.hide_context_menu(window, cx);
 3127                }
 3128            }
 3129
 3130            hide_hover(self, cx);
 3131
 3132            if old_cursor_position.to_display_point(&display_map).row()
 3133                != new_cursor_position.to_display_point(&display_map).row()
 3134            {
 3135                self.available_code_actions.take();
 3136            }
 3137            self.refresh_code_actions(window, cx);
 3138            self.refresh_document_highlights(cx);
 3139            self.refresh_selected_text_highlights(false, window, cx);
 3140            refresh_matching_bracket_highlights(self, window, cx);
 3141            self.update_visible_edit_prediction(window, cx);
 3142            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3143            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3144            self.inline_blame_popover.take();
 3145            if self.git_blame_inline_enabled {
 3146                self.start_inline_blame_timer(window, cx);
 3147            }
 3148        }
 3149
 3150        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3151        cx.emit(EditorEvent::SelectionsChanged { local });
 3152
 3153        let selections = &self.selections.disjoint;
 3154        if selections.len() == 1 {
 3155            cx.emit(SearchEvent::ActiveMatchChanged)
 3156        }
 3157        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3158            let inmemory_selections = selections
 3159                .iter()
 3160                .map(|s| {
 3161                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3162                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3163                })
 3164                .collect();
 3165            self.update_restoration_data(cx, |data| {
 3166                data.selections = inmemory_selections;
 3167            });
 3168
 3169            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3170                && let Some(workspace_id) =
 3171                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3172            {
 3173                let snapshot = self.buffer().read(cx).snapshot(cx);
 3174                let selections = selections.clone();
 3175                let background_executor = cx.background_executor().clone();
 3176                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3177                self.serialize_selections = cx.background_spawn(async move {
 3178                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3179                            let db_selections = selections
 3180                                .iter()
 3181                                .map(|selection| {
 3182                                    (
 3183                                        selection.start.to_offset(&snapshot),
 3184                                        selection.end.to_offset(&snapshot),
 3185                                    )
 3186                                })
 3187                                .collect();
 3188
 3189                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3190                                .await
 3191                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3192                                .log_err();
 3193                        });
 3194            }
 3195        }
 3196
 3197        cx.notify();
 3198    }
 3199
 3200    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3201        use text::ToOffset as _;
 3202        use text::ToPoint as _;
 3203
 3204        if self.mode.is_minimap()
 3205            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3206        {
 3207            return;
 3208        }
 3209
 3210        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3211            return;
 3212        };
 3213
 3214        let snapshot = singleton.read(cx).snapshot();
 3215        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3216            let display_snapshot = display_map.snapshot(cx);
 3217
 3218            display_snapshot
 3219                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3220                .map(|fold| {
 3221                    fold.range.start.text_anchor.to_point(&snapshot)
 3222                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3223                })
 3224                .collect()
 3225        });
 3226        self.update_restoration_data(cx, |data| {
 3227            data.folds = inmemory_folds;
 3228        });
 3229
 3230        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3231            return;
 3232        };
 3233        let background_executor = cx.background_executor().clone();
 3234        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3235        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3236            display_map
 3237                .snapshot(cx)
 3238                .folds_in_range(0..snapshot.len())
 3239                .map(|fold| {
 3240                    (
 3241                        fold.range.start.text_anchor.to_offset(&snapshot),
 3242                        fold.range.end.text_anchor.to_offset(&snapshot),
 3243                    )
 3244                })
 3245                .collect()
 3246        });
 3247        self.serialize_folds = cx.background_spawn(async move {
 3248            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3249            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3250                .await
 3251                .with_context(|| {
 3252                    format!(
 3253                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3254                    )
 3255                })
 3256                .log_err();
 3257        });
 3258    }
 3259
 3260    pub fn sync_selections(
 3261        &mut self,
 3262        other: Entity<Editor>,
 3263        cx: &mut Context<Self>,
 3264    ) -> gpui::Subscription {
 3265        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3266        self.selections.change_with(cx, |selections| {
 3267            selections.select_anchors(other_selections);
 3268        });
 3269
 3270        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3271            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3272                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3273                if other_selections.is_empty() {
 3274                    return;
 3275                }
 3276                this.selections.change_with(cx, |selections| {
 3277                    selections.select_anchors(other_selections);
 3278                });
 3279            }
 3280        });
 3281
 3282        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3283            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3284                let these_selections = this.selections.disjoint.to_vec();
 3285                if these_selections.is_empty() {
 3286                    return;
 3287                }
 3288                other.update(cx, |other_editor, cx| {
 3289                    other_editor.selections.change_with(cx, |selections| {
 3290                        selections.select_anchors(these_selections);
 3291                    })
 3292                });
 3293            }
 3294        });
 3295
 3296        Subscription::join(other_subscription, this_subscription)
 3297    }
 3298
 3299    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3300    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3301    /// effects of selection change occur at the end of the transaction.
 3302    pub fn change_selections<R>(
 3303        &mut self,
 3304        effects: SelectionEffects,
 3305        window: &mut Window,
 3306        cx: &mut Context<Self>,
 3307        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3308    ) -> R {
 3309        if let Some(state) = &mut self.deferred_selection_effects_state {
 3310            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3311            state.effects.completions = effects.completions;
 3312            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3313            let (changed, result) = self.selections.change_with(cx, change);
 3314            state.changed |= changed;
 3315            return result;
 3316        }
 3317        let mut state = DeferredSelectionEffectsState {
 3318            changed: false,
 3319            effects,
 3320            old_cursor_position: self.selections.newest_anchor().head(),
 3321            history_entry: SelectionHistoryEntry {
 3322                selections: self.selections.disjoint_anchors(),
 3323                select_next_state: self.select_next_state.clone(),
 3324                select_prev_state: self.select_prev_state.clone(),
 3325                add_selections_state: self.add_selections_state.clone(),
 3326            },
 3327        };
 3328        let (changed, result) = self.selections.change_with(cx, change);
 3329        state.changed = state.changed || changed;
 3330        if self.defer_selection_effects {
 3331            self.deferred_selection_effects_state = Some(state);
 3332        } else {
 3333            self.apply_selection_effects(state, window, cx);
 3334        }
 3335        result
 3336    }
 3337
 3338    /// Defers the effects of selection change, so that the effects of multiple calls to
 3339    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3340    /// to selection history and the state of popovers based on selection position aren't
 3341    /// erroneously updated.
 3342    pub fn with_selection_effects_deferred<R>(
 3343        &mut self,
 3344        window: &mut Window,
 3345        cx: &mut Context<Self>,
 3346        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3347    ) -> R {
 3348        let already_deferred = self.defer_selection_effects;
 3349        self.defer_selection_effects = true;
 3350        let result = update(self, window, cx);
 3351        if !already_deferred {
 3352            self.defer_selection_effects = false;
 3353            if let Some(state) = self.deferred_selection_effects_state.take() {
 3354                self.apply_selection_effects(state, window, cx);
 3355            }
 3356        }
 3357        result
 3358    }
 3359
 3360    fn apply_selection_effects(
 3361        &mut self,
 3362        state: DeferredSelectionEffectsState,
 3363        window: &mut Window,
 3364        cx: &mut Context<Self>,
 3365    ) {
 3366        if state.changed {
 3367            self.selection_history.push(state.history_entry);
 3368
 3369            if let Some(autoscroll) = state.effects.scroll {
 3370                self.request_autoscroll(autoscroll, cx);
 3371            }
 3372
 3373            let old_cursor_position = &state.old_cursor_position;
 3374
 3375            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3376
 3377            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3378                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3379            }
 3380        }
 3381    }
 3382
 3383    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3384    where
 3385        I: IntoIterator<Item = (Range<S>, T)>,
 3386        S: ToOffset,
 3387        T: Into<Arc<str>>,
 3388    {
 3389        if self.read_only(cx) {
 3390            return;
 3391        }
 3392
 3393        self.buffer
 3394            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3395    }
 3396
 3397    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3398    where
 3399        I: IntoIterator<Item = (Range<S>, T)>,
 3400        S: ToOffset,
 3401        T: Into<Arc<str>>,
 3402    {
 3403        if self.read_only(cx) {
 3404            return;
 3405        }
 3406
 3407        self.buffer.update(cx, |buffer, cx| {
 3408            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3409        });
 3410    }
 3411
 3412    pub fn edit_with_block_indent<I, S, T>(
 3413        &mut self,
 3414        edits: I,
 3415        original_indent_columns: Vec<Option<u32>>,
 3416        cx: &mut Context<Self>,
 3417    ) where
 3418        I: IntoIterator<Item = (Range<S>, T)>,
 3419        S: ToOffset,
 3420        T: Into<Arc<str>>,
 3421    {
 3422        if self.read_only(cx) {
 3423            return;
 3424        }
 3425
 3426        self.buffer.update(cx, |buffer, cx| {
 3427            buffer.edit(
 3428                edits,
 3429                Some(AutoindentMode::Block {
 3430                    original_indent_columns,
 3431                }),
 3432                cx,
 3433            )
 3434        });
 3435    }
 3436
 3437    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3438        self.hide_context_menu(window, cx);
 3439
 3440        match phase {
 3441            SelectPhase::Begin {
 3442                position,
 3443                add,
 3444                click_count,
 3445            } => self.begin_selection(position, add, click_count, window, cx),
 3446            SelectPhase::BeginColumnar {
 3447                position,
 3448                goal_column,
 3449                reset,
 3450                mode,
 3451            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3452            SelectPhase::Extend {
 3453                position,
 3454                click_count,
 3455            } => self.extend_selection(position, click_count, window, cx),
 3456            SelectPhase::Update {
 3457                position,
 3458                goal_column,
 3459                scroll_delta,
 3460            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3461            SelectPhase::End => self.end_selection(window, cx),
 3462        }
 3463    }
 3464
 3465    fn extend_selection(
 3466        &mut self,
 3467        position: DisplayPoint,
 3468        click_count: usize,
 3469        window: &mut Window,
 3470        cx: &mut Context<Self>,
 3471    ) {
 3472        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3473        let tail = self.selections.newest::<usize>(cx).tail();
 3474        self.begin_selection(position, false, click_count, window, cx);
 3475
 3476        let position = position.to_offset(&display_map, Bias::Left);
 3477        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3478
 3479        let mut pending_selection = self
 3480            .selections
 3481            .pending_anchor()
 3482            .expect("extend_selection not called with pending selection");
 3483        if position >= tail {
 3484            pending_selection.start = tail_anchor;
 3485        } else {
 3486            pending_selection.end = tail_anchor;
 3487            pending_selection.reversed = true;
 3488        }
 3489
 3490        let mut pending_mode = self.selections.pending_mode().unwrap();
 3491        match &mut pending_mode {
 3492            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3493            _ => {}
 3494        }
 3495
 3496        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3497            SelectionEffects::scroll(Autoscroll::fit())
 3498        } else {
 3499            SelectionEffects::no_scroll()
 3500        };
 3501
 3502        self.change_selections(effects, window, cx, |s| {
 3503            s.set_pending(pending_selection, pending_mode)
 3504        });
 3505    }
 3506
 3507    fn begin_selection(
 3508        &mut self,
 3509        position: DisplayPoint,
 3510        add: bool,
 3511        click_count: usize,
 3512        window: &mut Window,
 3513        cx: &mut Context<Self>,
 3514    ) {
 3515        if !self.focus_handle.is_focused(window) {
 3516            self.last_focused_descendant = None;
 3517            window.focus(&self.focus_handle);
 3518        }
 3519
 3520        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3521        let buffer = &display_map.buffer_snapshot;
 3522        let position = display_map.clip_point(position, Bias::Left);
 3523
 3524        let start;
 3525        let end;
 3526        let mode;
 3527        let mut auto_scroll;
 3528        match click_count {
 3529            1 => {
 3530                start = buffer.anchor_before(position.to_point(&display_map));
 3531                end = start;
 3532                mode = SelectMode::Character;
 3533                auto_scroll = true;
 3534            }
 3535            2 => {
 3536                let position = display_map
 3537                    .clip_point(position, Bias::Left)
 3538                    .to_offset(&display_map, Bias::Left);
 3539                let (range, _) = buffer.surrounding_word(position, false);
 3540                start = buffer.anchor_before(range.start);
 3541                end = buffer.anchor_before(range.end);
 3542                mode = SelectMode::Word(start..end);
 3543                auto_scroll = true;
 3544            }
 3545            3 => {
 3546                let position = display_map
 3547                    .clip_point(position, Bias::Left)
 3548                    .to_point(&display_map);
 3549                let line_start = display_map.prev_line_boundary(position).0;
 3550                let next_line_start = buffer.clip_point(
 3551                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3552                    Bias::Left,
 3553                );
 3554                start = buffer.anchor_before(line_start);
 3555                end = buffer.anchor_before(next_line_start);
 3556                mode = SelectMode::Line(start..end);
 3557                auto_scroll = true;
 3558            }
 3559            _ => {
 3560                start = buffer.anchor_before(0);
 3561                end = buffer.anchor_before(buffer.len());
 3562                mode = SelectMode::All;
 3563                auto_scroll = false;
 3564            }
 3565        }
 3566        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3567
 3568        let point_to_delete: Option<usize> = {
 3569            let selected_points: Vec<Selection<Point>> =
 3570                self.selections.disjoint_in_range(start..end, cx);
 3571
 3572            if !add || click_count > 1 {
 3573                None
 3574            } else if !selected_points.is_empty() {
 3575                Some(selected_points[0].id)
 3576            } else {
 3577                let clicked_point_already_selected =
 3578                    self.selections.disjoint.iter().find(|selection| {
 3579                        selection.start.to_point(buffer) == start.to_point(buffer)
 3580                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3581                    });
 3582
 3583                clicked_point_already_selected.map(|selection| selection.id)
 3584            }
 3585        };
 3586
 3587        let selections_count = self.selections.count();
 3588        let effects = if auto_scroll {
 3589            SelectionEffects::default()
 3590        } else {
 3591            SelectionEffects::no_scroll()
 3592        };
 3593
 3594        self.change_selections(effects, window, cx, |s| {
 3595            if let Some(point_to_delete) = point_to_delete {
 3596                s.delete(point_to_delete);
 3597
 3598                if selections_count == 1 {
 3599                    s.set_pending_anchor_range(start..end, mode);
 3600                }
 3601            } else {
 3602                if !add {
 3603                    s.clear_disjoint();
 3604                }
 3605
 3606                s.set_pending_anchor_range(start..end, mode);
 3607            }
 3608        });
 3609    }
 3610
 3611    fn begin_columnar_selection(
 3612        &mut self,
 3613        position: DisplayPoint,
 3614        goal_column: u32,
 3615        reset: bool,
 3616        mode: ColumnarMode,
 3617        window: &mut Window,
 3618        cx: &mut Context<Self>,
 3619    ) {
 3620        if !self.focus_handle.is_focused(window) {
 3621            self.last_focused_descendant = None;
 3622            window.focus(&self.focus_handle);
 3623        }
 3624
 3625        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3626
 3627        if reset {
 3628            let pointer_position = display_map
 3629                .buffer_snapshot
 3630                .anchor_before(position.to_point(&display_map));
 3631
 3632            self.change_selections(
 3633                SelectionEffects::scroll(Autoscroll::newest()),
 3634                window,
 3635                cx,
 3636                |s| {
 3637                    s.clear_disjoint();
 3638                    s.set_pending_anchor_range(
 3639                        pointer_position..pointer_position,
 3640                        SelectMode::Character,
 3641                    );
 3642                },
 3643            );
 3644        };
 3645
 3646        let tail = self.selections.newest::<Point>(cx).tail();
 3647        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3648        self.columnar_selection_state = match mode {
 3649            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3650                selection_tail: selection_anchor,
 3651                display_point: if reset {
 3652                    if position.column() != goal_column {
 3653                        Some(DisplayPoint::new(position.row(), goal_column))
 3654                    } else {
 3655                        None
 3656                    }
 3657                } else {
 3658                    None
 3659                },
 3660            }),
 3661            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3662                selection_tail: selection_anchor,
 3663            }),
 3664        };
 3665
 3666        if !reset {
 3667            self.select_columns(position, goal_column, &display_map, window, cx);
 3668        }
 3669    }
 3670
 3671    fn update_selection(
 3672        &mut self,
 3673        position: DisplayPoint,
 3674        goal_column: u32,
 3675        scroll_delta: gpui::Point<f32>,
 3676        window: &mut Window,
 3677        cx: &mut Context<Self>,
 3678    ) {
 3679        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3680
 3681        if self.columnar_selection_state.is_some() {
 3682            self.select_columns(position, goal_column, &display_map, window, cx);
 3683        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3684            let buffer = &display_map.buffer_snapshot;
 3685            let head;
 3686            let tail;
 3687            let mode = self.selections.pending_mode().unwrap();
 3688            match &mode {
 3689                SelectMode::Character => {
 3690                    head = position.to_point(&display_map);
 3691                    tail = pending.tail().to_point(buffer);
 3692                }
 3693                SelectMode::Word(original_range) => {
 3694                    let offset = display_map
 3695                        .clip_point(position, Bias::Left)
 3696                        .to_offset(&display_map, Bias::Left);
 3697                    let original_range = original_range.to_offset(buffer);
 3698
 3699                    let head_offset = if buffer.is_inside_word(offset, false)
 3700                        || original_range.contains(&offset)
 3701                    {
 3702                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3703                        if word_range.start < original_range.start {
 3704                            word_range.start
 3705                        } else {
 3706                            word_range.end
 3707                        }
 3708                    } else {
 3709                        offset
 3710                    };
 3711
 3712                    head = head_offset.to_point(buffer);
 3713                    if head_offset <= original_range.start {
 3714                        tail = original_range.end.to_point(buffer);
 3715                    } else {
 3716                        tail = original_range.start.to_point(buffer);
 3717                    }
 3718                }
 3719                SelectMode::Line(original_range) => {
 3720                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3721
 3722                    let position = display_map
 3723                        .clip_point(position, Bias::Left)
 3724                        .to_point(&display_map);
 3725                    let line_start = display_map.prev_line_boundary(position).0;
 3726                    let next_line_start = buffer.clip_point(
 3727                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3728                        Bias::Left,
 3729                    );
 3730
 3731                    if line_start < original_range.start {
 3732                        head = line_start
 3733                    } else {
 3734                        head = next_line_start
 3735                    }
 3736
 3737                    if head <= original_range.start {
 3738                        tail = original_range.end;
 3739                    } else {
 3740                        tail = original_range.start;
 3741                    }
 3742                }
 3743                SelectMode::All => {
 3744                    return;
 3745                }
 3746            };
 3747
 3748            if head < tail {
 3749                pending.start = buffer.anchor_before(head);
 3750                pending.end = buffer.anchor_before(tail);
 3751                pending.reversed = true;
 3752            } else {
 3753                pending.start = buffer.anchor_before(tail);
 3754                pending.end = buffer.anchor_before(head);
 3755                pending.reversed = false;
 3756            }
 3757
 3758            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3759                s.set_pending(pending, mode);
 3760            });
 3761        } else {
 3762            log::error!("update_selection dispatched with no pending selection");
 3763            return;
 3764        }
 3765
 3766        self.apply_scroll_delta(scroll_delta, window, cx);
 3767        cx.notify();
 3768    }
 3769
 3770    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3771        self.columnar_selection_state.take();
 3772        if self.selections.pending_anchor().is_some() {
 3773            let selections = self.selections.all::<usize>(cx);
 3774            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3775                s.select(selections);
 3776                s.clear_pending();
 3777            });
 3778        }
 3779    }
 3780
 3781    fn select_columns(
 3782        &mut self,
 3783        head: DisplayPoint,
 3784        goal_column: u32,
 3785        display_map: &DisplaySnapshot,
 3786        window: &mut Window,
 3787        cx: &mut Context<Self>,
 3788    ) {
 3789        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3790            return;
 3791        };
 3792
 3793        let tail = match columnar_state {
 3794            ColumnarSelectionState::FromMouse {
 3795                selection_tail,
 3796                display_point,
 3797            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3798            ColumnarSelectionState::FromSelection { selection_tail } => {
 3799                selection_tail.to_display_point(display_map)
 3800            }
 3801        };
 3802
 3803        let start_row = cmp::min(tail.row(), head.row());
 3804        let end_row = cmp::max(tail.row(), head.row());
 3805        let start_column = cmp::min(tail.column(), goal_column);
 3806        let end_column = cmp::max(tail.column(), goal_column);
 3807        let reversed = start_column < tail.column();
 3808
 3809        let selection_ranges = (start_row.0..=end_row.0)
 3810            .map(DisplayRow)
 3811            .filter_map(|row| {
 3812                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3813                    || start_column <= display_map.line_len(row))
 3814                    && !display_map.is_block_line(row)
 3815                {
 3816                    let start = display_map
 3817                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3818                        .to_point(display_map);
 3819                    let end = display_map
 3820                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3821                        .to_point(display_map);
 3822                    if reversed {
 3823                        Some(end..start)
 3824                    } else {
 3825                        Some(start..end)
 3826                    }
 3827                } else {
 3828                    None
 3829                }
 3830            })
 3831            .collect::<Vec<_>>();
 3832
 3833        let ranges = match columnar_state {
 3834            ColumnarSelectionState::FromMouse { .. } => {
 3835                let mut non_empty_ranges = selection_ranges
 3836                    .iter()
 3837                    .filter(|selection_range| selection_range.start != selection_range.end)
 3838                    .peekable();
 3839                if non_empty_ranges.peek().is_some() {
 3840                    non_empty_ranges.cloned().collect()
 3841                } else {
 3842                    selection_ranges
 3843                }
 3844            }
 3845            _ => selection_ranges,
 3846        };
 3847
 3848        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3849            s.select_ranges(ranges);
 3850        });
 3851        cx.notify();
 3852    }
 3853
 3854    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3855        self.selections
 3856            .all_adjusted(cx)
 3857            .iter()
 3858            .any(|selection| !selection.is_empty())
 3859    }
 3860
 3861    pub fn has_pending_nonempty_selection(&self) -> bool {
 3862        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3863            Some(Selection { start, end, .. }) => start != end,
 3864            None => false,
 3865        };
 3866
 3867        pending_nonempty_selection
 3868            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3869    }
 3870
 3871    pub fn has_pending_selection(&self) -> bool {
 3872        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3873    }
 3874
 3875    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3876        self.selection_mark_mode = false;
 3877        self.selection_drag_state = SelectionDragState::None;
 3878
 3879        if self.clear_expanded_diff_hunks(cx) {
 3880            cx.notify();
 3881            return;
 3882        }
 3883        if self.dismiss_menus_and_popups(true, window, cx) {
 3884            return;
 3885        }
 3886
 3887        if self.mode.is_full()
 3888            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3889        {
 3890            return;
 3891        }
 3892
 3893        cx.propagate();
 3894    }
 3895
 3896    pub fn dismiss_menus_and_popups(
 3897        &mut self,
 3898        is_user_requested: bool,
 3899        window: &mut Window,
 3900        cx: &mut Context<Self>,
 3901    ) -> bool {
 3902        if self.take_rename(false, window, cx).is_some() {
 3903            return true;
 3904        }
 3905
 3906        if hide_hover(self, cx) {
 3907            return true;
 3908        }
 3909
 3910        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3911            return true;
 3912        }
 3913
 3914        if self.hide_context_menu(window, cx).is_some() {
 3915            return true;
 3916        }
 3917
 3918        if self.mouse_context_menu.take().is_some() {
 3919            return true;
 3920        }
 3921
 3922        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3923            return true;
 3924        }
 3925
 3926        if self.snippet_stack.pop().is_some() {
 3927            return true;
 3928        }
 3929
 3930        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3931            self.dismiss_diagnostics(cx);
 3932            return true;
 3933        }
 3934
 3935        false
 3936    }
 3937
 3938    fn linked_editing_ranges_for(
 3939        &self,
 3940        selection: Range<text::Anchor>,
 3941        cx: &App,
 3942    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3943        if self.linked_edit_ranges.is_empty() {
 3944            return None;
 3945        }
 3946        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3947            selection.end.buffer_id.and_then(|end_buffer_id| {
 3948                if selection.start.buffer_id != Some(end_buffer_id) {
 3949                    return None;
 3950                }
 3951                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3952                let snapshot = buffer.read(cx).snapshot();
 3953                self.linked_edit_ranges
 3954                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3955                    .map(|ranges| (ranges, snapshot, buffer))
 3956            })?;
 3957        use text::ToOffset as TO;
 3958        // find offset from the start of current range to current cursor position
 3959        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3960
 3961        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3962        let start_difference = start_offset - start_byte_offset;
 3963        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3964        let end_difference = end_offset - start_byte_offset;
 3965        // Current range has associated linked ranges.
 3966        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3967        for range in linked_ranges.iter() {
 3968            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3969            let end_offset = start_offset + end_difference;
 3970            let start_offset = start_offset + start_difference;
 3971            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3972                continue;
 3973            }
 3974            if self.selections.disjoint_anchor_ranges().any(|s| {
 3975                if s.start.buffer_id != selection.start.buffer_id
 3976                    || s.end.buffer_id != selection.end.buffer_id
 3977                {
 3978                    return false;
 3979                }
 3980                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3981                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3982            }) {
 3983                continue;
 3984            }
 3985            let start = buffer_snapshot.anchor_after(start_offset);
 3986            let end = buffer_snapshot.anchor_after(end_offset);
 3987            linked_edits
 3988                .entry(buffer.clone())
 3989                .or_default()
 3990                .push(start..end);
 3991        }
 3992        Some(linked_edits)
 3993    }
 3994
 3995    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3996        let text: Arc<str> = text.into();
 3997
 3998        if self.read_only(cx) {
 3999            return;
 4000        }
 4001
 4002        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4003
 4004        let selections = self.selections.all_adjusted(cx);
 4005        let mut bracket_inserted = false;
 4006        let mut edits = Vec::new();
 4007        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4008        let mut new_selections = Vec::with_capacity(selections.len());
 4009        let mut new_autoclose_regions = Vec::new();
 4010        let snapshot = self.buffer.read(cx).read(cx);
 4011        let mut clear_linked_edit_ranges = false;
 4012
 4013        for (selection, autoclose_region) in
 4014            self.selections_with_autoclose_regions(selections, &snapshot)
 4015        {
 4016            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4017                // Determine if the inserted text matches the opening or closing
 4018                // bracket of any of this language's bracket pairs.
 4019                let mut bracket_pair = None;
 4020                let mut is_bracket_pair_start = false;
 4021                let mut is_bracket_pair_end = false;
 4022                if !text.is_empty() {
 4023                    let mut bracket_pair_matching_end = None;
 4024                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4025                    //  and they are removing the character that triggered IME popup.
 4026                    for (pair, enabled) in scope.brackets() {
 4027                        if !pair.close && !pair.surround {
 4028                            continue;
 4029                        }
 4030
 4031                        if enabled && pair.start.ends_with(text.as_ref()) {
 4032                            let prefix_len = pair.start.len() - text.len();
 4033                            let preceding_text_matches_prefix = prefix_len == 0
 4034                                || (selection.start.column >= (prefix_len as u32)
 4035                                    && snapshot.contains_str_at(
 4036                                        Point::new(
 4037                                            selection.start.row,
 4038                                            selection.start.column - (prefix_len as u32),
 4039                                        ),
 4040                                        &pair.start[..prefix_len],
 4041                                    ));
 4042                            if preceding_text_matches_prefix {
 4043                                bracket_pair = Some(pair.clone());
 4044                                is_bracket_pair_start = true;
 4045                                break;
 4046                            }
 4047                        }
 4048                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4049                        {
 4050                            // take first bracket pair matching end, but don't break in case a later bracket
 4051                            // pair matches start
 4052                            bracket_pair_matching_end = Some(pair.clone());
 4053                        }
 4054                    }
 4055                    if let Some(end) = bracket_pair_matching_end
 4056                        && bracket_pair.is_none()
 4057                    {
 4058                        bracket_pair = Some(end);
 4059                        is_bracket_pair_end = true;
 4060                    }
 4061                }
 4062
 4063                if let Some(bracket_pair) = bracket_pair {
 4064                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4065                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4066                    let auto_surround =
 4067                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4068                    if selection.is_empty() {
 4069                        if is_bracket_pair_start {
 4070                            // If the inserted text is a suffix of an opening bracket and the
 4071                            // selection is preceded by the rest of the opening bracket, then
 4072                            // insert the closing bracket.
 4073                            let following_text_allows_autoclose = snapshot
 4074                                .chars_at(selection.start)
 4075                                .next()
 4076                                .is_none_or(|c| scope.should_autoclose_before(c));
 4077
 4078                            let preceding_text_allows_autoclose = selection.start.column == 0
 4079                                || snapshot
 4080                                    .reversed_chars_at(selection.start)
 4081                                    .next()
 4082                                    .is_none_or(|c| {
 4083                                        bracket_pair.start != bracket_pair.end
 4084                                            || !snapshot
 4085                                                .char_classifier_at(selection.start)
 4086                                                .is_word(c)
 4087                                    });
 4088
 4089                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4090                                && bracket_pair.start.len() == 1
 4091                            {
 4092                                let target = bracket_pair.start.chars().next().unwrap();
 4093                                let current_line_count = snapshot
 4094                                    .reversed_chars_at(selection.start)
 4095                                    .take_while(|&c| c != '\n')
 4096                                    .filter(|&c| c == target)
 4097                                    .count();
 4098                                current_line_count % 2 == 1
 4099                            } else {
 4100                                false
 4101                            };
 4102
 4103                            if autoclose
 4104                                && bracket_pair.close
 4105                                && following_text_allows_autoclose
 4106                                && preceding_text_allows_autoclose
 4107                                && !is_closing_quote
 4108                            {
 4109                                let anchor = snapshot.anchor_before(selection.end);
 4110                                new_selections.push((selection.map(|_| anchor), text.len()));
 4111                                new_autoclose_regions.push((
 4112                                    anchor,
 4113                                    text.len(),
 4114                                    selection.id,
 4115                                    bracket_pair.clone(),
 4116                                ));
 4117                                edits.push((
 4118                                    selection.range(),
 4119                                    format!("{}{}", text, bracket_pair.end).into(),
 4120                                ));
 4121                                bracket_inserted = true;
 4122                                continue;
 4123                            }
 4124                        }
 4125
 4126                        if let Some(region) = autoclose_region {
 4127                            // If the selection is followed by an auto-inserted closing bracket,
 4128                            // then don't insert that closing bracket again; just move the selection
 4129                            // past the closing bracket.
 4130                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4131                                && text.as_ref() == region.pair.end.as_str()
 4132                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4133                            if should_skip {
 4134                                let anchor = snapshot.anchor_after(selection.end);
 4135                                new_selections
 4136                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4137                                continue;
 4138                            }
 4139                        }
 4140
 4141                        let always_treat_brackets_as_autoclosed = snapshot
 4142                            .language_settings_at(selection.start, cx)
 4143                            .always_treat_brackets_as_autoclosed;
 4144                        if always_treat_brackets_as_autoclosed
 4145                            && is_bracket_pair_end
 4146                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4147                        {
 4148                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4149                            // and the inserted text is a closing bracket and the selection is followed
 4150                            // by the closing bracket then move the selection past the closing bracket.
 4151                            let anchor = snapshot.anchor_after(selection.end);
 4152                            new_selections.push((selection.map(|_| anchor), text.len()));
 4153                            continue;
 4154                        }
 4155                    }
 4156                    // If an opening bracket is 1 character long and is typed while
 4157                    // text is selected, then surround that text with the bracket pair.
 4158                    else if auto_surround
 4159                        && bracket_pair.surround
 4160                        && is_bracket_pair_start
 4161                        && bracket_pair.start.chars().count() == 1
 4162                    {
 4163                        edits.push((selection.start..selection.start, text.clone()));
 4164                        edits.push((
 4165                            selection.end..selection.end,
 4166                            bracket_pair.end.as_str().into(),
 4167                        ));
 4168                        bracket_inserted = true;
 4169                        new_selections.push((
 4170                            Selection {
 4171                                id: selection.id,
 4172                                start: snapshot.anchor_after(selection.start),
 4173                                end: snapshot.anchor_before(selection.end),
 4174                                reversed: selection.reversed,
 4175                                goal: selection.goal,
 4176                            },
 4177                            0,
 4178                        ));
 4179                        continue;
 4180                    }
 4181                }
 4182            }
 4183
 4184            if self.auto_replace_emoji_shortcode
 4185                && selection.is_empty()
 4186                && text.as_ref().ends_with(':')
 4187                && let Some(possible_emoji_short_code) =
 4188                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4189                && !possible_emoji_short_code.is_empty()
 4190                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4191            {
 4192                let emoji_shortcode_start = Point::new(
 4193                    selection.start.row,
 4194                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4195                );
 4196
 4197                // Remove shortcode from buffer
 4198                edits.push((
 4199                    emoji_shortcode_start..selection.start,
 4200                    "".to_string().into(),
 4201                ));
 4202                new_selections.push((
 4203                    Selection {
 4204                        id: selection.id,
 4205                        start: snapshot.anchor_after(emoji_shortcode_start),
 4206                        end: snapshot.anchor_before(selection.start),
 4207                        reversed: selection.reversed,
 4208                        goal: selection.goal,
 4209                    },
 4210                    0,
 4211                ));
 4212
 4213                // Insert emoji
 4214                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4215                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4216                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4217
 4218                continue;
 4219            }
 4220
 4221            // If not handling any auto-close operation, then just replace the selected
 4222            // text with the given input and move the selection to the end of the
 4223            // newly inserted text.
 4224            let anchor = snapshot.anchor_after(selection.end);
 4225            if !self.linked_edit_ranges.is_empty() {
 4226                let start_anchor = snapshot.anchor_before(selection.start);
 4227
 4228                let is_word_char = text.chars().next().is_none_or(|char| {
 4229                    let classifier = snapshot
 4230                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4231                        .ignore_punctuation(true);
 4232                    classifier.is_word(char)
 4233                });
 4234
 4235                if is_word_char {
 4236                    if let Some(ranges) = self
 4237                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4238                    {
 4239                        for (buffer, edits) in ranges {
 4240                            linked_edits
 4241                                .entry(buffer.clone())
 4242                                .or_default()
 4243                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4244                        }
 4245                    }
 4246                } else {
 4247                    clear_linked_edit_ranges = true;
 4248                }
 4249            }
 4250
 4251            new_selections.push((selection.map(|_| anchor), 0));
 4252            edits.push((selection.start..selection.end, text.clone()));
 4253        }
 4254
 4255        drop(snapshot);
 4256
 4257        self.transact(window, cx, |this, window, cx| {
 4258            if clear_linked_edit_ranges {
 4259                this.linked_edit_ranges.clear();
 4260            }
 4261            let initial_buffer_versions =
 4262                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4263
 4264            this.buffer.update(cx, |buffer, cx| {
 4265                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4266            });
 4267            for (buffer, edits) in linked_edits {
 4268                buffer.update(cx, |buffer, cx| {
 4269                    let snapshot = buffer.snapshot();
 4270                    let edits = edits
 4271                        .into_iter()
 4272                        .map(|(range, text)| {
 4273                            use text::ToPoint as TP;
 4274                            let end_point = TP::to_point(&range.end, &snapshot);
 4275                            let start_point = TP::to_point(&range.start, &snapshot);
 4276                            (start_point..end_point, text)
 4277                        })
 4278                        .sorted_by_key(|(range, _)| range.start);
 4279                    buffer.edit(edits, None, cx);
 4280                })
 4281            }
 4282            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4283            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4284            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4285            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4286                .zip(new_selection_deltas)
 4287                .map(|(selection, delta)| Selection {
 4288                    id: selection.id,
 4289                    start: selection.start + delta,
 4290                    end: selection.end + delta,
 4291                    reversed: selection.reversed,
 4292                    goal: SelectionGoal::None,
 4293                })
 4294                .collect::<Vec<_>>();
 4295
 4296            let mut i = 0;
 4297            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4298                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4299                let start = map.buffer_snapshot.anchor_before(position);
 4300                let end = map.buffer_snapshot.anchor_after(position);
 4301                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4302                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4303                        Ordering::Less => i += 1,
 4304                        Ordering::Greater => break,
 4305                        Ordering::Equal => {
 4306                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4307                                Ordering::Less => i += 1,
 4308                                Ordering::Equal => break,
 4309                                Ordering::Greater => break,
 4310                            }
 4311                        }
 4312                    }
 4313                }
 4314                this.autoclose_regions.insert(
 4315                    i,
 4316                    AutocloseRegion {
 4317                        selection_id,
 4318                        range: start..end,
 4319                        pair,
 4320                    },
 4321                );
 4322            }
 4323
 4324            let had_active_edit_prediction = this.has_active_edit_prediction();
 4325            this.change_selections(
 4326                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4327                window,
 4328                cx,
 4329                |s| s.select(new_selections),
 4330            );
 4331
 4332            if !bracket_inserted
 4333                && let Some(on_type_format_task) =
 4334                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4335            {
 4336                on_type_format_task.detach_and_log_err(cx);
 4337            }
 4338
 4339            let editor_settings = EditorSettings::get_global(cx);
 4340            if bracket_inserted
 4341                && (editor_settings.auto_signature_help
 4342                    || editor_settings.show_signature_help_after_edits)
 4343            {
 4344                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4345            }
 4346
 4347            let trigger_in_words =
 4348                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4349            if this.hard_wrap.is_some() {
 4350                let latest: Range<Point> = this.selections.newest(cx).range();
 4351                if latest.is_empty()
 4352                    && this
 4353                        .buffer()
 4354                        .read(cx)
 4355                        .snapshot(cx)
 4356                        .line_len(MultiBufferRow(latest.start.row))
 4357                        == latest.start.column
 4358                {
 4359                    this.rewrap_impl(
 4360                        RewrapOptions {
 4361                            override_language_settings: true,
 4362                            preserve_existing_whitespace: true,
 4363                        },
 4364                        cx,
 4365                    )
 4366                }
 4367            }
 4368            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4369            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4370            this.refresh_edit_prediction(true, false, window, cx);
 4371            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4372        });
 4373    }
 4374
 4375    fn find_possible_emoji_shortcode_at_position(
 4376        snapshot: &MultiBufferSnapshot,
 4377        position: Point,
 4378    ) -> Option<String> {
 4379        let mut chars = Vec::new();
 4380        let mut found_colon = false;
 4381        for char in snapshot.reversed_chars_at(position).take(100) {
 4382            // Found a possible emoji shortcode in the middle of the buffer
 4383            if found_colon {
 4384                if char.is_whitespace() {
 4385                    chars.reverse();
 4386                    return Some(chars.iter().collect());
 4387                }
 4388                // If the previous character is not a whitespace, we are in the middle of a word
 4389                // and we only want to complete the shortcode if the word is made up of other emojis
 4390                let mut containing_word = String::new();
 4391                for ch in snapshot
 4392                    .reversed_chars_at(position)
 4393                    .skip(chars.len() + 1)
 4394                    .take(100)
 4395                {
 4396                    if ch.is_whitespace() {
 4397                        break;
 4398                    }
 4399                    containing_word.push(ch);
 4400                }
 4401                let containing_word = containing_word.chars().rev().collect::<String>();
 4402                if util::word_consists_of_emojis(containing_word.as_str()) {
 4403                    chars.reverse();
 4404                    return Some(chars.iter().collect());
 4405                }
 4406            }
 4407
 4408            if char.is_whitespace() || !char.is_ascii() {
 4409                return None;
 4410            }
 4411            if char == ':' {
 4412                found_colon = true;
 4413            } else {
 4414                chars.push(char);
 4415            }
 4416        }
 4417        // Found a possible emoji shortcode at the beginning of the buffer
 4418        chars.reverse();
 4419        Some(chars.iter().collect())
 4420    }
 4421
 4422    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4423        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4424        self.transact(window, cx, |this, window, cx| {
 4425            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4426                let selections = this.selections.all::<usize>(cx);
 4427                let multi_buffer = this.buffer.read(cx);
 4428                let buffer = multi_buffer.snapshot(cx);
 4429                selections
 4430                    .iter()
 4431                    .map(|selection| {
 4432                        let start_point = selection.start.to_point(&buffer);
 4433                        let mut existing_indent =
 4434                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4435                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4436                        let start = selection.start;
 4437                        let end = selection.end;
 4438                        let selection_is_empty = start == end;
 4439                        let language_scope = buffer.language_scope_at(start);
 4440                        let (
 4441                            comment_delimiter,
 4442                            doc_delimiter,
 4443                            insert_extra_newline,
 4444                            indent_on_newline,
 4445                            indent_on_extra_newline,
 4446                        ) = if let Some(language) = &language_scope {
 4447                            let mut insert_extra_newline =
 4448                                insert_extra_newline_brackets(&buffer, start..end, language)
 4449                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4450
 4451                            // Comment extension on newline is allowed only for cursor selections
 4452                            let comment_delimiter = maybe!({
 4453                                if !selection_is_empty {
 4454                                    return None;
 4455                                }
 4456
 4457                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4458                                    return None;
 4459                                }
 4460
 4461                                let delimiters = language.line_comment_prefixes();
 4462                                let max_len_of_delimiter =
 4463                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4464                                let (snapshot, range) =
 4465                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4466
 4467                                let num_of_whitespaces = snapshot
 4468                                    .chars_for_range(range.clone())
 4469                                    .take_while(|c| c.is_whitespace())
 4470                                    .count();
 4471                                let comment_candidate = snapshot
 4472                                    .chars_for_range(range.clone())
 4473                                    .skip(num_of_whitespaces)
 4474                                    .take(max_len_of_delimiter)
 4475                                    .collect::<String>();
 4476                                let (delimiter, trimmed_len) = delimiters
 4477                                    .iter()
 4478                                    .filter_map(|delimiter| {
 4479                                        let prefix = delimiter.trim_end();
 4480                                        if comment_candidate.starts_with(prefix) {
 4481                                            Some((delimiter, prefix.len()))
 4482                                        } else {
 4483                                            None
 4484                                        }
 4485                                    })
 4486                                    .max_by_key(|(_, len)| *len)?;
 4487
 4488                                if let Some(BlockCommentConfig {
 4489                                    start: block_start, ..
 4490                                }) = language.block_comment()
 4491                                {
 4492                                    let block_start_trimmed = block_start.trim_end();
 4493                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4494                                        let line_content = snapshot
 4495                                            .chars_for_range(range)
 4496                                            .skip(num_of_whitespaces)
 4497                                            .take(block_start_trimmed.len())
 4498                                            .collect::<String>();
 4499
 4500                                        if line_content.starts_with(block_start_trimmed) {
 4501                                            return None;
 4502                                        }
 4503                                    }
 4504                                }
 4505
 4506                                let cursor_is_placed_after_comment_marker =
 4507                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4508                                if cursor_is_placed_after_comment_marker {
 4509                                    Some(delimiter.clone())
 4510                                } else {
 4511                                    None
 4512                                }
 4513                            });
 4514
 4515                            let mut indent_on_newline = IndentSize::spaces(0);
 4516                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4517
 4518                            let doc_delimiter = maybe!({
 4519                                if !selection_is_empty {
 4520                                    return None;
 4521                                }
 4522
 4523                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4524                                    return None;
 4525                                }
 4526
 4527                                let BlockCommentConfig {
 4528                                    start: start_tag,
 4529                                    end: end_tag,
 4530                                    prefix: delimiter,
 4531                                    tab_size: len,
 4532                                } = language.documentation_comment()?;
 4533                                let is_within_block_comment = buffer
 4534                                    .language_scope_at(start_point)
 4535                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4536                                if !is_within_block_comment {
 4537                                    return None;
 4538                                }
 4539
 4540                                let (snapshot, range) =
 4541                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4542
 4543                                let num_of_whitespaces = snapshot
 4544                                    .chars_for_range(range.clone())
 4545                                    .take_while(|c| c.is_whitespace())
 4546                                    .count();
 4547
 4548                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4549                                let column = start_point.column;
 4550                                let cursor_is_after_start_tag = {
 4551                                    let start_tag_len = start_tag.len();
 4552                                    let start_tag_line = snapshot
 4553                                        .chars_for_range(range.clone())
 4554                                        .skip(num_of_whitespaces)
 4555                                        .take(start_tag_len)
 4556                                        .collect::<String>();
 4557                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4558                                        num_of_whitespaces + start_tag_len <= column as usize
 4559                                    } else {
 4560                                        false
 4561                                    }
 4562                                };
 4563
 4564                                let cursor_is_after_delimiter = {
 4565                                    let delimiter_trim = delimiter.trim_end();
 4566                                    let delimiter_line = snapshot
 4567                                        .chars_for_range(range.clone())
 4568                                        .skip(num_of_whitespaces)
 4569                                        .take(delimiter_trim.len())
 4570                                        .collect::<String>();
 4571                                    if delimiter_line.starts_with(delimiter_trim) {
 4572                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4573                                    } else {
 4574                                        false
 4575                                    }
 4576                                };
 4577
 4578                                let cursor_is_before_end_tag_if_exists = {
 4579                                    let mut char_position = 0u32;
 4580                                    let mut end_tag_offset = None;
 4581
 4582                                    'outer: for chunk in snapshot.text_for_range(range) {
 4583                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4584                                            let chars_before_match =
 4585                                                chunk[..byte_pos].chars().count() as u32;
 4586                                            end_tag_offset =
 4587                                                Some(char_position + chars_before_match);
 4588                                            break 'outer;
 4589                                        }
 4590                                        char_position += chunk.chars().count() as u32;
 4591                                    }
 4592
 4593                                    if let Some(end_tag_offset) = end_tag_offset {
 4594                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4595                                        if cursor_is_after_start_tag {
 4596                                            if cursor_is_before_end_tag {
 4597                                                insert_extra_newline = true;
 4598                                            }
 4599                                            let cursor_is_at_start_of_end_tag =
 4600                                                column == end_tag_offset;
 4601                                            if cursor_is_at_start_of_end_tag {
 4602                                                indent_on_extra_newline.len = *len;
 4603                                            }
 4604                                        }
 4605                                        cursor_is_before_end_tag
 4606                                    } else {
 4607                                        true
 4608                                    }
 4609                                };
 4610
 4611                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4612                                    && cursor_is_before_end_tag_if_exists
 4613                                {
 4614                                    if cursor_is_after_start_tag {
 4615                                        indent_on_newline.len = *len;
 4616                                    }
 4617                                    Some(delimiter.clone())
 4618                                } else {
 4619                                    None
 4620                                }
 4621                            });
 4622
 4623                            (
 4624                                comment_delimiter,
 4625                                doc_delimiter,
 4626                                insert_extra_newline,
 4627                                indent_on_newline,
 4628                                indent_on_extra_newline,
 4629                            )
 4630                        } else {
 4631                            (
 4632                                None,
 4633                                None,
 4634                                false,
 4635                                IndentSize::default(),
 4636                                IndentSize::default(),
 4637                            )
 4638                        };
 4639
 4640                        let prevent_auto_indent = doc_delimiter.is_some();
 4641                        let delimiter = comment_delimiter.or(doc_delimiter);
 4642
 4643                        let capacity_for_delimiter =
 4644                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4645                        let mut new_text = String::with_capacity(
 4646                            1 + capacity_for_delimiter
 4647                                + existing_indent.len as usize
 4648                                + indent_on_newline.len as usize
 4649                                + indent_on_extra_newline.len as usize,
 4650                        );
 4651                        new_text.push('\n');
 4652                        new_text.extend(existing_indent.chars());
 4653                        new_text.extend(indent_on_newline.chars());
 4654
 4655                        if let Some(delimiter) = &delimiter {
 4656                            new_text.push_str(delimiter);
 4657                        }
 4658
 4659                        if insert_extra_newline {
 4660                            new_text.push('\n');
 4661                            new_text.extend(existing_indent.chars());
 4662                            new_text.extend(indent_on_extra_newline.chars());
 4663                        }
 4664
 4665                        let anchor = buffer.anchor_after(end);
 4666                        let new_selection = selection.map(|_| anchor);
 4667                        (
 4668                            ((start..end, new_text), prevent_auto_indent),
 4669                            (insert_extra_newline, new_selection),
 4670                        )
 4671                    })
 4672                    .unzip()
 4673            };
 4674
 4675            let mut auto_indent_edits = Vec::new();
 4676            let mut edits = Vec::new();
 4677            for (edit, prevent_auto_indent) in edits_with_flags {
 4678                if prevent_auto_indent {
 4679                    edits.push(edit);
 4680                } else {
 4681                    auto_indent_edits.push(edit);
 4682                }
 4683            }
 4684            if !edits.is_empty() {
 4685                this.edit(edits, cx);
 4686            }
 4687            if !auto_indent_edits.is_empty() {
 4688                this.edit_with_autoindent(auto_indent_edits, cx);
 4689            }
 4690
 4691            let buffer = this.buffer.read(cx).snapshot(cx);
 4692            let new_selections = selection_info
 4693                .into_iter()
 4694                .map(|(extra_newline_inserted, new_selection)| {
 4695                    let mut cursor = new_selection.end.to_point(&buffer);
 4696                    if extra_newline_inserted {
 4697                        cursor.row -= 1;
 4698                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4699                    }
 4700                    new_selection.map(|_| cursor)
 4701                })
 4702                .collect();
 4703
 4704            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4705            this.refresh_edit_prediction(true, false, window, cx);
 4706        });
 4707    }
 4708
 4709    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4710        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4711
 4712        let buffer = self.buffer.read(cx);
 4713        let snapshot = buffer.snapshot(cx);
 4714
 4715        let mut edits = Vec::new();
 4716        let mut rows = Vec::new();
 4717
 4718        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4719            let cursor = selection.head();
 4720            let row = cursor.row;
 4721
 4722            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4723
 4724            let newline = "\n".to_string();
 4725            edits.push((start_of_line..start_of_line, newline));
 4726
 4727            rows.push(row + rows_inserted as u32);
 4728        }
 4729
 4730        self.transact(window, cx, |editor, window, cx| {
 4731            editor.edit(edits, cx);
 4732
 4733            editor.change_selections(Default::default(), window, cx, |s| {
 4734                let mut index = 0;
 4735                s.move_cursors_with(|map, _, _| {
 4736                    let row = rows[index];
 4737                    index += 1;
 4738
 4739                    let point = Point::new(row, 0);
 4740                    let boundary = map.next_line_boundary(point).1;
 4741                    let clipped = map.clip_point(boundary, Bias::Left);
 4742
 4743                    (clipped, SelectionGoal::None)
 4744                });
 4745            });
 4746
 4747            let mut indent_edits = Vec::new();
 4748            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4749            for row in rows {
 4750                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4751                for (row, indent) in indents {
 4752                    if indent.len == 0 {
 4753                        continue;
 4754                    }
 4755
 4756                    let text = match indent.kind {
 4757                        IndentKind::Space => " ".repeat(indent.len as usize),
 4758                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4759                    };
 4760                    let point = Point::new(row.0, 0);
 4761                    indent_edits.push((point..point, text));
 4762                }
 4763            }
 4764            editor.edit(indent_edits, cx);
 4765        });
 4766    }
 4767
 4768    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4769        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4770
 4771        let buffer = self.buffer.read(cx);
 4772        let snapshot = buffer.snapshot(cx);
 4773
 4774        let mut edits = Vec::new();
 4775        let mut rows = Vec::new();
 4776        let mut rows_inserted = 0;
 4777
 4778        for selection in self.selections.all_adjusted(cx) {
 4779            let cursor = selection.head();
 4780            let row = cursor.row;
 4781
 4782            let point = Point::new(row + 1, 0);
 4783            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4784
 4785            let newline = "\n".to_string();
 4786            edits.push((start_of_line..start_of_line, newline));
 4787
 4788            rows_inserted += 1;
 4789            rows.push(row + rows_inserted);
 4790        }
 4791
 4792        self.transact(window, cx, |editor, window, cx| {
 4793            editor.edit(edits, cx);
 4794
 4795            editor.change_selections(Default::default(), window, cx, |s| {
 4796                let mut index = 0;
 4797                s.move_cursors_with(|map, _, _| {
 4798                    let row = rows[index];
 4799                    index += 1;
 4800
 4801                    let point = Point::new(row, 0);
 4802                    let boundary = map.next_line_boundary(point).1;
 4803                    let clipped = map.clip_point(boundary, Bias::Left);
 4804
 4805                    (clipped, SelectionGoal::None)
 4806                });
 4807            });
 4808
 4809            let mut indent_edits = Vec::new();
 4810            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4811            for row in rows {
 4812                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4813                for (row, indent) in indents {
 4814                    if indent.len == 0 {
 4815                        continue;
 4816                    }
 4817
 4818                    let text = match indent.kind {
 4819                        IndentKind::Space => " ".repeat(indent.len as usize),
 4820                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4821                    };
 4822                    let point = Point::new(row.0, 0);
 4823                    indent_edits.push((point..point, text));
 4824                }
 4825            }
 4826            editor.edit(indent_edits, cx);
 4827        });
 4828    }
 4829
 4830    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4831        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4832            original_indent_columns: Vec::new(),
 4833        });
 4834        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4835    }
 4836
 4837    fn insert_with_autoindent_mode(
 4838        &mut self,
 4839        text: &str,
 4840        autoindent_mode: Option<AutoindentMode>,
 4841        window: &mut Window,
 4842        cx: &mut Context<Self>,
 4843    ) {
 4844        if self.read_only(cx) {
 4845            return;
 4846        }
 4847
 4848        let text: Arc<str> = text.into();
 4849        self.transact(window, cx, |this, window, cx| {
 4850            let old_selections = this.selections.all_adjusted(cx);
 4851            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4852                let anchors = {
 4853                    let snapshot = buffer.read(cx);
 4854                    old_selections
 4855                        .iter()
 4856                        .map(|s| {
 4857                            let anchor = snapshot.anchor_after(s.head());
 4858                            s.map(|_| anchor)
 4859                        })
 4860                        .collect::<Vec<_>>()
 4861                };
 4862                buffer.edit(
 4863                    old_selections
 4864                        .iter()
 4865                        .map(|s| (s.start..s.end, text.clone())),
 4866                    autoindent_mode,
 4867                    cx,
 4868                );
 4869                anchors
 4870            });
 4871
 4872            this.change_selections(Default::default(), window, cx, |s| {
 4873                s.select_anchors(selection_anchors);
 4874            });
 4875
 4876            cx.notify();
 4877        });
 4878    }
 4879
 4880    fn trigger_completion_on_input(
 4881        &mut self,
 4882        text: &str,
 4883        trigger_in_words: bool,
 4884        window: &mut Window,
 4885        cx: &mut Context<Self>,
 4886    ) {
 4887        let completions_source = self
 4888            .context_menu
 4889            .borrow()
 4890            .as_ref()
 4891            .and_then(|menu| match menu {
 4892                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4893                CodeContextMenu::CodeActions(_) => None,
 4894            });
 4895
 4896        match completions_source {
 4897            Some(CompletionsMenuSource::Words { .. }) => {
 4898                self.open_or_update_completions_menu(
 4899                    Some(CompletionsMenuSource::Words {
 4900                        ignore_threshold: false,
 4901                    }),
 4902                    None,
 4903                    window,
 4904                    cx,
 4905                );
 4906            }
 4907            Some(CompletionsMenuSource::Normal)
 4908            | Some(CompletionsMenuSource::SnippetChoices)
 4909            | None
 4910                if self.is_completion_trigger(
 4911                    text,
 4912                    trigger_in_words,
 4913                    completions_source.is_some(),
 4914                    cx,
 4915                ) =>
 4916            {
 4917                self.show_completions(
 4918                    &ShowCompletions {
 4919                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4920                    },
 4921                    window,
 4922                    cx,
 4923                )
 4924            }
 4925            _ => {
 4926                self.hide_context_menu(window, cx);
 4927            }
 4928        }
 4929    }
 4930
 4931    fn is_completion_trigger(
 4932        &self,
 4933        text: &str,
 4934        trigger_in_words: bool,
 4935        menu_is_open: bool,
 4936        cx: &mut Context<Self>,
 4937    ) -> bool {
 4938        let position = self.selections.newest_anchor().head();
 4939        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4940            return false;
 4941        };
 4942
 4943        if let Some(completion_provider) = &self.completion_provider {
 4944            completion_provider.is_completion_trigger(
 4945                &buffer,
 4946                position.text_anchor,
 4947                text,
 4948                trigger_in_words,
 4949                menu_is_open,
 4950                cx,
 4951            )
 4952        } else {
 4953            false
 4954        }
 4955    }
 4956
 4957    /// If any empty selections is touching the start of its innermost containing autoclose
 4958    /// region, expand it to select the brackets.
 4959    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4960        let selections = self.selections.all::<usize>(cx);
 4961        let buffer = self.buffer.read(cx).read(cx);
 4962        let new_selections = self
 4963            .selections_with_autoclose_regions(selections, &buffer)
 4964            .map(|(mut selection, region)| {
 4965                if !selection.is_empty() {
 4966                    return selection;
 4967                }
 4968
 4969                if let Some(region) = region {
 4970                    let mut range = region.range.to_offset(&buffer);
 4971                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4972                        range.start -= region.pair.start.len();
 4973                        if buffer.contains_str_at(range.start, &region.pair.start)
 4974                            && buffer.contains_str_at(range.end, &region.pair.end)
 4975                        {
 4976                            range.end += region.pair.end.len();
 4977                            selection.start = range.start;
 4978                            selection.end = range.end;
 4979
 4980                            return selection;
 4981                        }
 4982                    }
 4983                }
 4984
 4985                let always_treat_brackets_as_autoclosed = buffer
 4986                    .language_settings_at(selection.start, cx)
 4987                    .always_treat_brackets_as_autoclosed;
 4988
 4989                if !always_treat_brackets_as_autoclosed {
 4990                    return selection;
 4991                }
 4992
 4993                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4994                    for (pair, enabled) in scope.brackets() {
 4995                        if !enabled || !pair.close {
 4996                            continue;
 4997                        }
 4998
 4999                        if buffer.contains_str_at(selection.start, &pair.end) {
 5000                            let pair_start_len = pair.start.len();
 5001                            if buffer.contains_str_at(
 5002                                selection.start.saturating_sub(pair_start_len),
 5003                                &pair.start,
 5004                            ) {
 5005                                selection.start -= pair_start_len;
 5006                                selection.end += pair.end.len();
 5007
 5008                                return selection;
 5009                            }
 5010                        }
 5011                    }
 5012                }
 5013
 5014                selection
 5015            })
 5016            .collect();
 5017
 5018        drop(buffer);
 5019        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5020            selections.select(new_selections)
 5021        });
 5022    }
 5023
 5024    /// Iterate the given selections, and for each one, find the smallest surrounding
 5025    /// autoclose region. This uses the ordering of the selections and the autoclose
 5026    /// regions to avoid repeated comparisons.
 5027    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5028        &'a self,
 5029        selections: impl IntoIterator<Item = Selection<D>>,
 5030        buffer: &'a MultiBufferSnapshot,
 5031    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5032        let mut i = 0;
 5033        let mut regions = self.autoclose_regions.as_slice();
 5034        selections.into_iter().map(move |selection| {
 5035            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5036
 5037            let mut enclosing = None;
 5038            while let Some(pair_state) = regions.get(i) {
 5039                if pair_state.range.end.to_offset(buffer) < range.start {
 5040                    regions = &regions[i + 1..];
 5041                    i = 0;
 5042                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5043                    break;
 5044                } else {
 5045                    if pair_state.selection_id == selection.id {
 5046                        enclosing = Some(pair_state);
 5047                    }
 5048                    i += 1;
 5049                }
 5050            }
 5051
 5052            (selection, enclosing)
 5053        })
 5054    }
 5055
 5056    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5057    fn invalidate_autoclose_regions(
 5058        &mut self,
 5059        mut selections: &[Selection<Anchor>],
 5060        buffer: &MultiBufferSnapshot,
 5061    ) {
 5062        self.autoclose_regions.retain(|state| {
 5063            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5064                return false;
 5065            }
 5066
 5067            let mut i = 0;
 5068            while let Some(selection) = selections.get(i) {
 5069                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5070                    selections = &selections[1..];
 5071                    continue;
 5072                }
 5073                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5074                    break;
 5075                }
 5076                if selection.id == state.selection_id {
 5077                    return true;
 5078                } else {
 5079                    i += 1;
 5080                }
 5081            }
 5082            false
 5083        });
 5084    }
 5085
 5086    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5087        let offset = position.to_offset(buffer);
 5088        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5089        if offset > word_range.start && kind == Some(CharKind::Word) {
 5090            Some(
 5091                buffer
 5092                    .text_for_range(word_range.start..offset)
 5093                    .collect::<String>(),
 5094            )
 5095        } else {
 5096            None
 5097        }
 5098    }
 5099
 5100    pub fn toggle_inline_values(
 5101        &mut self,
 5102        _: &ToggleInlineValues,
 5103        _: &mut Window,
 5104        cx: &mut Context<Self>,
 5105    ) {
 5106        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5107
 5108        self.refresh_inline_values(cx);
 5109    }
 5110
 5111    pub fn toggle_inlay_hints(
 5112        &mut self,
 5113        _: &ToggleInlayHints,
 5114        _: &mut Window,
 5115        cx: &mut Context<Self>,
 5116    ) {
 5117        self.refresh_inlay_hints(
 5118            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5119            cx,
 5120        );
 5121    }
 5122
 5123    pub fn inlay_hints_enabled(&self) -> bool {
 5124        self.inlay_hint_cache.enabled
 5125    }
 5126
 5127    pub fn inline_values_enabled(&self) -> bool {
 5128        self.inline_value_cache.enabled
 5129    }
 5130
 5131    #[cfg(any(test, feature = "test-support"))]
 5132    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5133        self.display_map
 5134            .read(cx)
 5135            .current_inlays()
 5136            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5137            .cloned()
 5138            .collect()
 5139    }
 5140
 5141    #[cfg(any(test, feature = "test-support"))]
 5142    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5143        self.display_map
 5144            .read(cx)
 5145            .current_inlays()
 5146            .cloned()
 5147            .collect()
 5148    }
 5149
 5150    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5151        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5152            return;
 5153        }
 5154
 5155        let reason_description = reason.description();
 5156        let ignore_debounce = matches!(
 5157            reason,
 5158            InlayHintRefreshReason::SettingsChange(_)
 5159                | InlayHintRefreshReason::Toggle(_)
 5160                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5161                | InlayHintRefreshReason::ModifiersChanged(_)
 5162        );
 5163        let (invalidate_cache, required_languages) = match reason {
 5164            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5165                match self.inlay_hint_cache.modifiers_override(enabled) {
 5166                    Some(enabled) => {
 5167                        if enabled {
 5168                            (InvalidationStrategy::RefreshRequested, None)
 5169                        } else {
 5170                            self.splice_inlays(
 5171                                &self
 5172                                    .visible_inlay_hints(cx)
 5173                                    .iter()
 5174                                    .map(|inlay| inlay.id)
 5175                                    .collect::<Vec<InlayId>>(),
 5176                                Vec::new(),
 5177                                cx,
 5178                            );
 5179                            return;
 5180                        }
 5181                    }
 5182                    None => return,
 5183                }
 5184            }
 5185            InlayHintRefreshReason::Toggle(enabled) => {
 5186                if self.inlay_hint_cache.toggle(enabled) {
 5187                    if enabled {
 5188                        (InvalidationStrategy::RefreshRequested, None)
 5189                    } else {
 5190                        self.splice_inlays(
 5191                            &self
 5192                                .visible_inlay_hints(cx)
 5193                                .iter()
 5194                                .map(|inlay| inlay.id)
 5195                                .collect::<Vec<InlayId>>(),
 5196                            Vec::new(),
 5197                            cx,
 5198                        );
 5199                        return;
 5200                    }
 5201                } else {
 5202                    return;
 5203                }
 5204            }
 5205            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5206                match self.inlay_hint_cache.update_settings(
 5207                    &self.buffer,
 5208                    new_settings,
 5209                    self.visible_inlay_hints(cx),
 5210                    cx,
 5211                ) {
 5212                    ControlFlow::Break(Some(InlaySplice {
 5213                        to_remove,
 5214                        to_insert,
 5215                    })) => {
 5216                        self.splice_inlays(&to_remove, to_insert, cx);
 5217                        return;
 5218                    }
 5219                    ControlFlow::Break(None) => return,
 5220                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5221                }
 5222            }
 5223            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5224                if let Some(InlaySplice {
 5225                    to_remove,
 5226                    to_insert,
 5227                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5228                {
 5229                    self.splice_inlays(&to_remove, to_insert, cx);
 5230                }
 5231                self.display_map.update(cx, |display_map, _| {
 5232                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5233                });
 5234                return;
 5235            }
 5236            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5237            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5238                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5239            }
 5240            InlayHintRefreshReason::RefreshRequested => {
 5241                (InvalidationStrategy::RefreshRequested, None)
 5242            }
 5243        };
 5244
 5245        if let Some(InlaySplice {
 5246            to_remove,
 5247            to_insert,
 5248        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5249            reason_description,
 5250            self.visible_excerpts(required_languages.as_ref(), cx),
 5251            invalidate_cache,
 5252            ignore_debounce,
 5253            cx,
 5254        ) {
 5255            self.splice_inlays(&to_remove, to_insert, cx);
 5256        }
 5257    }
 5258
 5259    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5260        self.display_map
 5261            .read(cx)
 5262            .current_inlays()
 5263            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5264            .cloned()
 5265            .collect()
 5266    }
 5267
 5268    pub fn visible_excerpts(
 5269        &self,
 5270        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5271        cx: &mut Context<Editor>,
 5272    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5273        let Some(project) = self.project() else {
 5274            return HashMap::default();
 5275        };
 5276        let project = project.read(cx);
 5277        let multi_buffer = self.buffer().read(cx);
 5278        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5279        let multi_buffer_visible_start = self
 5280            .scroll_manager
 5281            .anchor()
 5282            .anchor
 5283            .to_point(&multi_buffer_snapshot);
 5284        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5285            multi_buffer_visible_start
 5286                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5287            Bias::Left,
 5288        );
 5289        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5290        multi_buffer_snapshot
 5291            .range_to_buffer_ranges(multi_buffer_visible_range)
 5292            .into_iter()
 5293            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5294            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5295                let buffer_file = project::File::from_dyn(buffer.file())?;
 5296                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5297                let worktree_entry = buffer_worktree
 5298                    .read(cx)
 5299                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5300                if worktree_entry.is_ignored {
 5301                    return None;
 5302                }
 5303
 5304                let language = buffer.language()?;
 5305                if let Some(restrict_to_languages) = restrict_to_languages
 5306                    && !restrict_to_languages.contains(language)
 5307                {
 5308                    return None;
 5309                }
 5310                Some((
 5311                    excerpt_id,
 5312                    (
 5313                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5314                        buffer.version().clone(),
 5315                        excerpt_visible_range,
 5316                    ),
 5317                ))
 5318            })
 5319            .collect()
 5320    }
 5321
 5322    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5323        TextLayoutDetails {
 5324            text_system: window.text_system().clone(),
 5325            editor_style: self.style.clone().unwrap(),
 5326            rem_size: window.rem_size(),
 5327            scroll_anchor: self.scroll_manager.anchor(),
 5328            visible_rows: self.visible_line_count(),
 5329            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5330        }
 5331    }
 5332
 5333    pub fn splice_inlays(
 5334        &self,
 5335        to_remove: &[InlayId],
 5336        to_insert: Vec<Inlay>,
 5337        cx: &mut Context<Self>,
 5338    ) {
 5339        self.display_map.update(cx, |display_map, cx| {
 5340            display_map.splice_inlays(to_remove, to_insert, cx)
 5341        });
 5342        cx.notify();
 5343    }
 5344
 5345    fn trigger_on_type_formatting(
 5346        &self,
 5347        input: String,
 5348        window: &mut Window,
 5349        cx: &mut Context<Self>,
 5350    ) -> Option<Task<Result<()>>> {
 5351        if input.len() != 1 {
 5352            return None;
 5353        }
 5354
 5355        let project = self.project()?;
 5356        let position = self.selections.newest_anchor().head();
 5357        let (buffer, buffer_position) = self
 5358            .buffer
 5359            .read(cx)
 5360            .text_anchor_for_position(position, cx)?;
 5361
 5362        let settings = language_settings::language_settings(
 5363            buffer
 5364                .read(cx)
 5365                .language_at(buffer_position)
 5366                .map(|l| l.name()),
 5367            buffer.read(cx).file(),
 5368            cx,
 5369        );
 5370        if !settings.use_on_type_format {
 5371            return None;
 5372        }
 5373
 5374        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5375        // hence we do LSP request & edit on host side only — add formats to host's history.
 5376        let push_to_lsp_host_history = true;
 5377        // If this is not the host, append its history with new edits.
 5378        let push_to_client_history = project.read(cx).is_via_collab();
 5379
 5380        let on_type_formatting = project.update(cx, |project, cx| {
 5381            project.on_type_format(
 5382                buffer.clone(),
 5383                buffer_position,
 5384                input,
 5385                push_to_lsp_host_history,
 5386                cx,
 5387            )
 5388        });
 5389        Some(cx.spawn_in(window, async move |editor, cx| {
 5390            if let Some(transaction) = on_type_formatting.await? {
 5391                if push_to_client_history {
 5392                    buffer
 5393                        .update(cx, |buffer, _| {
 5394                            buffer.push_transaction(transaction, Instant::now());
 5395                            buffer.finalize_last_transaction();
 5396                        })
 5397                        .ok();
 5398                }
 5399                editor.update(cx, |editor, cx| {
 5400                    editor.refresh_document_highlights(cx);
 5401                })?;
 5402            }
 5403            Ok(())
 5404        }))
 5405    }
 5406
 5407    pub fn show_word_completions(
 5408        &mut self,
 5409        _: &ShowWordCompletions,
 5410        window: &mut Window,
 5411        cx: &mut Context<Self>,
 5412    ) {
 5413        self.open_or_update_completions_menu(
 5414            Some(CompletionsMenuSource::Words {
 5415                ignore_threshold: true,
 5416            }),
 5417            None,
 5418            window,
 5419            cx,
 5420        );
 5421    }
 5422
 5423    pub fn show_completions(
 5424        &mut self,
 5425        options: &ShowCompletions,
 5426        window: &mut Window,
 5427        cx: &mut Context<Self>,
 5428    ) {
 5429        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5430    }
 5431
 5432    fn open_or_update_completions_menu(
 5433        &mut self,
 5434        requested_source: Option<CompletionsMenuSource>,
 5435        trigger: Option<&str>,
 5436        window: &mut Window,
 5437        cx: &mut Context<Self>,
 5438    ) {
 5439        if self.pending_rename.is_some() {
 5440            return;
 5441        }
 5442
 5443        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5444
 5445        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5446        // inserted and selected. To handle that case, the start of the selection is used so that
 5447        // the menu starts with all choices.
 5448        let position = self
 5449            .selections
 5450            .newest_anchor()
 5451            .start
 5452            .bias_right(&multibuffer_snapshot);
 5453        if position.diff_base_anchor.is_some() {
 5454            return;
 5455        }
 5456        let (buffer, buffer_position) =
 5457            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5458                output
 5459            } else {
 5460                return;
 5461            };
 5462        let buffer_snapshot = buffer.read(cx).snapshot();
 5463
 5464        let query: Option<Arc<String>> =
 5465            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5466
 5467        drop(multibuffer_snapshot);
 5468
 5469        let mut ignore_word_threshold = false;
 5470        let provider = match requested_source {
 5471            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5472            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5473                ignore_word_threshold = ignore_threshold;
 5474                None
 5475            }
 5476            Some(CompletionsMenuSource::SnippetChoices) => {
 5477                log::error!("bug: SnippetChoices requested_source is not handled");
 5478                None
 5479            }
 5480        };
 5481
 5482        let sort_completions = provider
 5483            .as_ref()
 5484            .is_some_and(|provider| provider.sort_completions());
 5485
 5486        let filter_completions = provider
 5487            .as_ref()
 5488            .is_none_or(|provider| provider.filter_completions());
 5489
 5490        let trigger_kind = match trigger {
 5491            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5492                CompletionTriggerKind::TRIGGER_CHARACTER
 5493            }
 5494            _ => CompletionTriggerKind::INVOKED,
 5495        };
 5496        let completion_context = CompletionContext {
 5497            trigger_character: trigger.and_then(|trigger| {
 5498                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5499                    Some(String::from(trigger))
 5500                } else {
 5501                    None
 5502                }
 5503            }),
 5504            trigger_kind,
 5505        };
 5506
 5507        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5508        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5509        // involve trigger chars, so this is skipped in that case.
 5510        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5511        {
 5512            let menu_is_open = matches!(
 5513                self.context_menu.borrow().as_ref(),
 5514                Some(CodeContextMenu::Completions(_))
 5515            );
 5516            if menu_is_open {
 5517                self.hide_context_menu(window, cx);
 5518            }
 5519        }
 5520
 5521        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5522            if filter_completions {
 5523                menu.filter(query.clone(), provider.clone(), window, cx);
 5524            }
 5525            // When `is_incomplete` is false, no need to re-query completions when the current query
 5526            // is a suffix of the initial query.
 5527            if !menu.is_incomplete {
 5528                // If the new query is a suffix of the old query (typing more characters) and
 5529                // the previous result was complete, the existing completions can be filtered.
 5530                //
 5531                // Note that this is always true for snippet completions.
 5532                let query_matches = match (&menu.initial_query, &query) {
 5533                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5534                    (None, _) => true,
 5535                    _ => false,
 5536                };
 5537                if query_matches {
 5538                    let position_matches = if menu.initial_position == position {
 5539                        true
 5540                    } else {
 5541                        let snapshot = self.buffer.read(cx).read(cx);
 5542                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5543                    };
 5544                    if position_matches {
 5545                        return;
 5546                    }
 5547                }
 5548            }
 5549        };
 5550
 5551        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5552            buffer_snapshot.surrounding_word(buffer_position, false)
 5553        {
 5554            let word_to_exclude = buffer_snapshot
 5555                .text_for_range(word_range.clone())
 5556                .collect::<String>();
 5557            (
 5558                buffer_snapshot.anchor_before(word_range.start)
 5559                    ..buffer_snapshot.anchor_after(buffer_position),
 5560                Some(word_to_exclude),
 5561            )
 5562        } else {
 5563            (buffer_position..buffer_position, None)
 5564        };
 5565
 5566        let language = buffer_snapshot
 5567            .language_at(buffer_position)
 5568            .map(|language| language.name());
 5569
 5570        let completion_settings =
 5571            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5572
 5573        let show_completion_documentation = buffer_snapshot
 5574            .settings_at(buffer_position, cx)
 5575            .show_completion_documentation;
 5576
 5577        // The document can be large, so stay in reasonable bounds when searching for words,
 5578        // otherwise completion pop-up might be slow to appear.
 5579        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5580        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5581        let min_word_search = buffer_snapshot.clip_point(
 5582            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5583            Bias::Left,
 5584        );
 5585        let max_word_search = buffer_snapshot.clip_point(
 5586            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5587            Bias::Right,
 5588        );
 5589        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5590            ..buffer_snapshot.point_to_offset(max_word_search);
 5591
 5592        let skip_digits = query
 5593            .as_ref()
 5594            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5595
 5596        let omit_word_completions = !self.word_completions_enabled
 5597            || (!ignore_word_threshold
 5598                && match &query {
 5599                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5600                    None => completion_settings.words_min_length != 0,
 5601                });
 5602
 5603        let (mut words, provider_responses) = match &provider {
 5604            Some(provider) => {
 5605                let provider_responses = provider.completions(
 5606                    position.excerpt_id,
 5607                    &buffer,
 5608                    buffer_position,
 5609                    completion_context,
 5610                    window,
 5611                    cx,
 5612                );
 5613
 5614                let words = match (omit_word_completions, completion_settings.words) {
 5615                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5616                        Task::ready(BTreeMap::default())
 5617                    }
 5618                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5619                        .background_spawn(async move {
 5620                            buffer_snapshot.words_in_range(WordsQuery {
 5621                                fuzzy_contents: None,
 5622                                range: word_search_range,
 5623                                skip_digits,
 5624                            })
 5625                        }),
 5626                };
 5627
 5628                (words, provider_responses)
 5629            }
 5630            None => {
 5631                let words = if omit_word_completions {
 5632                    Task::ready(BTreeMap::default())
 5633                } else {
 5634                    cx.background_spawn(async move {
 5635                        buffer_snapshot.words_in_range(WordsQuery {
 5636                            fuzzy_contents: None,
 5637                            range: word_search_range,
 5638                            skip_digits,
 5639                        })
 5640                    })
 5641                };
 5642                (words, Task::ready(Ok(Vec::new())))
 5643            }
 5644        };
 5645
 5646        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5647
 5648        let id = post_inc(&mut self.next_completion_id);
 5649        let task = cx.spawn_in(window, async move |editor, cx| {
 5650            let Ok(()) = editor.update(cx, |this, _| {
 5651                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5652            }) else {
 5653                return;
 5654            };
 5655
 5656            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5657            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5658            let mut completions = Vec::new();
 5659            let mut is_incomplete = false;
 5660            let mut display_options: Option<CompletionDisplayOptions> = None;
 5661            if let Some(provider_responses) = provider_responses.await.log_err()
 5662                && !provider_responses.is_empty()
 5663            {
 5664                for response in provider_responses {
 5665                    completions.extend(response.completions);
 5666                    is_incomplete = is_incomplete || response.is_incomplete;
 5667                    match display_options.as_mut() {
 5668                        None => {
 5669                            display_options = Some(response.display_options);
 5670                        }
 5671                        Some(options) => options.merge(&response.display_options),
 5672                    }
 5673                }
 5674                if completion_settings.words == WordsCompletionMode::Fallback {
 5675                    words = Task::ready(BTreeMap::default());
 5676                }
 5677            }
 5678            let display_options = display_options.unwrap_or_default();
 5679
 5680            let mut words = words.await;
 5681            if let Some(word_to_exclude) = &word_to_exclude {
 5682                words.remove(word_to_exclude);
 5683            }
 5684            for lsp_completion in &completions {
 5685                words.remove(&lsp_completion.new_text);
 5686            }
 5687            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5688                replace_range: word_replace_range.clone(),
 5689                new_text: word.clone(),
 5690                label: CodeLabel::plain(word, None),
 5691                icon_path: None,
 5692                documentation: None,
 5693                source: CompletionSource::BufferWord {
 5694                    word_range,
 5695                    resolved: false,
 5696                },
 5697                insert_text_mode: Some(InsertTextMode::AS_IS),
 5698                confirm: None,
 5699            }));
 5700
 5701            let menu = if completions.is_empty() {
 5702                None
 5703            } else {
 5704                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5705                    let languages = editor
 5706                        .workspace
 5707                        .as_ref()
 5708                        .and_then(|(workspace, _)| workspace.upgrade())
 5709                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5710                    let menu = CompletionsMenu::new(
 5711                        id,
 5712                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5713                        sort_completions,
 5714                        show_completion_documentation,
 5715                        position,
 5716                        query.clone(),
 5717                        is_incomplete,
 5718                        buffer.clone(),
 5719                        completions.into(),
 5720                        display_options,
 5721                        snippet_sort_order,
 5722                        languages,
 5723                        language,
 5724                        cx,
 5725                    );
 5726
 5727                    let query = if filter_completions { query } else { None };
 5728                    let matches_task = if let Some(query) = query {
 5729                        menu.do_async_filtering(query, cx)
 5730                    } else {
 5731                        Task::ready(menu.unfiltered_matches())
 5732                    };
 5733                    (menu, matches_task)
 5734                }) else {
 5735                    return;
 5736                };
 5737
 5738                let matches = matches_task.await;
 5739
 5740                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5741                    // Newer menu already set, so exit.
 5742                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5743                        editor.context_menu.borrow().as_ref()
 5744                        && prev_menu.id > id
 5745                    {
 5746                        return;
 5747                    };
 5748
 5749                    // Only valid to take prev_menu because it the new menu is immediately set
 5750                    // below, or the menu is hidden.
 5751                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5752                        editor.context_menu.borrow_mut().take()
 5753                    {
 5754                        let position_matches =
 5755                            if prev_menu.initial_position == menu.initial_position {
 5756                                true
 5757                            } else {
 5758                                let snapshot = editor.buffer.read(cx).read(cx);
 5759                                prev_menu.initial_position.to_offset(&snapshot)
 5760                                    == menu.initial_position.to_offset(&snapshot)
 5761                            };
 5762                        if position_matches {
 5763                            // Preserve markdown cache before `set_filter_results` because it will
 5764                            // try to populate the documentation cache.
 5765                            menu.preserve_markdown_cache(prev_menu);
 5766                        }
 5767                    };
 5768
 5769                    menu.set_filter_results(matches, provider, window, cx);
 5770                }) else {
 5771                    return;
 5772                };
 5773
 5774                menu.visible().then_some(menu)
 5775            };
 5776
 5777            editor
 5778                .update_in(cx, |editor, window, cx| {
 5779                    if editor.focus_handle.is_focused(window)
 5780                        && let Some(menu) = menu
 5781                    {
 5782                        *editor.context_menu.borrow_mut() =
 5783                            Some(CodeContextMenu::Completions(menu));
 5784
 5785                        crate::hover_popover::hide_hover(editor, cx);
 5786                        if editor.show_edit_predictions_in_menu() {
 5787                            editor.update_visible_edit_prediction(window, cx);
 5788                        } else {
 5789                            editor.discard_edit_prediction(false, cx);
 5790                        }
 5791
 5792                        cx.notify();
 5793                        return;
 5794                    }
 5795
 5796                    if editor.completion_tasks.len() <= 1 {
 5797                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5798                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5799                        // If it was already hidden and we don't show edit predictions in the menu,
 5800                        // we should also show the edit prediction when available.
 5801                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5802                            editor.update_visible_edit_prediction(window, cx);
 5803                        }
 5804                    }
 5805                })
 5806                .ok();
 5807        });
 5808
 5809        self.completion_tasks.push((id, task));
 5810    }
 5811
 5812    #[cfg(feature = "test-support")]
 5813    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5814        let menu = self.context_menu.borrow();
 5815        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5816            let completions = menu.completions.borrow();
 5817            Some(completions.to_vec())
 5818        } else {
 5819            None
 5820        }
 5821    }
 5822
 5823    pub fn with_completions_menu_matching_id<R>(
 5824        &self,
 5825        id: CompletionId,
 5826        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5827    ) -> R {
 5828        let mut context_menu = self.context_menu.borrow_mut();
 5829        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5830            return f(None);
 5831        };
 5832        if completions_menu.id != id {
 5833            return f(None);
 5834        }
 5835        f(Some(completions_menu))
 5836    }
 5837
 5838    pub fn confirm_completion(
 5839        &mut self,
 5840        action: &ConfirmCompletion,
 5841        window: &mut Window,
 5842        cx: &mut Context<Self>,
 5843    ) -> Option<Task<Result<()>>> {
 5844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5845        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5846    }
 5847
 5848    pub fn confirm_completion_insert(
 5849        &mut self,
 5850        _: &ConfirmCompletionInsert,
 5851        window: &mut Window,
 5852        cx: &mut Context<Self>,
 5853    ) -> Option<Task<Result<()>>> {
 5854        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5855        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5856    }
 5857
 5858    pub fn confirm_completion_replace(
 5859        &mut self,
 5860        _: &ConfirmCompletionReplace,
 5861        window: &mut Window,
 5862        cx: &mut Context<Self>,
 5863    ) -> Option<Task<Result<()>>> {
 5864        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5865        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5866    }
 5867
 5868    pub fn compose_completion(
 5869        &mut self,
 5870        action: &ComposeCompletion,
 5871        window: &mut Window,
 5872        cx: &mut Context<Self>,
 5873    ) -> Option<Task<Result<()>>> {
 5874        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5875        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5876    }
 5877
 5878    fn do_completion(
 5879        &mut self,
 5880        item_ix: Option<usize>,
 5881        intent: CompletionIntent,
 5882        window: &mut Window,
 5883        cx: &mut Context<Editor>,
 5884    ) -> Option<Task<Result<()>>> {
 5885        use language::ToOffset as _;
 5886
 5887        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5888        else {
 5889            return None;
 5890        };
 5891
 5892        let candidate_id = {
 5893            let entries = completions_menu.entries.borrow();
 5894            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5895            if self.show_edit_predictions_in_menu() {
 5896                self.discard_edit_prediction(true, cx);
 5897            }
 5898            mat.candidate_id
 5899        };
 5900
 5901        let completion = completions_menu
 5902            .completions
 5903            .borrow()
 5904            .get(candidate_id)?
 5905            .clone();
 5906        cx.stop_propagation();
 5907
 5908        let buffer_handle = completions_menu.buffer.clone();
 5909
 5910        let CompletionEdit {
 5911            new_text,
 5912            snippet,
 5913            replace_range,
 5914        } = process_completion_for_edit(
 5915            &completion,
 5916            intent,
 5917            &buffer_handle,
 5918            &completions_menu.initial_position.text_anchor,
 5919            cx,
 5920        );
 5921
 5922        let buffer = buffer_handle.read(cx);
 5923        let snapshot = self.buffer.read(cx).snapshot(cx);
 5924        let newest_anchor = self.selections.newest_anchor();
 5925        let replace_range_multibuffer = {
 5926            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5927            let multibuffer_anchor = snapshot
 5928                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5929                .unwrap()
 5930                ..snapshot
 5931                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5932                    .unwrap();
 5933            multibuffer_anchor.start.to_offset(&snapshot)
 5934                ..multibuffer_anchor.end.to_offset(&snapshot)
 5935        };
 5936        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5937            return None;
 5938        }
 5939
 5940        let old_text = buffer
 5941            .text_for_range(replace_range.clone())
 5942            .collect::<String>();
 5943        let lookbehind = newest_anchor
 5944            .start
 5945            .text_anchor
 5946            .to_offset(buffer)
 5947            .saturating_sub(replace_range.start);
 5948        let lookahead = replace_range
 5949            .end
 5950            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5951        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5952        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5953
 5954        let selections = self.selections.all::<usize>(cx);
 5955        let mut ranges = Vec::new();
 5956        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5957
 5958        for selection in &selections {
 5959            let range = if selection.id == newest_anchor.id {
 5960                replace_range_multibuffer.clone()
 5961            } else {
 5962                let mut range = selection.range();
 5963
 5964                // if prefix is present, don't duplicate it
 5965                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5966                    range.start = range.start.saturating_sub(lookbehind);
 5967
 5968                    // if suffix is also present, mimic the newest cursor and replace it
 5969                    if selection.id != newest_anchor.id
 5970                        && snapshot.contains_str_at(range.end, suffix)
 5971                    {
 5972                        range.end += lookahead;
 5973                    }
 5974                }
 5975                range
 5976            };
 5977
 5978            ranges.push(range.clone());
 5979
 5980            if !self.linked_edit_ranges.is_empty() {
 5981                let start_anchor = snapshot.anchor_before(range.start);
 5982                let end_anchor = snapshot.anchor_after(range.end);
 5983                if let Some(ranges) = self
 5984                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5985                {
 5986                    for (buffer, edits) in ranges {
 5987                        linked_edits
 5988                            .entry(buffer.clone())
 5989                            .or_default()
 5990                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5991                    }
 5992                }
 5993            }
 5994        }
 5995
 5996        let common_prefix_len = old_text
 5997            .chars()
 5998            .zip(new_text.chars())
 5999            .take_while(|(a, b)| a == b)
 6000            .map(|(a, _)| a.len_utf8())
 6001            .sum::<usize>();
 6002
 6003        cx.emit(EditorEvent::InputHandled {
 6004            utf16_range_to_replace: None,
 6005            text: new_text[common_prefix_len..].into(),
 6006        });
 6007
 6008        self.transact(window, cx, |editor, window, cx| {
 6009            if let Some(mut snippet) = snippet {
 6010                snippet.text = new_text.to_string();
 6011                editor
 6012                    .insert_snippet(&ranges, snippet, window, cx)
 6013                    .log_err();
 6014            } else {
 6015                editor.buffer.update(cx, |multi_buffer, cx| {
 6016                    let auto_indent = match completion.insert_text_mode {
 6017                        Some(InsertTextMode::AS_IS) => None,
 6018                        _ => editor.autoindent_mode.clone(),
 6019                    };
 6020                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6021                    multi_buffer.edit(edits, auto_indent, cx);
 6022                });
 6023            }
 6024            for (buffer, edits) in linked_edits {
 6025                buffer.update(cx, |buffer, cx| {
 6026                    let snapshot = buffer.snapshot();
 6027                    let edits = edits
 6028                        .into_iter()
 6029                        .map(|(range, text)| {
 6030                            use text::ToPoint as TP;
 6031                            let end_point = TP::to_point(&range.end, &snapshot);
 6032                            let start_point = TP::to_point(&range.start, &snapshot);
 6033                            (start_point..end_point, text)
 6034                        })
 6035                        .sorted_by_key(|(range, _)| range.start);
 6036                    buffer.edit(edits, None, cx);
 6037                })
 6038            }
 6039
 6040            editor.refresh_edit_prediction(true, false, window, cx);
 6041        });
 6042        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 6043
 6044        let show_new_completions_on_confirm = completion
 6045            .confirm
 6046            .as_ref()
 6047            .is_some_and(|confirm| confirm(intent, window, cx));
 6048        if show_new_completions_on_confirm {
 6049            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6050        }
 6051
 6052        let provider = self.completion_provider.as_ref()?;
 6053        drop(completion);
 6054        let apply_edits = provider.apply_additional_edits_for_completion(
 6055            buffer_handle,
 6056            completions_menu.completions.clone(),
 6057            candidate_id,
 6058            true,
 6059            cx,
 6060        );
 6061
 6062        let editor_settings = EditorSettings::get_global(cx);
 6063        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6064            // After the code completion is finished, users often want to know what signatures are needed.
 6065            // so we should automatically call signature_help
 6066            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6067        }
 6068
 6069        Some(cx.foreground_executor().spawn(async move {
 6070            apply_edits.await?;
 6071            Ok(())
 6072        }))
 6073    }
 6074
 6075    pub fn toggle_code_actions(
 6076        &mut self,
 6077        action: &ToggleCodeActions,
 6078        window: &mut Window,
 6079        cx: &mut Context<Self>,
 6080    ) {
 6081        let quick_launch = action.quick_launch;
 6082        let mut context_menu = self.context_menu.borrow_mut();
 6083        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6084            if code_actions.deployed_from == action.deployed_from {
 6085                // Toggle if we're selecting the same one
 6086                *context_menu = None;
 6087                cx.notify();
 6088                return;
 6089            } else {
 6090                // Otherwise, clear it and start a new one
 6091                *context_menu = None;
 6092                cx.notify();
 6093            }
 6094        }
 6095        drop(context_menu);
 6096        let snapshot = self.snapshot(window, cx);
 6097        let deployed_from = action.deployed_from.clone();
 6098        let action = action.clone();
 6099        self.completion_tasks.clear();
 6100        self.discard_edit_prediction(false, cx);
 6101
 6102        let multibuffer_point = match &action.deployed_from {
 6103            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6104                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6105            }
 6106            _ => self.selections.newest::<Point>(cx).head(),
 6107        };
 6108        let Some((buffer, buffer_row)) = snapshot
 6109            .buffer_snapshot
 6110            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6111            .and_then(|(buffer_snapshot, range)| {
 6112                self.buffer()
 6113                    .read(cx)
 6114                    .buffer(buffer_snapshot.remote_id())
 6115                    .map(|buffer| (buffer, range.start.row))
 6116            })
 6117        else {
 6118            return;
 6119        };
 6120        let buffer_id = buffer.read(cx).remote_id();
 6121        let tasks = self
 6122            .tasks
 6123            .get(&(buffer_id, buffer_row))
 6124            .map(|t| Arc::new(t.to_owned()));
 6125
 6126        if !self.focus_handle.is_focused(window) {
 6127            return;
 6128        }
 6129        let project = self.project.clone();
 6130
 6131        let code_actions_task = match deployed_from {
 6132            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6133            _ => self.code_actions(buffer_row, window, cx),
 6134        };
 6135
 6136        let runnable_task = match deployed_from {
 6137            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6138            _ => {
 6139                let mut task_context_task = Task::ready(None);
 6140                if let Some(tasks) = &tasks
 6141                    && let Some(project) = project
 6142                {
 6143                    task_context_task =
 6144                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6145                }
 6146
 6147                cx.spawn_in(window, {
 6148                    let buffer = buffer.clone();
 6149                    async move |editor, cx| {
 6150                        let task_context = task_context_task.await;
 6151
 6152                        let resolved_tasks =
 6153                            tasks
 6154                                .zip(task_context.clone())
 6155                                .map(|(tasks, task_context)| ResolvedTasks {
 6156                                    templates: tasks.resolve(&task_context).collect(),
 6157                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6158                                        multibuffer_point.row,
 6159                                        tasks.column,
 6160                                    )),
 6161                                });
 6162                        let debug_scenarios = editor
 6163                            .update(cx, |editor, cx| {
 6164                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6165                            })?
 6166                            .await;
 6167                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6168                    }
 6169                })
 6170            }
 6171        };
 6172
 6173        cx.spawn_in(window, async move |editor, cx| {
 6174            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6175            let code_actions = code_actions_task.await;
 6176            let spawn_straight_away = quick_launch
 6177                && resolved_tasks
 6178                    .as_ref()
 6179                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6180                && code_actions
 6181                    .as_ref()
 6182                    .is_none_or(|actions| actions.is_empty())
 6183                && debug_scenarios.is_empty();
 6184
 6185            editor.update_in(cx, |editor, window, cx| {
 6186                crate::hover_popover::hide_hover(editor, cx);
 6187                let actions = CodeActionContents::new(
 6188                    resolved_tasks,
 6189                    code_actions,
 6190                    debug_scenarios,
 6191                    task_context.unwrap_or_default(),
 6192                );
 6193
 6194                // Don't show the menu if there are no actions available
 6195                if actions.is_empty() {
 6196                    cx.notify();
 6197                    return Task::ready(Ok(()));
 6198                }
 6199
 6200                *editor.context_menu.borrow_mut() =
 6201                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6202                        buffer,
 6203                        actions,
 6204                        selected_item: Default::default(),
 6205                        scroll_handle: UniformListScrollHandle::default(),
 6206                        deployed_from,
 6207                    }));
 6208                cx.notify();
 6209                if spawn_straight_away
 6210                    && let Some(task) = editor.confirm_code_action(
 6211                        &ConfirmCodeAction { item_ix: Some(0) },
 6212                        window,
 6213                        cx,
 6214                    )
 6215                {
 6216                    return task;
 6217                }
 6218
 6219                Task::ready(Ok(()))
 6220            })
 6221        })
 6222        .detach_and_log_err(cx);
 6223    }
 6224
 6225    fn debug_scenarios(
 6226        &mut self,
 6227        resolved_tasks: &Option<ResolvedTasks>,
 6228        buffer: &Entity<Buffer>,
 6229        cx: &mut App,
 6230    ) -> Task<Vec<task::DebugScenario>> {
 6231        maybe!({
 6232            let project = self.project()?;
 6233            let dap_store = project.read(cx).dap_store();
 6234            let mut scenarios = vec![];
 6235            let resolved_tasks = resolved_tasks.as_ref()?;
 6236            let buffer = buffer.read(cx);
 6237            let language = buffer.language()?;
 6238            let file = buffer.file();
 6239            let debug_adapter = language_settings(language.name().into(), file, cx)
 6240                .debuggers
 6241                .first()
 6242                .map(SharedString::from)
 6243                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6244
 6245            dap_store.update(cx, |dap_store, cx| {
 6246                for (_, task) in &resolved_tasks.templates {
 6247                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6248                        task.original_task().clone(),
 6249                        debug_adapter.clone().into(),
 6250                        task.display_label().to_owned().into(),
 6251                        cx,
 6252                    );
 6253                    scenarios.push(maybe_scenario);
 6254                }
 6255            });
 6256            Some(cx.background_spawn(async move {
 6257                futures::future::join_all(scenarios)
 6258                    .await
 6259                    .into_iter()
 6260                    .flatten()
 6261                    .collect::<Vec<_>>()
 6262            }))
 6263        })
 6264        .unwrap_or_else(|| Task::ready(vec![]))
 6265    }
 6266
 6267    fn code_actions(
 6268        &mut self,
 6269        buffer_row: u32,
 6270        window: &mut Window,
 6271        cx: &mut Context<Self>,
 6272    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6273        let mut task = self.code_actions_task.take();
 6274        cx.spawn_in(window, async move |editor, cx| {
 6275            while let Some(prev_task) = task {
 6276                prev_task.await.log_err();
 6277                task = editor
 6278                    .update(cx, |this, _| this.code_actions_task.take())
 6279                    .ok()?;
 6280            }
 6281
 6282            editor
 6283                .update(cx, |editor, cx| {
 6284                    editor
 6285                        .available_code_actions
 6286                        .clone()
 6287                        .and_then(|(location, code_actions)| {
 6288                            let snapshot = location.buffer.read(cx).snapshot();
 6289                            let point_range = location.range.to_point(&snapshot);
 6290                            let point_range = point_range.start.row..=point_range.end.row;
 6291                            if point_range.contains(&buffer_row) {
 6292                                Some(code_actions)
 6293                            } else {
 6294                                None
 6295                            }
 6296                        })
 6297                })
 6298                .ok()
 6299                .flatten()
 6300        })
 6301    }
 6302
 6303    pub fn confirm_code_action(
 6304        &mut self,
 6305        action: &ConfirmCodeAction,
 6306        window: &mut Window,
 6307        cx: &mut Context<Self>,
 6308    ) -> Option<Task<Result<()>>> {
 6309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6310
 6311        let actions_menu =
 6312            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6313                menu
 6314            } else {
 6315                return None;
 6316            };
 6317
 6318        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6319        let action = actions_menu.actions.get(action_ix)?;
 6320        let title = action.label();
 6321        let buffer = actions_menu.buffer;
 6322        let workspace = self.workspace()?;
 6323
 6324        match action {
 6325            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6326                workspace.update(cx, |workspace, cx| {
 6327                    workspace.schedule_resolved_task(
 6328                        task_source_kind,
 6329                        resolved_task,
 6330                        false,
 6331                        window,
 6332                        cx,
 6333                    );
 6334
 6335                    Some(Task::ready(Ok(())))
 6336                })
 6337            }
 6338            CodeActionsItem::CodeAction {
 6339                excerpt_id,
 6340                action,
 6341                provider,
 6342            } => {
 6343                let apply_code_action =
 6344                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6345                let workspace = workspace.downgrade();
 6346                Some(cx.spawn_in(window, async move |editor, cx| {
 6347                    let project_transaction = apply_code_action.await?;
 6348                    Self::open_project_transaction(
 6349                        &editor,
 6350                        workspace,
 6351                        project_transaction,
 6352                        title,
 6353                        cx,
 6354                    )
 6355                    .await
 6356                }))
 6357            }
 6358            CodeActionsItem::DebugScenario(scenario) => {
 6359                let context = actions_menu.actions.context;
 6360
 6361                workspace.update(cx, |workspace, cx| {
 6362                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6363                    workspace.start_debug_session(
 6364                        scenario,
 6365                        context,
 6366                        Some(buffer),
 6367                        None,
 6368                        window,
 6369                        cx,
 6370                    );
 6371                });
 6372                Some(Task::ready(Ok(())))
 6373            }
 6374        }
 6375    }
 6376
 6377    pub async fn open_project_transaction(
 6378        editor: &WeakEntity<Editor>,
 6379        workspace: WeakEntity<Workspace>,
 6380        transaction: ProjectTransaction,
 6381        title: String,
 6382        cx: &mut AsyncWindowContext,
 6383    ) -> Result<()> {
 6384        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6385        cx.update(|_, cx| {
 6386            entries.sort_unstable_by_key(|(buffer, _)| {
 6387                buffer.read(cx).file().map(|f| f.path().clone())
 6388            });
 6389        })?;
 6390
 6391        // If the project transaction's edits are all contained within this editor, then
 6392        // avoid opening a new editor to display them.
 6393
 6394        if let Some((buffer, transaction)) = entries.first() {
 6395            if entries.len() == 1 {
 6396                let excerpt = editor.update(cx, |editor, cx| {
 6397                    editor
 6398                        .buffer()
 6399                        .read(cx)
 6400                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6401                })?;
 6402                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6403                    && excerpted_buffer == *buffer
 6404                {
 6405                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6406                        let excerpt_range = excerpt_range.to_offset(buffer);
 6407                        buffer
 6408                            .edited_ranges_for_transaction::<usize>(transaction)
 6409                            .all(|range| {
 6410                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6411                            })
 6412                    })?;
 6413
 6414                    if all_edits_within_excerpt {
 6415                        return Ok(());
 6416                    }
 6417                }
 6418            }
 6419        } else {
 6420            return Ok(());
 6421        }
 6422
 6423        let mut ranges_to_highlight = Vec::new();
 6424        let excerpt_buffer = cx.new(|cx| {
 6425            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6426            for (buffer_handle, transaction) in &entries {
 6427                let edited_ranges = buffer_handle
 6428                    .read(cx)
 6429                    .edited_ranges_for_transaction::<Point>(transaction)
 6430                    .collect::<Vec<_>>();
 6431                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6432                    PathKey::for_buffer(buffer_handle, cx),
 6433                    buffer_handle.clone(),
 6434                    edited_ranges,
 6435                    multibuffer_context_lines(cx),
 6436                    cx,
 6437                );
 6438
 6439                ranges_to_highlight.extend(ranges);
 6440            }
 6441            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6442            multibuffer
 6443        })?;
 6444
 6445        workspace.update_in(cx, |workspace, window, cx| {
 6446            let project = workspace.project().clone();
 6447            let editor =
 6448                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6449            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6450            editor.update(cx, |editor, cx| {
 6451                editor.highlight_background::<Self>(
 6452                    &ranges_to_highlight,
 6453                    |theme| theme.colors().editor_highlighted_line_background,
 6454                    cx,
 6455                );
 6456            });
 6457        })?;
 6458
 6459        Ok(())
 6460    }
 6461
 6462    pub fn clear_code_action_providers(&mut self) {
 6463        self.code_action_providers.clear();
 6464        self.available_code_actions.take();
 6465    }
 6466
 6467    pub fn add_code_action_provider(
 6468        &mut self,
 6469        provider: Rc<dyn CodeActionProvider>,
 6470        window: &mut Window,
 6471        cx: &mut Context<Self>,
 6472    ) {
 6473        if self
 6474            .code_action_providers
 6475            .iter()
 6476            .any(|existing_provider| existing_provider.id() == provider.id())
 6477        {
 6478            return;
 6479        }
 6480
 6481        self.code_action_providers.push(provider);
 6482        self.refresh_code_actions(window, cx);
 6483    }
 6484
 6485    pub fn remove_code_action_provider(
 6486        &mut self,
 6487        id: Arc<str>,
 6488        window: &mut Window,
 6489        cx: &mut Context<Self>,
 6490    ) {
 6491        self.code_action_providers
 6492            .retain(|provider| provider.id() != id);
 6493        self.refresh_code_actions(window, cx);
 6494    }
 6495
 6496    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6497        !self.code_action_providers.is_empty()
 6498            && EditorSettings::get_global(cx).toolbar.code_actions
 6499    }
 6500
 6501    pub fn has_available_code_actions(&self) -> bool {
 6502        self.available_code_actions
 6503            .as_ref()
 6504            .is_some_and(|(_, actions)| !actions.is_empty())
 6505    }
 6506
 6507    fn render_inline_code_actions(
 6508        &self,
 6509        icon_size: ui::IconSize,
 6510        display_row: DisplayRow,
 6511        is_active: bool,
 6512        cx: &mut Context<Self>,
 6513    ) -> AnyElement {
 6514        let show_tooltip = !self.context_menu_visible();
 6515        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6516            .icon_size(icon_size)
 6517            .shape(ui::IconButtonShape::Square)
 6518            .icon_color(ui::Color::Hidden)
 6519            .toggle_state(is_active)
 6520            .when(show_tooltip, |this| {
 6521                this.tooltip({
 6522                    let focus_handle = self.focus_handle.clone();
 6523                    move |window, cx| {
 6524                        Tooltip::for_action_in(
 6525                            "Toggle Code Actions",
 6526                            &ToggleCodeActions {
 6527                                deployed_from: None,
 6528                                quick_launch: false,
 6529                            },
 6530                            &focus_handle,
 6531                            window,
 6532                            cx,
 6533                        )
 6534                    }
 6535                })
 6536            })
 6537            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6538                window.focus(&editor.focus_handle(cx));
 6539                editor.toggle_code_actions(
 6540                    &crate::actions::ToggleCodeActions {
 6541                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6542                            display_row,
 6543                        )),
 6544                        quick_launch: false,
 6545                    },
 6546                    window,
 6547                    cx,
 6548                );
 6549            }))
 6550            .into_any_element()
 6551    }
 6552
 6553    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6554        &self.context_menu
 6555    }
 6556
 6557    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6558        let newest_selection = self.selections.newest_anchor().clone();
 6559        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6560        let buffer = self.buffer.read(cx);
 6561        if newest_selection.head().diff_base_anchor.is_some() {
 6562            return None;
 6563        }
 6564        let (start_buffer, start) =
 6565            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6566        let (end_buffer, end) =
 6567            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6568        if start_buffer != end_buffer {
 6569            return None;
 6570        }
 6571
 6572        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6573            cx.background_executor()
 6574                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6575                .await;
 6576
 6577            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6578                let providers = this.code_action_providers.clone();
 6579                let tasks = this
 6580                    .code_action_providers
 6581                    .iter()
 6582                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6583                    .collect::<Vec<_>>();
 6584                (providers, tasks)
 6585            })?;
 6586
 6587            let mut actions = Vec::new();
 6588            for (provider, provider_actions) in
 6589                providers.into_iter().zip(future::join_all(tasks).await)
 6590            {
 6591                if let Some(provider_actions) = provider_actions.log_err() {
 6592                    actions.extend(provider_actions.into_iter().map(|action| {
 6593                        AvailableCodeAction {
 6594                            excerpt_id: newest_selection.start.excerpt_id,
 6595                            action,
 6596                            provider: provider.clone(),
 6597                        }
 6598                    }));
 6599                }
 6600            }
 6601
 6602            this.update(cx, |this, cx| {
 6603                this.available_code_actions = if actions.is_empty() {
 6604                    None
 6605                } else {
 6606                    Some((
 6607                        Location {
 6608                            buffer: start_buffer,
 6609                            range: start..end,
 6610                        },
 6611                        actions.into(),
 6612                    ))
 6613                };
 6614                cx.notify();
 6615            })
 6616        }));
 6617        None
 6618    }
 6619
 6620    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6621        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6622            self.show_git_blame_inline = false;
 6623
 6624            self.show_git_blame_inline_delay_task =
 6625                Some(cx.spawn_in(window, async move |this, cx| {
 6626                    cx.background_executor().timer(delay).await;
 6627
 6628                    this.update(cx, |this, cx| {
 6629                        this.show_git_blame_inline = true;
 6630                        cx.notify();
 6631                    })
 6632                    .log_err();
 6633                }));
 6634        }
 6635    }
 6636
 6637    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6638        let snapshot = self.snapshot(window, cx);
 6639        let cursor = self.selections.newest::<Point>(cx).head();
 6640        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6641        else {
 6642            return;
 6643        };
 6644
 6645        let Some(blame) = self.blame.as_ref() else {
 6646            return;
 6647        };
 6648
 6649        let row_info = RowInfo {
 6650            buffer_id: Some(buffer.remote_id()),
 6651            buffer_row: Some(point.row),
 6652            ..Default::default()
 6653        };
 6654        let Some((buffer, blame_entry)) = blame
 6655            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6656            .flatten()
 6657        else {
 6658            return;
 6659        };
 6660
 6661        let anchor = self.selections.newest_anchor().head();
 6662        let position = self.to_pixel_point(anchor, &snapshot, window);
 6663        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6664            self.show_blame_popover(
 6665                buffer,
 6666                &blame_entry,
 6667                position + last_bounds.origin,
 6668                true,
 6669                cx,
 6670            );
 6671        };
 6672    }
 6673
 6674    fn show_blame_popover(
 6675        &mut self,
 6676        buffer: BufferId,
 6677        blame_entry: &BlameEntry,
 6678        position: gpui::Point<Pixels>,
 6679        ignore_timeout: bool,
 6680        cx: &mut Context<Self>,
 6681    ) {
 6682        if let Some(state) = &mut self.inline_blame_popover {
 6683            state.hide_task.take();
 6684        } else {
 6685            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6686            let blame_entry = blame_entry.clone();
 6687            let show_task = cx.spawn(async move |editor, cx| {
 6688                if !ignore_timeout {
 6689                    cx.background_executor()
 6690                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6691                        .await;
 6692                }
 6693                editor
 6694                    .update(cx, |editor, cx| {
 6695                        editor.inline_blame_popover_show_task.take();
 6696                        let Some(blame) = editor.blame.as_ref() else {
 6697                            return;
 6698                        };
 6699                        let blame = blame.read(cx);
 6700                        let details = blame.details_for_entry(buffer, &blame_entry);
 6701                        let markdown = cx.new(|cx| {
 6702                            Markdown::new(
 6703                                details
 6704                                    .as_ref()
 6705                                    .map(|message| message.message.clone())
 6706                                    .unwrap_or_default(),
 6707                                None,
 6708                                None,
 6709                                cx,
 6710                            )
 6711                        });
 6712                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6713                            position,
 6714                            hide_task: None,
 6715                            popover_bounds: None,
 6716                            popover_state: InlineBlamePopoverState {
 6717                                scroll_handle: ScrollHandle::new(),
 6718                                commit_message: details,
 6719                                markdown,
 6720                            },
 6721                            keyboard_grace: ignore_timeout,
 6722                        });
 6723                        cx.notify();
 6724                    })
 6725                    .ok();
 6726            });
 6727            self.inline_blame_popover_show_task = Some(show_task);
 6728        }
 6729    }
 6730
 6731    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6732        self.inline_blame_popover_show_task.take();
 6733        if let Some(state) = &mut self.inline_blame_popover {
 6734            let hide_task = cx.spawn(async move |editor, cx| {
 6735                cx.background_executor()
 6736                    .timer(std::time::Duration::from_millis(100))
 6737                    .await;
 6738                editor
 6739                    .update(cx, |editor, cx| {
 6740                        editor.inline_blame_popover.take();
 6741                        cx.notify();
 6742                    })
 6743                    .ok();
 6744            });
 6745            state.hide_task = Some(hide_task);
 6746        }
 6747    }
 6748
 6749    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6750        if self.pending_rename.is_some() {
 6751            return None;
 6752        }
 6753
 6754        let provider = self.semantics_provider.clone()?;
 6755        let buffer = self.buffer.read(cx);
 6756        let newest_selection = self.selections.newest_anchor().clone();
 6757        let cursor_position = newest_selection.head();
 6758        let (cursor_buffer, cursor_buffer_position) =
 6759            buffer.text_anchor_for_position(cursor_position, cx)?;
 6760        let (tail_buffer, tail_buffer_position) =
 6761            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6762        if cursor_buffer != tail_buffer {
 6763            return None;
 6764        }
 6765
 6766        let snapshot = cursor_buffer.read(cx).snapshot();
 6767        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6768        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6769        if start_word_range != end_word_range {
 6770            self.document_highlights_task.take();
 6771            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6772            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6773            return None;
 6774        }
 6775
 6776        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6777        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6778            cx.background_executor()
 6779                .timer(Duration::from_millis(debounce))
 6780                .await;
 6781
 6782            let highlights = if let Some(highlights) = cx
 6783                .update(|cx| {
 6784                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6785                })
 6786                .ok()
 6787                .flatten()
 6788            {
 6789                highlights.await.log_err()
 6790            } else {
 6791                None
 6792            };
 6793
 6794            if let Some(highlights) = highlights {
 6795                this.update(cx, |this, cx| {
 6796                    if this.pending_rename.is_some() {
 6797                        return;
 6798                    }
 6799
 6800                    let buffer = this.buffer.read(cx);
 6801                    if buffer
 6802                        .text_anchor_for_position(cursor_position, cx)
 6803                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6804                    {
 6805                        return;
 6806                    }
 6807
 6808                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6809                    let mut write_ranges = Vec::new();
 6810                    let mut read_ranges = Vec::new();
 6811                    for highlight in highlights {
 6812                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6813                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6814                        {
 6815                            let start = highlight
 6816                                .range
 6817                                .start
 6818                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6819                            let end = highlight
 6820                                .range
 6821                                .end
 6822                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6823                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6824                                continue;
 6825                            }
 6826
 6827                            let range = Anchor {
 6828                                buffer_id: Some(buffer_id),
 6829                                excerpt_id,
 6830                                text_anchor: start,
 6831                                diff_base_anchor: None,
 6832                            }..Anchor {
 6833                                buffer_id: Some(buffer_id),
 6834                                excerpt_id,
 6835                                text_anchor: end,
 6836                                diff_base_anchor: None,
 6837                            };
 6838                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6839                                write_ranges.push(range);
 6840                            } else {
 6841                                read_ranges.push(range);
 6842                            }
 6843                        }
 6844                    }
 6845
 6846                    this.highlight_background::<DocumentHighlightRead>(
 6847                        &read_ranges,
 6848                        |theme| theme.colors().editor_document_highlight_read_background,
 6849                        cx,
 6850                    );
 6851                    this.highlight_background::<DocumentHighlightWrite>(
 6852                        &write_ranges,
 6853                        |theme| theme.colors().editor_document_highlight_write_background,
 6854                        cx,
 6855                    );
 6856                    cx.notify();
 6857                })
 6858                .log_err();
 6859            }
 6860        }));
 6861        None
 6862    }
 6863
 6864    fn prepare_highlight_query_from_selection(
 6865        &mut self,
 6866        cx: &mut Context<Editor>,
 6867    ) -> Option<(String, Range<Anchor>)> {
 6868        if matches!(self.mode, EditorMode::SingleLine) {
 6869            return None;
 6870        }
 6871        if !EditorSettings::get_global(cx).selection_highlight {
 6872            return None;
 6873        }
 6874        if self.selections.count() != 1 || self.selections.line_mode {
 6875            return None;
 6876        }
 6877        let selection = self.selections.newest::<Point>(cx);
 6878        if selection.is_empty() || selection.start.row != selection.end.row {
 6879            return None;
 6880        }
 6881        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6882        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6883        let query = multi_buffer_snapshot
 6884            .text_for_range(selection_anchor_range.clone())
 6885            .collect::<String>();
 6886        if query.trim().is_empty() {
 6887            return None;
 6888        }
 6889        Some((query, selection_anchor_range))
 6890    }
 6891
 6892    fn update_selection_occurrence_highlights(
 6893        &mut self,
 6894        query_text: String,
 6895        query_range: Range<Anchor>,
 6896        multi_buffer_range_to_query: Range<Point>,
 6897        use_debounce: bool,
 6898        window: &mut Window,
 6899        cx: &mut Context<Editor>,
 6900    ) -> Task<()> {
 6901        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6902        cx.spawn_in(window, async move |editor, cx| {
 6903            if use_debounce {
 6904                cx.background_executor()
 6905                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6906                    .await;
 6907            }
 6908            let match_task = cx.background_spawn(async move {
 6909                let buffer_ranges = multi_buffer_snapshot
 6910                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6911                    .into_iter()
 6912                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6913                let mut match_ranges = Vec::new();
 6914                let Ok(regex) = project::search::SearchQuery::text(
 6915                    query_text.clone(),
 6916                    false,
 6917                    false,
 6918                    false,
 6919                    Default::default(),
 6920                    Default::default(),
 6921                    false,
 6922                    None,
 6923                ) else {
 6924                    return Vec::default();
 6925                };
 6926                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6927                    match_ranges.extend(
 6928                        regex
 6929                            .search(buffer_snapshot, Some(search_range.clone()))
 6930                            .await
 6931                            .into_iter()
 6932                            .filter_map(|match_range| {
 6933                                let match_start = buffer_snapshot
 6934                                    .anchor_after(search_range.start + match_range.start);
 6935                                let match_end = buffer_snapshot
 6936                                    .anchor_before(search_range.start + match_range.end);
 6937                                let match_anchor_range = Anchor::range_in_buffer(
 6938                                    excerpt_id,
 6939                                    buffer_snapshot.remote_id(),
 6940                                    match_start..match_end,
 6941                                );
 6942                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6943                            }),
 6944                    );
 6945                }
 6946                match_ranges
 6947            });
 6948            let match_ranges = match_task.await;
 6949            editor
 6950                .update_in(cx, |editor, _, cx| {
 6951                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6952                    if !match_ranges.is_empty() {
 6953                        editor.highlight_background::<SelectedTextHighlight>(
 6954                            &match_ranges,
 6955                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6956                            cx,
 6957                        )
 6958                    }
 6959                })
 6960                .log_err();
 6961        })
 6962    }
 6963
 6964    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6965        struct NewlineFold;
 6966        let type_id = std::any::TypeId::of::<NewlineFold>();
 6967        if !self.mode.is_single_line() {
 6968            return;
 6969        }
 6970        let snapshot = self.snapshot(window, cx);
 6971        if snapshot.buffer_snapshot.max_point().row == 0 {
 6972            return;
 6973        }
 6974        let task = cx.background_spawn(async move {
 6975            let new_newlines = snapshot
 6976                .buffer_chars_at(0)
 6977                .filter_map(|(c, i)| {
 6978                    if c == '\n' {
 6979                        Some(
 6980                            snapshot.buffer_snapshot.anchor_after(i)
 6981                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6982                        )
 6983                    } else {
 6984                        None
 6985                    }
 6986                })
 6987                .collect::<Vec<_>>();
 6988            let existing_newlines = snapshot
 6989                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6990                .filter_map(|fold| {
 6991                    if fold.placeholder.type_tag == Some(type_id) {
 6992                        Some(fold.range.start..fold.range.end)
 6993                    } else {
 6994                        None
 6995                    }
 6996                })
 6997                .collect::<Vec<_>>();
 6998
 6999            (new_newlines, existing_newlines)
 7000        });
 7001        self.folding_newlines = cx.spawn(async move |this, cx| {
 7002            let (new_newlines, existing_newlines) = task.await;
 7003            if new_newlines == existing_newlines {
 7004                return;
 7005            }
 7006            let placeholder = FoldPlaceholder {
 7007                render: Arc::new(move |_, _, cx| {
 7008                    div()
 7009                        .bg(cx.theme().status().hint_background)
 7010                        .border_b_1()
 7011                        .size_full()
 7012                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7013                        .border_color(cx.theme().status().hint)
 7014                        .child("\\n")
 7015                        .into_any()
 7016                }),
 7017                constrain_width: false,
 7018                merge_adjacent: false,
 7019                type_tag: Some(type_id),
 7020            };
 7021            let creases = new_newlines
 7022                .into_iter()
 7023                .map(|range| Crease::simple(range, placeholder.clone()))
 7024                .collect();
 7025            this.update(cx, |this, cx| {
 7026                this.display_map.update(cx, |display_map, cx| {
 7027                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7028                    display_map.fold(creases, cx);
 7029                });
 7030            })
 7031            .ok();
 7032        });
 7033    }
 7034
 7035    fn refresh_selected_text_highlights(
 7036        &mut self,
 7037        on_buffer_edit: bool,
 7038        window: &mut Window,
 7039        cx: &mut Context<Editor>,
 7040    ) {
 7041        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7042        else {
 7043            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7044            self.quick_selection_highlight_task.take();
 7045            self.debounced_selection_highlight_task.take();
 7046            return;
 7047        };
 7048        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7049        if on_buffer_edit
 7050            || self
 7051                .quick_selection_highlight_task
 7052                .as_ref()
 7053                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7054        {
 7055            let multi_buffer_visible_start = self
 7056                .scroll_manager
 7057                .anchor()
 7058                .anchor
 7059                .to_point(&multi_buffer_snapshot);
 7060            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7061                multi_buffer_visible_start
 7062                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7063                Bias::Left,
 7064            );
 7065            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7066            self.quick_selection_highlight_task = Some((
 7067                query_range.clone(),
 7068                self.update_selection_occurrence_highlights(
 7069                    query_text.clone(),
 7070                    query_range.clone(),
 7071                    multi_buffer_visible_range,
 7072                    false,
 7073                    window,
 7074                    cx,
 7075                ),
 7076            ));
 7077        }
 7078        if on_buffer_edit
 7079            || self
 7080                .debounced_selection_highlight_task
 7081                .as_ref()
 7082                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7083        {
 7084            let multi_buffer_start = multi_buffer_snapshot
 7085                .anchor_before(0)
 7086                .to_point(&multi_buffer_snapshot);
 7087            let multi_buffer_end = multi_buffer_snapshot
 7088                .anchor_after(multi_buffer_snapshot.len())
 7089                .to_point(&multi_buffer_snapshot);
 7090            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7091            self.debounced_selection_highlight_task = Some((
 7092                query_range.clone(),
 7093                self.update_selection_occurrence_highlights(
 7094                    query_text,
 7095                    query_range,
 7096                    multi_buffer_full_range,
 7097                    true,
 7098                    window,
 7099                    cx,
 7100                ),
 7101            ));
 7102        }
 7103    }
 7104
 7105    pub fn refresh_edit_prediction(
 7106        &mut self,
 7107        debounce: bool,
 7108        user_requested: bool,
 7109        window: &mut Window,
 7110        cx: &mut Context<Self>,
 7111    ) -> Option<()> {
 7112        if DisableAiSettings::get_global(cx).disable_ai {
 7113            return None;
 7114        }
 7115
 7116        let provider = self.edit_prediction_provider()?;
 7117        let cursor = self.selections.newest_anchor().head();
 7118        let (buffer, cursor_buffer_position) =
 7119            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7120
 7121        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7122            self.discard_edit_prediction(false, cx);
 7123            return None;
 7124        }
 7125
 7126        if !user_requested
 7127            && (!self.should_show_edit_predictions()
 7128                || !self.is_focused(window)
 7129                || buffer.read(cx).is_empty())
 7130        {
 7131            self.discard_edit_prediction(false, cx);
 7132            return None;
 7133        }
 7134
 7135        self.update_visible_edit_prediction(window, cx);
 7136        provider.refresh(
 7137            self.project.clone(),
 7138            buffer,
 7139            cursor_buffer_position,
 7140            debounce,
 7141            cx,
 7142        );
 7143        Some(())
 7144    }
 7145
 7146    fn show_edit_predictions_in_menu(&self) -> bool {
 7147        match self.edit_prediction_settings {
 7148            EditPredictionSettings::Disabled => false,
 7149            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7150        }
 7151    }
 7152
 7153    pub fn edit_predictions_enabled(&self) -> bool {
 7154        match self.edit_prediction_settings {
 7155            EditPredictionSettings::Disabled => false,
 7156            EditPredictionSettings::Enabled { .. } => true,
 7157        }
 7158    }
 7159
 7160    fn edit_prediction_requires_modifier(&self) -> bool {
 7161        match self.edit_prediction_settings {
 7162            EditPredictionSettings::Disabled => false,
 7163            EditPredictionSettings::Enabled {
 7164                preview_requires_modifier,
 7165                ..
 7166            } => preview_requires_modifier,
 7167        }
 7168    }
 7169
 7170    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7171        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7172            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7173            self.discard_edit_prediction(false, cx);
 7174        } else {
 7175            let selection = self.selections.newest_anchor();
 7176            let cursor = selection.head();
 7177
 7178            if let Some((buffer, cursor_buffer_position)) =
 7179                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7180            {
 7181                self.edit_prediction_settings =
 7182                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7183            }
 7184        }
 7185    }
 7186
 7187    fn edit_prediction_settings_at_position(
 7188        &self,
 7189        buffer: &Entity<Buffer>,
 7190        buffer_position: language::Anchor,
 7191        cx: &App,
 7192    ) -> EditPredictionSettings {
 7193        if !self.mode.is_full()
 7194            || !self.show_edit_predictions_override.unwrap_or(true)
 7195            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7196        {
 7197            return EditPredictionSettings::Disabled;
 7198        }
 7199
 7200        let buffer = buffer.read(cx);
 7201
 7202        let file = buffer.file();
 7203
 7204        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7205            return EditPredictionSettings::Disabled;
 7206        };
 7207
 7208        let by_provider = matches!(
 7209            self.menu_edit_predictions_policy,
 7210            MenuEditPredictionsPolicy::ByProvider
 7211        );
 7212
 7213        let show_in_menu = by_provider
 7214            && self
 7215                .edit_prediction_provider
 7216                .as_ref()
 7217                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7218
 7219        let preview_requires_modifier =
 7220            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7221
 7222        EditPredictionSettings::Enabled {
 7223            show_in_menu,
 7224            preview_requires_modifier,
 7225        }
 7226    }
 7227
 7228    fn should_show_edit_predictions(&self) -> bool {
 7229        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7230    }
 7231
 7232    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7233        matches!(
 7234            self.edit_prediction_preview,
 7235            EditPredictionPreview::Active { .. }
 7236        )
 7237    }
 7238
 7239    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7240        let cursor = self.selections.newest_anchor().head();
 7241        if let Some((buffer, cursor_position)) =
 7242            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7243        {
 7244            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7245        } else {
 7246            false
 7247        }
 7248    }
 7249
 7250    pub fn supports_minimap(&self, cx: &App) -> bool {
 7251        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7252    }
 7253
 7254    fn edit_predictions_enabled_in_buffer(
 7255        &self,
 7256        buffer: &Entity<Buffer>,
 7257        buffer_position: language::Anchor,
 7258        cx: &App,
 7259    ) -> bool {
 7260        maybe!({
 7261            if self.read_only(cx) {
 7262                return Some(false);
 7263            }
 7264            let provider = self.edit_prediction_provider()?;
 7265            if !provider.is_enabled(buffer, buffer_position, cx) {
 7266                return Some(false);
 7267            }
 7268            let buffer = buffer.read(cx);
 7269            let Some(file) = buffer.file() else {
 7270                return Some(true);
 7271            };
 7272            let settings = all_language_settings(Some(file), cx);
 7273            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7274        })
 7275        .unwrap_or(false)
 7276    }
 7277
 7278    fn cycle_edit_prediction(
 7279        &mut self,
 7280        direction: Direction,
 7281        window: &mut Window,
 7282        cx: &mut Context<Self>,
 7283    ) -> Option<()> {
 7284        let provider = self.edit_prediction_provider()?;
 7285        let cursor = self.selections.newest_anchor().head();
 7286        let (buffer, cursor_buffer_position) =
 7287            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7288        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7289            return None;
 7290        }
 7291
 7292        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7293        self.update_visible_edit_prediction(window, cx);
 7294
 7295        Some(())
 7296    }
 7297
 7298    pub fn show_edit_prediction(
 7299        &mut self,
 7300        _: &ShowEditPrediction,
 7301        window: &mut Window,
 7302        cx: &mut Context<Self>,
 7303    ) {
 7304        if !self.has_active_edit_prediction() {
 7305            self.refresh_edit_prediction(false, true, window, cx);
 7306            return;
 7307        }
 7308
 7309        self.update_visible_edit_prediction(window, cx);
 7310    }
 7311
 7312    pub fn display_cursor_names(
 7313        &mut self,
 7314        _: &DisplayCursorNames,
 7315        window: &mut Window,
 7316        cx: &mut Context<Self>,
 7317    ) {
 7318        self.show_cursor_names(window, cx);
 7319    }
 7320
 7321    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7322        self.show_cursor_names = true;
 7323        cx.notify();
 7324        cx.spawn_in(window, async move |this, cx| {
 7325            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7326            this.update(cx, |this, cx| {
 7327                this.show_cursor_names = false;
 7328                cx.notify()
 7329            })
 7330            .ok()
 7331        })
 7332        .detach();
 7333    }
 7334
 7335    pub fn next_edit_prediction(
 7336        &mut self,
 7337        _: &NextEditPrediction,
 7338        window: &mut Window,
 7339        cx: &mut Context<Self>,
 7340    ) {
 7341        if self.has_active_edit_prediction() {
 7342            self.cycle_edit_prediction(Direction::Next, window, cx);
 7343        } else {
 7344            let is_copilot_disabled = self
 7345                .refresh_edit_prediction(false, true, window, cx)
 7346                .is_none();
 7347            if is_copilot_disabled {
 7348                cx.propagate();
 7349            }
 7350        }
 7351    }
 7352
 7353    pub fn previous_edit_prediction(
 7354        &mut self,
 7355        _: &PreviousEditPrediction,
 7356        window: &mut Window,
 7357        cx: &mut Context<Self>,
 7358    ) {
 7359        if self.has_active_edit_prediction() {
 7360            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7361        } else {
 7362            let is_copilot_disabled = self
 7363                .refresh_edit_prediction(false, true, window, cx)
 7364                .is_none();
 7365            if is_copilot_disabled {
 7366                cx.propagate();
 7367            }
 7368        }
 7369    }
 7370
 7371    pub fn accept_edit_prediction(
 7372        &mut self,
 7373        _: &AcceptEditPrediction,
 7374        window: &mut Window,
 7375        cx: &mut Context<Self>,
 7376    ) {
 7377        if self.show_edit_predictions_in_menu() {
 7378            self.hide_context_menu(window, cx);
 7379        }
 7380
 7381        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7382            return;
 7383        };
 7384
 7385        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7386
 7387        match &active_edit_prediction.completion {
 7388            EditPrediction::Move { target, .. } => {
 7389                let target = *target;
 7390
 7391                if let Some(position_map) = &self.last_position_map {
 7392                    if position_map
 7393                        .visible_row_range
 7394                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7395                        || !self.edit_prediction_requires_modifier()
 7396                    {
 7397                        self.unfold_ranges(&[target..target], true, false, cx);
 7398                        // Note that this is also done in vim's handler of the Tab action.
 7399                        self.change_selections(
 7400                            SelectionEffects::scroll(Autoscroll::newest()),
 7401                            window,
 7402                            cx,
 7403                            |selections| {
 7404                                selections.select_anchor_ranges([target..target]);
 7405                            },
 7406                        );
 7407                        self.clear_row_highlights::<EditPredictionPreview>();
 7408
 7409                        self.edit_prediction_preview
 7410                            .set_previous_scroll_position(None);
 7411                    } else {
 7412                        self.edit_prediction_preview
 7413                            .set_previous_scroll_position(Some(
 7414                                position_map.snapshot.scroll_anchor,
 7415                            ));
 7416
 7417                        self.highlight_rows::<EditPredictionPreview>(
 7418                            target..target,
 7419                            cx.theme().colors().editor_highlighted_line_background,
 7420                            RowHighlightOptions {
 7421                                autoscroll: true,
 7422                                ..Default::default()
 7423                            },
 7424                            cx,
 7425                        );
 7426                        self.request_autoscroll(Autoscroll::fit(), cx);
 7427                    }
 7428                }
 7429            }
 7430            EditPrediction::Edit { edits, .. } => {
 7431                if let Some(provider) = self.edit_prediction_provider() {
 7432                    provider.accept(cx);
 7433                }
 7434
 7435                // Store the transaction ID and selections before applying the edit
 7436                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7437
 7438                let snapshot = self.buffer.read(cx).snapshot(cx);
 7439                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7440
 7441                self.buffer.update(cx, |buffer, cx| {
 7442                    buffer.edit(edits.iter().cloned(), None, cx)
 7443                });
 7444
 7445                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7446                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7447                });
 7448
 7449                let selections = self.selections.disjoint_anchors();
 7450                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7451                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7452                    if has_new_transaction {
 7453                        self.selection_history
 7454                            .insert_transaction(transaction_id_now, selections);
 7455                    }
 7456                }
 7457
 7458                self.update_visible_edit_prediction(window, cx);
 7459                if self.active_edit_prediction.is_none() {
 7460                    self.refresh_edit_prediction(true, true, window, cx);
 7461                }
 7462
 7463                cx.notify();
 7464            }
 7465        }
 7466
 7467        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7468    }
 7469
 7470    pub fn accept_partial_edit_prediction(
 7471        &mut self,
 7472        _: &AcceptPartialEditPrediction,
 7473        window: &mut Window,
 7474        cx: &mut Context<Self>,
 7475    ) {
 7476        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7477            return;
 7478        };
 7479        if self.selections.count() != 1 {
 7480            return;
 7481        }
 7482
 7483        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7484
 7485        match &active_edit_prediction.completion {
 7486            EditPrediction::Move { target, .. } => {
 7487                let target = *target;
 7488                self.change_selections(
 7489                    SelectionEffects::scroll(Autoscroll::newest()),
 7490                    window,
 7491                    cx,
 7492                    |selections| {
 7493                        selections.select_anchor_ranges([target..target]);
 7494                    },
 7495                );
 7496            }
 7497            EditPrediction::Edit { edits, .. } => {
 7498                // Find an insertion that starts at the cursor position.
 7499                let snapshot = self.buffer.read(cx).snapshot(cx);
 7500                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7501                let insertion = edits.iter().find_map(|(range, text)| {
 7502                    let range = range.to_offset(&snapshot);
 7503                    if range.is_empty() && range.start == cursor_offset {
 7504                        Some(text)
 7505                    } else {
 7506                        None
 7507                    }
 7508                });
 7509
 7510                if let Some(text) = insertion {
 7511                    let mut partial_completion = text
 7512                        .chars()
 7513                        .by_ref()
 7514                        .take_while(|c| c.is_alphabetic())
 7515                        .collect::<String>();
 7516                    if partial_completion.is_empty() {
 7517                        partial_completion = text
 7518                            .chars()
 7519                            .by_ref()
 7520                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7521                            .collect::<String>();
 7522                    }
 7523
 7524                    cx.emit(EditorEvent::InputHandled {
 7525                        utf16_range_to_replace: None,
 7526                        text: partial_completion.clone().into(),
 7527                    });
 7528
 7529                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7530
 7531                    self.refresh_edit_prediction(true, true, window, cx);
 7532                    cx.notify();
 7533                } else {
 7534                    self.accept_edit_prediction(&Default::default(), window, cx);
 7535                }
 7536            }
 7537        }
 7538    }
 7539
 7540    fn discard_edit_prediction(
 7541        &mut self,
 7542        should_report_edit_prediction_event: bool,
 7543        cx: &mut Context<Self>,
 7544    ) -> bool {
 7545        if should_report_edit_prediction_event {
 7546            let completion_id = self
 7547                .active_edit_prediction
 7548                .as_ref()
 7549                .and_then(|active_completion| active_completion.completion_id.clone());
 7550
 7551            self.report_edit_prediction_event(completion_id, false, cx);
 7552        }
 7553
 7554        if let Some(provider) = self.edit_prediction_provider() {
 7555            provider.discard(cx);
 7556        }
 7557
 7558        self.take_active_edit_prediction(cx)
 7559    }
 7560
 7561    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7562        let Some(provider) = self.edit_prediction_provider() else {
 7563            return;
 7564        };
 7565
 7566        let Some((_, buffer, _)) = self
 7567            .buffer
 7568            .read(cx)
 7569            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7570        else {
 7571            return;
 7572        };
 7573
 7574        let extension = buffer
 7575            .read(cx)
 7576            .file()
 7577            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7578
 7579        let event_type = match accepted {
 7580            true => "Edit Prediction Accepted",
 7581            false => "Edit Prediction Discarded",
 7582        };
 7583        telemetry::event!(
 7584            event_type,
 7585            provider = provider.name(),
 7586            prediction_id = id,
 7587            suggestion_accepted = accepted,
 7588            file_extension = extension,
 7589        );
 7590    }
 7591
 7592    pub fn has_active_edit_prediction(&self) -> bool {
 7593        self.active_edit_prediction.is_some()
 7594    }
 7595
 7596    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7597        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7598            return false;
 7599        };
 7600
 7601        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7602        self.clear_highlights::<EditPredictionHighlight>(cx);
 7603        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7604        true
 7605    }
 7606
 7607    /// Returns true when we're displaying the edit prediction popover below the cursor
 7608    /// like we are not previewing and the LSP autocomplete menu is visible
 7609    /// or we are in `when_holding_modifier` mode.
 7610    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7611        if self.edit_prediction_preview_is_active()
 7612            || !self.show_edit_predictions_in_menu()
 7613            || !self.edit_predictions_enabled()
 7614        {
 7615            return false;
 7616        }
 7617
 7618        if self.has_visible_completions_menu() {
 7619            return true;
 7620        }
 7621
 7622        has_completion && self.edit_prediction_requires_modifier()
 7623    }
 7624
 7625    fn handle_modifiers_changed(
 7626        &mut self,
 7627        modifiers: Modifiers,
 7628        position_map: &PositionMap,
 7629        window: &mut Window,
 7630        cx: &mut Context<Self>,
 7631    ) {
 7632        if self.show_edit_predictions_in_menu() {
 7633            self.update_edit_prediction_preview(&modifiers, window, cx);
 7634        }
 7635
 7636        self.update_selection_mode(&modifiers, position_map, window, cx);
 7637
 7638        let mouse_position = window.mouse_position();
 7639        if !position_map.text_hitbox.is_hovered(window) {
 7640            return;
 7641        }
 7642
 7643        self.update_hovered_link(
 7644            position_map.point_for_position(mouse_position),
 7645            &position_map.snapshot,
 7646            modifiers,
 7647            window,
 7648            cx,
 7649        )
 7650    }
 7651
 7652    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7653        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7654        if invert {
 7655            match multi_cursor_setting {
 7656                MultiCursorModifier::Alt => modifiers.alt,
 7657                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7658            }
 7659        } else {
 7660            match multi_cursor_setting {
 7661                MultiCursorModifier::Alt => modifiers.secondary(),
 7662                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7663            }
 7664        }
 7665    }
 7666
 7667    fn columnar_selection_mode(
 7668        modifiers: &Modifiers,
 7669        cx: &mut Context<Self>,
 7670    ) -> Option<ColumnarMode> {
 7671        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7672            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7673                Some(ColumnarMode::FromMouse)
 7674            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7675                Some(ColumnarMode::FromSelection)
 7676            } else {
 7677                None
 7678            }
 7679        } else {
 7680            None
 7681        }
 7682    }
 7683
 7684    fn update_selection_mode(
 7685        &mut self,
 7686        modifiers: &Modifiers,
 7687        position_map: &PositionMap,
 7688        window: &mut Window,
 7689        cx: &mut Context<Self>,
 7690    ) {
 7691        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7692            return;
 7693        };
 7694        if self.selections.pending.is_none() {
 7695            return;
 7696        }
 7697
 7698        let mouse_position = window.mouse_position();
 7699        let point_for_position = position_map.point_for_position(mouse_position);
 7700        let position = point_for_position.previous_valid;
 7701
 7702        self.select(
 7703            SelectPhase::BeginColumnar {
 7704                position,
 7705                reset: false,
 7706                mode,
 7707                goal_column: point_for_position.exact_unclipped.column(),
 7708            },
 7709            window,
 7710            cx,
 7711        );
 7712    }
 7713
 7714    fn update_edit_prediction_preview(
 7715        &mut self,
 7716        modifiers: &Modifiers,
 7717        window: &mut Window,
 7718        cx: &mut Context<Self>,
 7719    ) {
 7720        let mut modifiers_held = false;
 7721        if let Some(accept_keystroke) = self
 7722            .accept_edit_prediction_keybind(false, window, cx)
 7723            .keystroke()
 7724        {
 7725            modifiers_held = modifiers_held
 7726                || (accept_keystroke.modifiers() == modifiers
 7727                    && accept_keystroke.modifiers().modified());
 7728        };
 7729        if let Some(accept_partial_keystroke) = self
 7730            .accept_edit_prediction_keybind(true, window, cx)
 7731            .keystroke()
 7732        {
 7733            modifiers_held = modifiers_held
 7734                || (accept_partial_keystroke.modifiers() == modifiers
 7735                    && accept_partial_keystroke.modifiers().modified());
 7736        }
 7737
 7738        if modifiers_held {
 7739            if matches!(
 7740                self.edit_prediction_preview,
 7741                EditPredictionPreview::Inactive { .. }
 7742            ) {
 7743                self.edit_prediction_preview = EditPredictionPreview::Active {
 7744                    previous_scroll_position: None,
 7745                    since: Instant::now(),
 7746                };
 7747
 7748                self.update_visible_edit_prediction(window, cx);
 7749                cx.notify();
 7750            }
 7751        } else if let EditPredictionPreview::Active {
 7752            previous_scroll_position,
 7753            since,
 7754        } = self.edit_prediction_preview
 7755        {
 7756            if let (Some(previous_scroll_position), Some(position_map)) =
 7757                (previous_scroll_position, self.last_position_map.as_ref())
 7758            {
 7759                self.set_scroll_position(
 7760                    previous_scroll_position
 7761                        .scroll_position(&position_map.snapshot.display_snapshot),
 7762                    window,
 7763                    cx,
 7764                );
 7765            }
 7766
 7767            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7768                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7769            };
 7770            self.clear_row_highlights::<EditPredictionPreview>();
 7771            self.update_visible_edit_prediction(window, cx);
 7772            cx.notify();
 7773        }
 7774    }
 7775
 7776    fn update_visible_edit_prediction(
 7777        &mut self,
 7778        _window: &mut Window,
 7779        cx: &mut Context<Self>,
 7780    ) -> Option<()> {
 7781        if DisableAiSettings::get_global(cx).disable_ai {
 7782            return None;
 7783        }
 7784
 7785        if self.ime_transaction.is_some() {
 7786            self.discard_edit_prediction(false, cx);
 7787            return None;
 7788        }
 7789
 7790        let selection = self.selections.newest_anchor();
 7791        let cursor = selection.head();
 7792        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7793        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7794        let excerpt_id = cursor.excerpt_id;
 7795
 7796        let show_in_menu = self.show_edit_predictions_in_menu();
 7797        let completions_menu_has_precedence = !show_in_menu
 7798            && (self.context_menu.borrow().is_some()
 7799                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7800
 7801        if completions_menu_has_precedence
 7802            || !offset_selection.is_empty()
 7803            || self
 7804                .active_edit_prediction
 7805                .as_ref()
 7806                .is_some_and(|completion| {
 7807                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7808                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7809                    !invalidation_range.contains(&offset_selection.head())
 7810                })
 7811        {
 7812            self.discard_edit_prediction(false, cx);
 7813            return None;
 7814        }
 7815
 7816        self.take_active_edit_prediction(cx);
 7817        let Some(provider) = self.edit_prediction_provider() else {
 7818            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7819            return None;
 7820        };
 7821
 7822        let (buffer, cursor_buffer_position) =
 7823            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7824
 7825        self.edit_prediction_settings =
 7826            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7827
 7828        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7829            self.discard_edit_prediction(false, cx);
 7830            return None;
 7831        };
 7832
 7833        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7834
 7835        if self.edit_prediction_indent_conflict {
 7836            let cursor_point = cursor.to_point(&multibuffer);
 7837
 7838            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7839
 7840            if let Some((_, indent)) = indents.iter().next()
 7841                && indent.len == cursor_point.column
 7842            {
 7843                self.edit_prediction_indent_conflict = false;
 7844            }
 7845        }
 7846
 7847        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7848        let edits = edit_prediction
 7849            .edits
 7850            .into_iter()
 7851            .flat_map(|(range, new_text)| {
 7852                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7853                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7854                Some((start..end, new_text))
 7855            })
 7856            .collect::<Vec<_>>();
 7857        if edits.is_empty() {
 7858            return None;
 7859        }
 7860
 7861        let first_edit_start = edits.first().unwrap().0.start;
 7862        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7863        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7864
 7865        let last_edit_end = edits.last().unwrap().0.end;
 7866        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7867        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7868
 7869        let cursor_row = cursor.to_point(&multibuffer).row;
 7870
 7871        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7872
 7873        let mut inlay_ids = Vec::new();
 7874        let invalidation_row_range;
 7875        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7876            Some(cursor_row..edit_end_row)
 7877        } else if cursor_row > edit_end_row {
 7878            Some(edit_start_row..cursor_row)
 7879        } else {
 7880            None
 7881        };
 7882        let supports_jump = self
 7883            .edit_prediction_provider
 7884            .as_ref()
 7885            .map(|provider| provider.provider.supports_jump_to_edit())
 7886            .unwrap_or(true);
 7887
 7888        let is_move = supports_jump
 7889            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7890        let completion = if is_move {
 7891            invalidation_row_range =
 7892                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7893            let target = first_edit_start;
 7894            EditPrediction::Move { target, snapshot }
 7895        } else {
 7896            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7897                && !self.edit_predictions_hidden_for_vim_mode;
 7898
 7899            if show_completions_in_buffer {
 7900                if edits
 7901                    .iter()
 7902                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7903                {
 7904                    let mut inlays = Vec::new();
 7905                    for (range, new_text) in &edits {
 7906                        let inlay = Inlay::edit_prediction(
 7907                            post_inc(&mut self.next_inlay_id),
 7908                            range.start,
 7909                            new_text.as_str(),
 7910                        );
 7911                        inlay_ids.push(inlay.id);
 7912                        inlays.push(inlay);
 7913                    }
 7914
 7915                    self.splice_inlays(&[], inlays, cx);
 7916                } else {
 7917                    let background_color = cx.theme().status().deleted_background;
 7918                    self.highlight_text::<EditPredictionHighlight>(
 7919                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7920                        HighlightStyle {
 7921                            background_color: Some(background_color),
 7922                            ..Default::default()
 7923                        },
 7924                        cx,
 7925                    );
 7926                }
 7927            }
 7928
 7929            invalidation_row_range = edit_start_row..edit_end_row;
 7930
 7931            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7932                if provider.show_tab_accept_marker() {
 7933                    EditDisplayMode::TabAccept
 7934                } else {
 7935                    EditDisplayMode::Inline
 7936                }
 7937            } else {
 7938                EditDisplayMode::DiffPopover
 7939            };
 7940
 7941            EditPrediction::Edit {
 7942                edits,
 7943                edit_preview: edit_prediction.edit_preview,
 7944                display_mode,
 7945                snapshot,
 7946            }
 7947        };
 7948
 7949        let invalidation_range = multibuffer
 7950            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7951            ..multibuffer.anchor_after(Point::new(
 7952                invalidation_row_range.end,
 7953                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7954            ));
 7955
 7956        self.stale_edit_prediction_in_menu = None;
 7957        self.active_edit_prediction = Some(EditPredictionState {
 7958            inlay_ids,
 7959            completion,
 7960            completion_id: edit_prediction.id,
 7961            invalidation_range,
 7962        });
 7963
 7964        cx.notify();
 7965
 7966        Some(())
 7967    }
 7968
 7969    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7970        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7971    }
 7972
 7973    fn clear_tasks(&mut self) {
 7974        self.tasks.clear()
 7975    }
 7976
 7977    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7978        if self.tasks.insert(key, value).is_some() {
 7979            // This case should hopefully be rare, but just in case...
 7980            log::error!(
 7981                "multiple different run targets found on a single line, only the last target will be rendered"
 7982            )
 7983        }
 7984    }
 7985
 7986    /// Get all display points of breakpoints that will be rendered within editor
 7987    ///
 7988    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7989    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7990    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7991    fn active_breakpoints(
 7992        &self,
 7993        range: Range<DisplayRow>,
 7994        window: &mut Window,
 7995        cx: &mut Context<Self>,
 7996    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7997        let mut breakpoint_display_points = HashMap::default();
 7998
 7999        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8000            return breakpoint_display_points;
 8001        };
 8002
 8003        let snapshot = self.snapshot(window, cx);
 8004
 8005        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8006        let Some(project) = self.project() else {
 8007            return breakpoint_display_points;
 8008        };
 8009
 8010        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8011            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8012
 8013        for (buffer_snapshot, range, excerpt_id) in
 8014            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8015        {
 8016            let Some(buffer) = project
 8017                .read(cx)
 8018                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8019            else {
 8020                continue;
 8021            };
 8022            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8023                &buffer,
 8024                Some(
 8025                    buffer_snapshot.anchor_before(range.start)
 8026                        ..buffer_snapshot.anchor_after(range.end),
 8027                ),
 8028                buffer_snapshot,
 8029                cx,
 8030            );
 8031            for (breakpoint, state) in breakpoints {
 8032                let multi_buffer_anchor =
 8033                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8034                let position = multi_buffer_anchor
 8035                    .to_point(multi_buffer_snapshot)
 8036                    .to_display_point(&snapshot);
 8037
 8038                breakpoint_display_points.insert(
 8039                    position.row(),
 8040                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8041                );
 8042            }
 8043        }
 8044
 8045        breakpoint_display_points
 8046    }
 8047
 8048    fn breakpoint_context_menu(
 8049        &self,
 8050        anchor: Anchor,
 8051        window: &mut Window,
 8052        cx: &mut Context<Self>,
 8053    ) -> Entity<ui::ContextMenu> {
 8054        let weak_editor = cx.weak_entity();
 8055        let focus_handle = self.focus_handle(cx);
 8056
 8057        let row = self
 8058            .buffer
 8059            .read(cx)
 8060            .snapshot(cx)
 8061            .summary_for_anchor::<Point>(&anchor)
 8062            .row;
 8063
 8064        let breakpoint = self
 8065            .breakpoint_at_row(row, window, cx)
 8066            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8067
 8068        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8069            "Edit Log Breakpoint"
 8070        } else {
 8071            "Set Log Breakpoint"
 8072        };
 8073
 8074        let condition_breakpoint_msg = if breakpoint
 8075            .as_ref()
 8076            .is_some_and(|bp| bp.1.condition.is_some())
 8077        {
 8078            "Edit Condition Breakpoint"
 8079        } else {
 8080            "Set Condition Breakpoint"
 8081        };
 8082
 8083        let hit_condition_breakpoint_msg = if breakpoint
 8084            .as_ref()
 8085            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8086        {
 8087            "Edit Hit Condition Breakpoint"
 8088        } else {
 8089            "Set Hit Condition Breakpoint"
 8090        };
 8091
 8092        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8093            "Unset Breakpoint"
 8094        } else {
 8095            "Set Breakpoint"
 8096        };
 8097
 8098        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8099
 8100        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8101            BreakpointState::Enabled => Some("Disable"),
 8102            BreakpointState::Disabled => Some("Enable"),
 8103        });
 8104
 8105        let (anchor, breakpoint) =
 8106            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8107
 8108        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8109            menu.on_blur_subscription(Subscription::new(|| {}))
 8110                .context(focus_handle)
 8111                .when(run_to_cursor, |this| {
 8112                    let weak_editor = weak_editor.clone();
 8113                    this.entry("Run to cursor", None, move |window, cx| {
 8114                        weak_editor
 8115                            .update(cx, |editor, cx| {
 8116                                editor.change_selections(
 8117                                    SelectionEffects::no_scroll(),
 8118                                    window,
 8119                                    cx,
 8120                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8121                                );
 8122                            })
 8123                            .ok();
 8124
 8125                        window.dispatch_action(Box::new(RunToCursor), cx);
 8126                    })
 8127                    .separator()
 8128                })
 8129                .when_some(toggle_state_msg, |this, msg| {
 8130                    this.entry(msg, None, {
 8131                        let weak_editor = weak_editor.clone();
 8132                        let breakpoint = breakpoint.clone();
 8133                        move |_window, cx| {
 8134                            weak_editor
 8135                                .update(cx, |this, cx| {
 8136                                    this.edit_breakpoint_at_anchor(
 8137                                        anchor,
 8138                                        breakpoint.as_ref().clone(),
 8139                                        BreakpointEditAction::InvertState,
 8140                                        cx,
 8141                                    );
 8142                                })
 8143                                .log_err();
 8144                        }
 8145                    })
 8146                })
 8147                .entry(set_breakpoint_msg, None, {
 8148                    let weak_editor = weak_editor.clone();
 8149                    let breakpoint = breakpoint.clone();
 8150                    move |_window, cx| {
 8151                        weak_editor
 8152                            .update(cx, |this, cx| {
 8153                                this.edit_breakpoint_at_anchor(
 8154                                    anchor,
 8155                                    breakpoint.as_ref().clone(),
 8156                                    BreakpointEditAction::Toggle,
 8157                                    cx,
 8158                                );
 8159                            })
 8160                            .log_err();
 8161                    }
 8162                })
 8163                .entry(log_breakpoint_msg, None, {
 8164                    let breakpoint = breakpoint.clone();
 8165                    let weak_editor = weak_editor.clone();
 8166                    move |window, cx| {
 8167                        weak_editor
 8168                            .update(cx, |this, cx| {
 8169                                this.add_edit_breakpoint_block(
 8170                                    anchor,
 8171                                    breakpoint.as_ref(),
 8172                                    BreakpointPromptEditAction::Log,
 8173                                    window,
 8174                                    cx,
 8175                                );
 8176                            })
 8177                            .log_err();
 8178                    }
 8179                })
 8180                .entry(condition_breakpoint_msg, None, {
 8181                    let breakpoint = breakpoint.clone();
 8182                    let weak_editor = weak_editor.clone();
 8183                    move |window, cx| {
 8184                        weak_editor
 8185                            .update(cx, |this, cx| {
 8186                                this.add_edit_breakpoint_block(
 8187                                    anchor,
 8188                                    breakpoint.as_ref(),
 8189                                    BreakpointPromptEditAction::Condition,
 8190                                    window,
 8191                                    cx,
 8192                                );
 8193                            })
 8194                            .log_err();
 8195                    }
 8196                })
 8197                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8198                    weak_editor
 8199                        .update(cx, |this, cx| {
 8200                            this.add_edit_breakpoint_block(
 8201                                anchor,
 8202                                breakpoint.as_ref(),
 8203                                BreakpointPromptEditAction::HitCondition,
 8204                                window,
 8205                                cx,
 8206                            );
 8207                        })
 8208                        .log_err();
 8209                })
 8210        })
 8211    }
 8212
 8213    fn render_breakpoint(
 8214        &self,
 8215        position: Anchor,
 8216        row: DisplayRow,
 8217        breakpoint: &Breakpoint,
 8218        state: Option<BreakpointSessionState>,
 8219        cx: &mut Context<Self>,
 8220    ) -> IconButton {
 8221        let is_rejected = state.is_some_and(|s| !s.verified);
 8222        // Is it a breakpoint that shows up when hovering over gutter?
 8223        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8224            (false, false),
 8225            |PhantomBreakpointIndicator {
 8226                 is_active,
 8227                 display_row,
 8228                 collides_with_existing_breakpoint,
 8229             }| {
 8230                (
 8231                    is_active && display_row == row,
 8232                    collides_with_existing_breakpoint,
 8233                )
 8234            },
 8235        );
 8236
 8237        let (color, icon) = {
 8238            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8239                (false, false) => ui::IconName::DebugBreakpoint,
 8240                (true, false) => ui::IconName::DebugLogBreakpoint,
 8241                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8242                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8243            };
 8244
 8245            let color = if is_phantom {
 8246                Color::Hint
 8247            } else if is_rejected {
 8248                Color::Disabled
 8249            } else {
 8250                Color::Debugger
 8251            };
 8252
 8253            (color, icon)
 8254        };
 8255
 8256        let breakpoint = Arc::from(breakpoint.clone());
 8257
 8258        let alt_as_text = gpui::Keystroke {
 8259            modifiers: Modifiers::secondary_key(),
 8260            ..Default::default()
 8261        };
 8262        let primary_action_text = if breakpoint.is_disabled() {
 8263            "Enable breakpoint"
 8264        } else if is_phantom && !collides_with_existing {
 8265            "Set breakpoint"
 8266        } else {
 8267            "Unset breakpoint"
 8268        };
 8269        let focus_handle = self.focus_handle.clone();
 8270
 8271        let meta = if is_rejected {
 8272            SharedString::from("No executable code is associated with this line.")
 8273        } else if collides_with_existing && !breakpoint.is_disabled() {
 8274            SharedString::from(format!(
 8275                "{alt_as_text}-click to disable,\nright-click for more options."
 8276            ))
 8277        } else {
 8278            SharedString::from("Right-click for more options.")
 8279        };
 8280        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8281            .icon_size(IconSize::XSmall)
 8282            .size(ui::ButtonSize::None)
 8283            .when(is_rejected, |this| {
 8284                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8285            })
 8286            .icon_color(color)
 8287            .style(ButtonStyle::Transparent)
 8288            .on_click(cx.listener({
 8289                move |editor, event: &ClickEvent, window, cx| {
 8290                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8291                        BreakpointEditAction::InvertState
 8292                    } else {
 8293                        BreakpointEditAction::Toggle
 8294                    };
 8295
 8296                    window.focus(&editor.focus_handle(cx));
 8297                    editor.edit_breakpoint_at_anchor(
 8298                        position,
 8299                        breakpoint.as_ref().clone(),
 8300                        edit_action,
 8301                        cx,
 8302                    );
 8303                }
 8304            }))
 8305            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8306                editor.set_breakpoint_context_menu(
 8307                    row,
 8308                    Some(position),
 8309                    event.position(),
 8310                    window,
 8311                    cx,
 8312                );
 8313            }))
 8314            .tooltip(move |window, cx| {
 8315                Tooltip::with_meta_in(
 8316                    primary_action_text,
 8317                    Some(&ToggleBreakpoint),
 8318                    meta.clone(),
 8319                    &focus_handle,
 8320                    window,
 8321                    cx,
 8322                )
 8323            })
 8324    }
 8325
 8326    fn build_tasks_context(
 8327        project: &Entity<Project>,
 8328        buffer: &Entity<Buffer>,
 8329        buffer_row: u32,
 8330        tasks: &Arc<RunnableTasks>,
 8331        cx: &mut Context<Self>,
 8332    ) -> Task<Option<task::TaskContext>> {
 8333        let position = Point::new(buffer_row, tasks.column);
 8334        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8335        let location = Location {
 8336            buffer: buffer.clone(),
 8337            range: range_start..range_start,
 8338        };
 8339        // Fill in the environmental variables from the tree-sitter captures
 8340        let mut captured_task_variables = TaskVariables::default();
 8341        for (capture_name, value) in tasks.extra_variables.clone() {
 8342            captured_task_variables.insert(
 8343                task::VariableName::Custom(capture_name.into()),
 8344                value.clone(),
 8345            );
 8346        }
 8347        project.update(cx, |project, cx| {
 8348            project.task_store().update(cx, |task_store, cx| {
 8349                task_store.task_context_for_location(captured_task_variables, location, cx)
 8350            })
 8351        })
 8352    }
 8353
 8354    pub fn spawn_nearest_task(
 8355        &mut self,
 8356        action: &SpawnNearestTask,
 8357        window: &mut Window,
 8358        cx: &mut Context<Self>,
 8359    ) {
 8360        let Some((workspace, _)) = self.workspace.clone() else {
 8361            return;
 8362        };
 8363        let Some(project) = self.project.clone() else {
 8364            return;
 8365        };
 8366
 8367        // Try to find a closest, enclosing node using tree-sitter that has a task
 8368        let Some((buffer, buffer_row, tasks)) = self
 8369            .find_enclosing_node_task(cx)
 8370            // Or find the task that's closest in row-distance.
 8371            .or_else(|| self.find_closest_task(cx))
 8372        else {
 8373            return;
 8374        };
 8375
 8376        let reveal_strategy = action.reveal;
 8377        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8378        cx.spawn_in(window, async move |_, cx| {
 8379            let context = task_context.await?;
 8380            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8381
 8382            let resolved = &mut resolved_task.resolved;
 8383            resolved.reveal = reveal_strategy;
 8384
 8385            workspace
 8386                .update_in(cx, |workspace, window, cx| {
 8387                    workspace.schedule_resolved_task(
 8388                        task_source_kind,
 8389                        resolved_task,
 8390                        false,
 8391                        window,
 8392                        cx,
 8393                    );
 8394                })
 8395                .ok()
 8396        })
 8397        .detach();
 8398    }
 8399
 8400    fn find_closest_task(
 8401        &mut self,
 8402        cx: &mut Context<Self>,
 8403    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8404        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8405
 8406        let ((buffer_id, row), tasks) = self
 8407            .tasks
 8408            .iter()
 8409            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8410
 8411        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8412        let tasks = Arc::new(tasks.to_owned());
 8413        Some((buffer, *row, tasks))
 8414    }
 8415
 8416    fn find_enclosing_node_task(
 8417        &mut self,
 8418        cx: &mut Context<Self>,
 8419    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8420        let snapshot = self.buffer.read(cx).snapshot(cx);
 8421        let offset = self.selections.newest::<usize>(cx).head();
 8422        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8423        let buffer_id = excerpt.buffer().remote_id();
 8424
 8425        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8426        let mut cursor = layer.node().walk();
 8427
 8428        while cursor.goto_first_child_for_byte(offset).is_some() {
 8429            if cursor.node().end_byte() == offset {
 8430                cursor.goto_next_sibling();
 8431            }
 8432        }
 8433
 8434        // Ascend to the smallest ancestor that contains the range and has a task.
 8435        loop {
 8436            let node = cursor.node();
 8437            let node_range = node.byte_range();
 8438            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8439
 8440            // Check if this node contains our offset
 8441            if node_range.start <= offset && node_range.end >= offset {
 8442                // If it contains offset, check for task
 8443                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8444                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8445                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8446                }
 8447            }
 8448
 8449            if !cursor.goto_parent() {
 8450                break;
 8451            }
 8452        }
 8453        None
 8454    }
 8455
 8456    fn render_run_indicator(
 8457        &self,
 8458        _style: &EditorStyle,
 8459        is_active: bool,
 8460        row: DisplayRow,
 8461        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8462        cx: &mut Context<Self>,
 8463    ) -> IconButton {
 8464        let color = Color::Muted;
 8465        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8466
 8467        IconButton::new(
 8468            ("run_indicator", row.0 as usize),
 8469            ui::IconName::PlayOutlined,
 8470        )
 8471        .shape(ui::IconButtonShape::Square)
 8472        .icon_size(IconSize::XSmall)
 8473        .icon_color(color)
 8474        .toggle_state(is_active)
 8475        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8476            let quick_launch = match e {
 8477                ClickEvent::Keyboard(_) => true,
 8478                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8479            };
 8480
 8481            window.focus(&editor.focus_handle(cx));
 8482            editor.toggle_code_actions(
 8483                &ToggleCodeActions {
 8484                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8485                    quick_launch,
 8486                },
 8487                window,
 8488                cx,
 8489            );
 8490        }))
 8491        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8492            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8493        }))
 8494    }
 8495
 8496    pub fn context_menu_visible(&self) -> bool {
 8497        !self.edit_prediction_preview_is_active()
 8498            && self
 8499                .context_menu
 8500                .borrow()
 8501                .as_ref()
 8502                .is_some_and(|menu| menu.visible())
 8503    }
 8504
 8505    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8506        self.context_menu
 8507            .borrow()
 8508            .as_ref()
 8509            .map(|menu| menu.origin())
 8510    }
 8511
 8512    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8513        self.context_menu_options = Some(options);
 8514    }
 8515
 8516    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8517    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8518
 8519    fn render_edit_prediction_popover(
 8520        &mut self,
 8521        text_bounds: &Bounds<Pixels>,
 8522        content_origin: gpui::Point<Pixels>,
 8523        right_margin: Pixels,
 8524        editor_snapshot: &EditorSnapshot,
 8525        visible_row_range: Range<DisplayRow>,
 8526        scroll_top: f32,
 8527        scroll_bottom: f32,
 8528        line_layouts: &[LineWithInvisibles],
 8529        line_height: Pixels,
 8530        scroll_pixel_position: gpui::Point<Pixels>,
 8531        newest_selection_head: Option<DisplayPoint>,
 8532        editor_width: Pixels,
 8533        style: &EditorStyle,
 8534        window: &mut Window,
 8535        cx: &mut App,
 8536    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8537        if self.mode().is_minimap() {
 8538            return None;
 8539        }
 8540        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8541
 8542        if self.edit_prediction_visible_in_cursor_popover(true) {
 8543            return None;
 8544        }
 8545
 8546        match &active_edit_prediction.completion {
 8547            EditPrediction::Move { target, .. } => {
 8548                let target_display_point = target.to_display_point(editor_snapshot);
 8549
 8550                if self.edit_prediction_requires_modifier() {
 8551                    if !self.edit_prediction_preview_is_active() {
 8552                        return None;
 8553                    }
 8554
 8555                    self.render_edit_prediction_modifier_jump_popover(
 8556                        text_bounds,
 8557                        content_origin,
 8558                        visible_row_range,
 8559                        line_layouts,
 8560                        line_height,
 8561                        scroll_pixel_position,
 8562                        newest_selection_head,
 8563                        target_display_point,
 8564                        window,
 8565                        cx,
 8566                    )
 8567                } else {
 8568                    self.render_edit_prediction_eager_jump_popover(
 8569                        text_bounds,
 8570                        content_origin,
 8571                        editor_snapshot,
 8572                        visible_row_range,
 8573                        scroll_top,
 8574                        scroll_bottom,
 8575                        line_height,
 8576                        scroll_pixel_position,
 8577                        target_display_point,
 8578                        editor_width,
 8579                        window,
 8580                        cx,
 8581                    )
 8582                }
 8583            }
 8584            EditPrediction::Edit {
 8585                display_mode: EditDisplayMode::Inline,
 8586                ..
 8587            } => None,
 8588            EditPrediction::Edit {
 8589                display_mode: EditDisplayMode::TabAccept,
 8590                edits,
 8591                ..
 8592            } => {
 8593                let range = &edits.first()?.0;
 8594                let target_display_point = range.end.to_display_point(editor_snapshot);
 8595
 8596                self.render_edit_prediction_end_of_line_popover(
 8597                    "Accept",
 8598                    editor_snapshot,
 8599                    visible_row_range,
 8600                    target_display_point,
 8601                    line_height,
 8602                    scroll_pixel_position,
 8603                    content_origin,
 8604                    editor_width,
 8605                    window,
 8606                    cx,
 8607                )
 8608            }
 8609            EditPrediction::Edit {
 8610                edits,
 8611                edit_preview,
 8612                display_mode: EditDisplayMode::DiffPopover,
 8613                snapshot,
 8614            } => self.render_edit_prediction_diff_popover(
 8615                text_bounds,
 8616                content_origin,
 8617                right_margin,
 8618                editor_snapshot,
 8619                visible_row_range,
 8620                line_layouts,
 8621                line_height,
 8622                scroll_pixel_position,
 8623                newest_selection_head,
 8624                editor_width,
 8625                style,
 8626                edits,
 8627                edit_preview,
 8628                snapshot,
 8629                window,
 8630                cx,
 8631            ),
 8632        }
 8633    }
 8634
 8635    fn render_edit_prediction_modifier_jump_popover(
 8636        &mut self,
 8637        text_bounds: &Bounds<Pixels>,
 8638        content_origin: gpui::Point<Pixels>,
 8639        visible_row_range: Range<DisplayRow>,
 8640        line_layouts: &[LineWithInvisibles],
 8641        line_height: Pixels,
 8642        scroll_pixel_position: gpui::Point<Pixels>,
 8643        newest_selection_head: Option<DisplayPoint>,
 8644        target_display_point: DisplayPoint,
 8645        window: &mut Window,
 8646        cx: &mut App,
 8647    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8648        let scrolled_content_origin =
 8649            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8650
 8651        const SCROLL_PADDING_Y: Pixels = px(12.);
 8652
 8653        if target_display_point.row() < visible_row_range.start {
 8654            return self.render_edit_prediction_scroll_popover(
 8655                |_| SCROLL_PADDING_Y,
 8656                IconName::ArrowUp,
 8657                visible_row_range,
 8658                line_layouts,
 8659                newest_selection_head,
 8660                scrolled_content_origin,
 8661                window,
 8662                cx,
 8663            );
 8664        } else if target_display_point.row() >= visible_row_range.end {
 8665            return self.render_edit_prediction_scroll_popover(
 8666                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8667                IconName::ArrowDown,
 8668                visible_row_range,
 8669                line_layouts,
 8670                newest_selection_head,
 8671                scrolled_content_origin,
 8672                window,
 8673                cx,
 8674            );
 8675        }
 8676
 8677        const POLE_WIDTH: Pixels = px(2.);
 8678
 8679        let line_layout =
 8680            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8681        let target_column = target_display_point.column() as usize;
 8682
 8683        let target_x = line_layout.x_for_index(target_column);
 8684        let target_y =
 8685            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8686
 8687        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8688
 8689        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8690        border_color.l += 0.001;
 8691
 8692        let mut element = v_flex()
 8693            .items_end()
 8694            .when(flag_on_right, |el| el.items_start())
 8695            .child(if flag_on_right {
 8696                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8697                    .rounded_bl(px(0.))
 8698                    .rounded_tl(px(0.))
 8699                    .border_l_2()
 8700                    .border_color(border_color)
 8701            } else {
 8702                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8703                    .rounded_br(px(0.))
 8704                    .rounded_tr(px(0.))
 8705                    .border_r_2()
 8706                    .border_color(border_color)
 8707            })
 8708            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8709            .into_any();
 8710
 8711        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8712
 8713        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8714            - point(
 8715                if flag_on_right {
 8716                    POLE_WIDTH
 8717                } else {
 8718                    size.width - POLE_WIDTH
 8719                },
 8720                size.height - line_height,
 8721            );
 8722
 8723        origin.x = origin.x.max(content_origin.x);
 8724
 8725        element.prepaint_at(origin, window, cx);
 8726
 8727        Some((element, origin))
 8728    }
 8729
 8730    fn render_edit_prediction_scroll_popover(
 8731        &mut self,
 8732        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8733        scroll_icon: IconName,
 8734        visible_row_range: Range<DisplayRow>,
 8735        line_layouts: &[LineWithInvisibles],
 8736        newest_selection_head: Option<DisplayPoint>,
 8737        scrolled_content_origin: gpui::Point<Pixels>,
 8738        window: &mut Window,
 8739        cx: &mut App,
 8740    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8741        let mut element = self
 8742            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8743            .into_any();
 8744
 8745        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8746
 8747        let cursor = newest_selection_head?;
 8748        let cursor_row_layout =
 8749            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8750        let cursor_column = cursor.column() as usize;
 8751
 8752        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8753
 8754        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8755
 8756        element.prepaint_at(origin, window, cx);
 8757        Some((element, origin))
 8758    }
 8759
 8760    fn render_edit_prediction_eager_jump_popover(
 8761        &mut self,
 8762        text_bounds: &Bounds<Pixels>,
 8763        content_origin: gpui::Point<Pixels>,
 8764        editor_snapshot: &EditorSnapshot,
 8765        visible_row_range: Range<DisplayRow>,
 8766        scroll_top: f32,
 8767        scroll_bottom: f32,
 8768        line_height: Pixels,
 8769        scroll_pixel_position: gpui::Point<Pixels>,
 8770        target_display_point: DisplayPoint,
 8771        editor_width: Pixels,
 8772        window: &mut Window,
 8773        cx: &mut App,
 8774    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8775        if target_display_point.row().as_f32() < scroll_top {
 8776            let mut element = self
 8777                .render_edit_prediction_line_popover(
 8778                    "Jump to Edit",
 8779                    Some(IconName::ArrowUp),
 8780                    window,
 8781                    cx,
 8782                )?
 8783                .into_any();
 8784
 8785            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8786            let offset = point(
 8787                (text_bounds.size.width - size.width) / 2.,
 8788                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8789            );
 8790
 8791            let origin = text_bounds.origin + offset;
 8792            element.prepaint_at(origin, window, cx);
 8793            Some((element, origin))
 8794        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8795            let mut element = self
 8796                .render_edit_prediction_line_popover(
 8797                    "Jump to Edit",
 8798                    Some(IconName::ArrowDown),
 8799                    window,
 8800                    cx,
 8801                )?
 8802                .into_any();
 8803
 8804            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8805            let offset = point(
 8806                (text_bounds.size.width - size.width) / 2.,
 8807                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8808            );
 8809
 8810            let origin = text_bounds.origin + offset;
 8811            element.prepaint_at(origin, window, cx);
 8812            Some((element, origin))
 8813        } else {
 8814            self.render_edit_prediction_end_of_line_popover(
 8815                "Jump to Edit",
 8816                editor_snapshot,
 8817                visible_row_range,
 8818                target_display_point,
 8819                line_height,
 8820                scroll_pixel_position,
 8821                content_origin,
 8822                editor_width,
 8823                window,
 8824                cx,
 8825            )
 8826        }
 8827    }
 8828
 8829    fn render_edit_prediction_end_of_line_popover(
 8830        self: &mut Editor,
 8831        label: &'static str,
 8832        editor_snapshot: &EditorSnapshot,
 8833        visible_row_range: Range<DisplayRow>,
 8834        target_display_point: DisplayPoint,
 8835        line_height: Pixels,
 8836        scroll_pixel_position: gpui::Point<Pixels>,
 8837        content_origin: gpui::Point<Pixels>,
 8838        editor_width: Pixels,
 8839        window: &mut Window,
 8840        cx: &mut App,
 8841    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8842        let target_line_end = DisplayPoint::new(
 8843            target_display_point.row(),
 8844            editor_snapshot.line_len(target_display_point.row()),
 8845        );
 8846
 8847        let mut element = self
 8848            .render_edit_prediction_line_popover(label, None, window, cx)?
 8849            .into_any();
 8850
 8851        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8852
 8853        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8854
 8855        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8856        let mut origin = start_point
 8857            + line_origin
 8858            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8859        origin.x = origin.x.max(content_origin.x);
 8860
 8861        let max_x = content_origin.x + editor_width - size.width;
 8862
 8863        if origin.x > max_x {
 8864            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8865
 8866            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8867                origin.y += offset;
 8868                IconName::ArrowUp
 8869            } else {
 8870                origin.y -= offset;
 8871                IconName::ArrowDown
 8872            };
 8873
 8874            element = self
 8875                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8876                .into_any();
 8877
 8878            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8879
 8880            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8881        }
 8882
 8883        element.prepaint_at(origin, window, cx);
 8884        Some((element, origin))
 8885    }
 8886
 8887    fn render_edit_prediction_diff_popover(
 8888        self: &Editor,
 8889        text_bounds: &Bounds<Pixels>,
 8890        content_origin: gpui::Point<Pixels>,
 8891        right_margin: Pixels,
 8892        editor_snapshot: &EditorSnapshot,
 8893        visible_row_range: Range<DisplayRow>,
 8894        line_layouts: &[LineWithInvisibles],
 8895        line_height: Pixels,
 8896        scroll_pixel_position: gpui::Point<Pixels>,
 8897        newest_selection_head: Option<DisplayPoint>,
 8898        editor_width: Pixels,
 8899        style: &EditorStyle,
 8900        edits: &Vec<(Range<Anchor>, String)>,
 8901        edit_preview: &Option<language::EditPreview>,
 8902        snapshot: &language::BufferSnapshot,
 8903        window: &mut Window,
 8904        cx: &mut App,
 8905    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8906        let edit_start = edits
 8907            .first()
 8908            .unwrap()
 8909            .0
 8910            .start
 8911            .to_display_point(editor_snapshot);
 8912        let edit_end = edits
 8913            .last()
 8914            .unwrap()
 8915            .0
 8916            .end
 8917            .to_display_point(editor_snapshot);
 8918
 8919        let is_visible = visible_row_range.contains(&edit_start.row())
 8920            || visible_row_range.contains(&edit_end.row());
 8921        if !is_visible {
 8922            return None;
 8923        }
 8924
 8925        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8926            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8927        } else {
 8928            // Fallback for providers without edit_preview
 8929            crate::edit_prediction_fallback_text(edits, cx)
 8930        };
 8931
 8932        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8933        let line_count = highlighted_edits.text.lines().count();
 8934
 8935        const BORDER_WIDTH: Pixels = px(1.);
 8936
 8937        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8938        let has_keybind = keybind.is_some();
 8939
 8940        let mut element = h_flex()
 8941            .items_start()
 8942            .child(
 8943                h_flex()
 8944                    .bg(cx.theme().colors().editor_background)
 8945                    .border(BORDER_WIDTH)
 8946                    .shadow_xs()
 8947                    .border_color(cx.theme().colors().border)
 8948                    .rounded_l_lg()
 8949                    .when(line_count > 1, |el| el.rounded_br_lg())
 8950                    .pr_1()
 8951                    .child(styled_text),
 8952            )
 8953            .child(
 8954                h_flex()
 8955                    .h(line_height + BORDER_WIDTH * 2.)
 8956                    .px_1p5()
 8957                    .gap_1()
 8958                    // Workaround: For some reason, there's a gap if we don't do this
 8959                    .ml(-BORDER_WIDTH)
 8960                    .shadow(vec![gpui::BoxShadow {
 8961                        color: gpui::black().opacity(0.05),
 8962                        offset: point(px(1.), px(1.)),
 8963                        blur_radius: px(2.),
 8964                        spread_radius: px(0.),
 8965                    }])
 8966                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8967                    .border(BORDER_WIDTH)
 8968                    .border_color(cx.theme().colors().border)
 8969                    .rounded_r_lg()
 8970                    .id("edit_prediction_diff_popover_keybind")
 8971                    .when(!has_keybind, |el| {
 8972                        let status_colors = cx.theme().status();
 8973
 8974                        el.bg(status_colors.error_background)
 8975                            .border_color(status_colors.error.opacity(0.6))
 8976                            .child(Icon::new(IconName::Info).color(Color::Error))
 8977                            .cursor_default()
 8978                            .hoverable_tooltip(move |_window, cx| {
 8979                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8980                            })
 8981                    })
 8982                    .children(keybind),
 8983            )
 8984            .into_any();
 8985
 8986        let longest_row =
 8987            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8988        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8989            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8990        } else {
 8991            layout_line(
 8992                longest_row,
 8993                editor_snapshot,
 8994                style,
 8995                editor_width,
 8996                |_| false,
 8997                window,
 8998                cx,
 8999            )
 9000            .width
 9001        };
 9002
 9003        let viewport_bounds =
 9004            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9005                right: -right_margin,
 9006                ..Default::default()
 9007            });
 9008
 9009        let x_after_longest =
 9010            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9011                - scroll_pixel_position.x;
 9012
 9013        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9014
 9015        // Fully visible if it can be displayed within the window (allow overlapping other
 9016        // panes). However, this is only allowed if the popover starts within text_bounds.
 9017        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9018            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9019
 9020        let mut origin = if can_position_to_the_right {
 9021            point(
 9022                x_after_longest,
 9023                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9024                    - scroll_pixel_position.y,
 9025            )
 9026        } else {
 9027            let cursor_row = newest_selection_head.map(|head| head.row());
 9028            let above_edit = edit_start
 9029                .row()
 9030                .0
 9031                .checked_sub(line_count as u32)
 9032                .map(DisplayRow);
 9033            let below_edit = Some(edit_end.row() + 1);
 9034            let above_cursor =
 9035                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9036            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9037
 9038            // Place the edit popover adjacent to the edit if there is a location
 9039            // available that is onscreen and does not obscure the cursor. Otherwise,
 9040            // place it adjacent to the cursor.
 9041            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9042                .into_iter()
 9043                .flatten()
 9044                .find(|&start_row| {
 9045                    let end_row = start_row + line_count as u32;
 9046                    visible_row_range.contains(&start_row)
 9047                        && visible_row_range.contains(&end_row)
 9048                        && cursor_row
 9049                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9050                })?;
 9051
 9052            content_origin
 9053                + point(
 9054                    -scroll_pixel_position.x,
 9055                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9056                )
 9057        };
 9058
 9059        origin.x -= BORDER_WIDTH;
 9060
 9061        window.defer_draw(element, origin, 1);
 9062
 9063        // Do not return an element, since it will already be drawn due to defer_draw.
 9064        None
 9065    }
 9066
 9067    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9068        px(30.)
 9069    }
 9070
 9071    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9072        if self.read_only(cx) {
 9073            cx.theme().players().read_only()
 9074        } else {
 9075            self.style.as_ref().unwrap().local_player
 9076        }
 9077    }
 9078
 9079    fn render_edit_prediction_accept_keybind(
 9080        &self,
 9081        window: &mut Window,
 9082        cx: &App,
 9083    ) -> Option<AnyElement> {
 9084        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9085        let accept_keystroke = accept_binding.keystroke()?;
 9086
 9087        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9088
 9089        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9090            Color::Accent
 9091        } else {
 9092            Color::Muted
 9093        };
 9094
 9095        h_flex()
 9096            .px_0p5()
 9097            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9098            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9099            .text_size(TextSize::XSmall.rems(cx))
 9100            .child(h_flex().children(ui::render_modifiers(
 9101                accept_keystroke.modifiers(),
 9102                PlatformStyle::platform(),
 9103                Some(modifiers_color),
 9104                Some(IconSize::XSmall.rems().into()),
 9105                true,
 9106            )))
 9107            .when(is_platform_style_mac, |parent| {
 9108                parent.child(accept_keystroke.key().to_string())
 9109            })
 9110            .when(!is_platform_style_mac, |parent| {
 9111                parent.child(
 9112                    Key::new(
 9113                        util::capitalize(accept_keystroke.key()),
 9114                        Some(Color::Default),
 9115                    )
 9116                    .size(Some(IconSize::XSmall.rems().into())),
 9117                )
 9118            })
 9119            .into_any()
 9120            .into()
 9121    }
 9122
 9123    fn render_edit_prediction_line_popover(
 9124        &self,
 9125        label: impl Into<SharedString>,
 9126        icon: Option<IconName>,
 9127        window: &mut Window,
 9128        cx: &App,
 9129    ) -> Option<Stateful<Div>> {
 9130        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9131
 9132        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9133        let has_keybind = keybind.is_some();
 9134
 9135        let result = h_flex()
 9136            .id("ep-line-popover")
 9137            .py_0p5()
 9138            .pl_1()
 9139            .pr(padding_right)
 9140            .gap_1()
 9141            .rounded_md()
 9142            .border_1()
 9143            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9144            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9145            .shadow_xs()
 9146            .when(!has_keybind, |el| {
 9147                let status_colors = cx.theme().status();
 9148
 9149                el.bg(status_colors.error_background)
 9150                    .border_color(status_colors.error.opacity(0.6))
 9151                    .pl_2()
 9152                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9153                    .cursor_default()
 9154                    .hoverable_tooltip(move |_window, cx| {
 9155                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9156                    })
 9157            })
 9158            .children(keybind)
 9159            .child(
 9160                Label::new(label)
 9161                    .size(LabelSize::Small)
 9162                    .when(!has_keybind, |el| {
 9163                        el.color(cx.theme().status().error.into()).strikethrough()
 9164                    }),
 9165            )
 9166            .when(!has_keybind, |el| {
 9167                el.child(
 9168                    h_flex().ml_1().child(
 9169                        Icon::new(IconName::Info)
 9170                            .size(IconSize::Small)
 9171                            .color(cx.theme().status().error.into()),
 9172                    ),
 9173                )
 9174            })
 9175            .when_some(icon, |element, icon| {
 9176                element.child(
 9177                    div()
 9178                        .mt(px(1.5))
 9179                        .child(Icon::new(icon).size(IconSize::Small)),
 9180                )
 9181            });
 9182
 9183        Some(result)
 9184    }
 9185
 9186    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9187        let accent_color = cx.theme().colors().text_accent;
 9188        let editor_bg_color = cx.theme().colors().editor_background;
 9189        editor_bg_color.blend(accent_color.opacity(0.1))
 9190    }
 9191
 9192    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9193        let accent_color = cx.theme().colors().text_accent;
 9194        let editor_bg_color = cx.theme().colors().editor_background;
 9195        editor_bg_color.blend(accent_color.opacity(0.6))
 9196    }
 9197    fn get_prediction_provider_icon_name(
 9198        provider: &Option<RegisteredEditPredictionProvider>,
 9199    ) -> IconName {
 9200        match provider {
 9201            Some(provider) => match provider.provider.name() {
 9202                "copilot" => IconName::Copilot,
 9203                "supermaven" => IconName::Supermaven,
 9204                _ => IconName::ZedPredict,
 9205            },
 9206            None => IconName::ZedPredict,
 9207        }
 9208    }
 9209
 9210    fn render_edit_prediction_cursor_popover(
 9211        &self,
 9212        min_width: Pixels,
 9213        max_width: Pixels,
 9214        cursor_point: Point,
 9215        style: &EditorStyle,
 9216        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9217        _window: &Window,
 9218        cx: &mut Context<Editor>,
 9219    ) -> Option<AnyElement> {
 9220        let provider = self.edit_prediction_provider.as_ref()?;
 9221        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9222
 9223        let is_refreshing = provider.provider.is_refreshing(cx);
 9224
 9225        fn pending_completion_container(icon: IconName) -> Div {
 9226            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9227        }
 9228
 9229        let completion = match &self.active_edit_prediction {
 9230            Some(prediction) => {
 9231                if !self.has_visible_completions_menu() {
 9232                    const RADIUS: Pixels = px(6.);
 9233                    const BORDER_WIDTH: Pixels = px(1.);
 9234
 9235                    return Some(
 9236                        h_flex()
 9237                            .elevation_2(cx)
 9238                            .border(BORDER_WIDTH)
 9239                            .border_color(cx.theme().colors().border)
 9240                            .when(accept_keystroke.is_none(), |el| {
 9241                                el.border_color(cx.theme().status().error)
 9242                            })
 9243                            .rounded(RADIUS)
 9244                            .rounded_tl(px(0.))
 9245                            .overflow_hidden()
 9246                            .child(div().px_1p5().child(match &prediction.completion {
 9247                                EditPrediction::Move { target, snapshot } => {
 9248                                    use text::ToPoint as _;
 9249                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9250                                    {
 9251                                        Icon::new(IconName::ZedPredictDown)
 9252                                    } else {
 9253                                        Icon::new(IconName::ZedPredictUp)
 9254                                    }
 9255                                }
 9256                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9257                            }))
 9258                            .child(
 9259                                h_flex()
 9260                                    .gap_1()
 9261                                    .py_1()
 9262                                    .px_2()
 9263                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9264                                    .border_l_1()
 9265                                    .border_color(cx.theme().colors().border)
 9266                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9267                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9268                                        el.child(
 9269                                            Label::new("Hold")
 9270                                                .size(LabelSize::Small)
 9271                                                .when(accept_keystroke.is_none(), |el| {
 9272                                                    el.strikethrough()
 9273                                                })
 9274                                                .line_height_style(LineHeightStyle::UiLabel),
 9275                                        )
 9276                                    })
 9277                                    .id("edit_prediction_cursor_popover_keybind")
 9278                                    .when(accept_keystroke.is_none(), |el| {
 9279                                        let status_colors = cx.theme().status();
 9280
 9281                                        el.bg(status_colors.error_background)
 9282                                            .border_color(status_colors.error.opacity(0.6))
 9283                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9284                                            .cursor_default()
 9285                                            .hoverable_tooltip(move |_window, cx| {
 9286                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9287                                                    .into()
 9288                                            })
 9289                                    })
 9290                                    .when_some(
 9291                                        accept_keystroke.as_ref(),
 9292                                        |el, accept_keystroke| {
 9293                                            el.child(h_flex().children(ui::render_modifiers(
 9294                                                accept_keystroke.modifiers(),
 9295                                                PlatformStyle::platform(),
 9296                                                Some(Color::Default),
 9297                                                Some(IconSize::XSmall.rems().into()),
 9298                                                false,
 9299                                            )))
 9300                                        },
 9301                                    ),
 9302                            )
 9303                            .into_any(),
 9304                    );
 9305                }
 9306
 9307                self.render_edit_prediction_cursor_popover_preview(
 9308                    prediction,
 9309                    cursor_point,
 9310                    style,
 9311                    cx,
 9312                )?
 9313            }
 9314
 9315            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9316                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9317                    stale_completion,
 9318                    cursor_point,
 9319                    style,
 9320                    cx,
 9321                )?,
 9322
 9323                None => pending_completion_container(provider_icon)
 9324                    .child(Label::new("...").size(LabelSize::Small)),
 9325            },
 9326
 9327            None => pending_completion_container(provider_icon)
 9328                .child(Label::new("...").size(LabelSize::Small)),
 9329        };
 9330
 9331        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9332            completion
 9333                .with_animation(
 9334                    "loading-completion",
 9335                    Animation::new(Duration::from_secs(2))
 9336                        .repeat()
 9337                        .with_easing(pulsating_between(0.4, 0.8)),
 9338                    |label, delta| label.opacity(delta),
 9339                )
 9340                .into_any_element()
 9341        } else {
 9342            completion.into_any_element()
 9343        };
 9344
 9345        let has_completion = self.active_edit_prediction.is_some();
 9346
 9347        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9348        Some(
 9349            h_flex()
 9350                .min_w(min_width)
 9351                .max_w(max_width)
 9352                .flex_1()
 9353                .elevation_2(cx)
 9354                .border_color(cx.theme().colors().border)
 9355                .child(
 9356                    div()
 9357                        .flex_1()
 9358                        .py_1()
 9359                        .px_2()
 9360                        .overflow_hidden()
 9361                        .child(completion),
 9362                )
 9363                .when_some(accept_keystroke, |el, accept_keystroke| {
 9364                    if !accept_keystroke.modifiers().modified() {
 9365                        return el;
 9366                    }
 9367
 9368                    el.child(
 9369                        h_flex()
 9370                            .h_full()
 9371                            .border_l_1()
 9372                            .rounded_r_lg()
 9373                            .border_color(cx.theme().colors().border)
 9374                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9375                            .gap_1()
 9376                            .py_1()
 9377                            .px_2()
 9378                            .child(
 9379                                h_flex()
 9380                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9381                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9382                                    .child(h_flex().children(ui::render_modifiers(
 9383                                        accept_keystroke.modifiers(),
 9384                                        PlatformStyle::platform(),
 9385                                        Some(if !has_completion {
 9386                                            Color::Muted
 9387                                        } else {
 9388                                            Color::Default
 9389                                        }),
 9390                                        None,
 9391                                        false,
 9392                                    ))),
 9393                            )
 9394                            .child(Label::new("Preview").into_any_element())
 9395                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9396                    )
 9397                })
 9398                .into_any(),
 9399        )
 9400    }
 9401
 9402    fn render_edit_prediction_cursor_popover_preview(
 9403        &self,
 9404        completion: &EditPredictionState,
 9405        cursor_point: Point,
 9406        style: &EditorStyle,
 9407        cx: &mut Context<Editor>,
 9408    ) -> Option<Div> {
 9409        use text::ToPoint as _;
 9410
 9411        fn render_relative_row_jump(
 9412            prefix: impl Into<String>,
 9413            current_row: u32,
 9414            target_row: u32,
 9415        ) -> Div {
 9416            let (row_diff, arrow) = if target_row < current_row {
 9417                (current_row - target_row, IconName::ArrowUp)
 9418            } else {
 9419                (target_row - current_row, IconName::ArrowDown)
 9420            };
 9421
 9422            h_flex()
 9423                .child(
 9424                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9425                        .color(Color::Muted)
 9426                        .size(LabelSize::Small),
 9427                )
 9428                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9429        }
 9430
 9431        let supports_jump = self
 9432            .edit_prediction_provider
 9433            .as_ref()
 9434            .map(|provider| provider.provider.supports_jump_to_edit())
 9435            .unwrap_or(true);
 9436
 9437        match &completion.completion {
 9438            EditPrediction::Move {
 9439                target, snapshot, ..
 9440            } => {
 9441                if !supports_jump {
 9442                    return None;
 9443                }
 9444
 9445                Some(
 9446                    h_flex()
 9447                        .px_2()
 9448                        .gap_2()
 9449                        .flex_1()
 9450                        .child(
 9451                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9452                                Icon::new(IconName::ZedPredictDown)
 9453                            } else {
 9454                                Icon::new(IconName::ZedPredictUp)
 9455                            },
 9456                        )
 9457                        .child(Label::new("Jump to Edit")),
 9458                )
 9459            }
 9460
 9461            EditPrediction::Edit {
 9462                edits,
 9463                edit_preview,
 9464                snapshot,
 9465                display_mode: _,
 9466            } => {
 9467                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9468
 9469                let (highlighted_edits, has_more_lines) =
 9470                    if let Some(edit_preview) = edit_preview.as_ref() {
 9471                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9472                            .first_line_preview()
 9473                    } else {
 9474                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9475                    };
 9476
 9477                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9478                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9479
 9480                let preview = h_flex()
 9481                    .gap_1()
 9482                    .min_w_16()
 9483                    .child(styled_text)
 9484                    .when(has_more_lines, |parent| parent.child(""));
 9485
 9486                let left = if supports_jump && first_edit_row != cursor_point.row {
 9487                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9488                        .into_any_element()
 9489                } else {
 9490                    let icon_name =
 9491                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9492                    Icon::new(icon_name).into_any_element()
 9493                };
 9494
 9495                Some(
 9496                    h_flex()
 9497                        .h_full()
 9498                        .flex_1()
 9499                        .gap_2()
 9500                        .pr_1()
 9501                        .overflow_x_hidden()
 9502                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9503                        .child(left)
 9504                        .child(preview),
 9505                )
 9506            }
 9507        }
 9508    }
 9509
 9510    pub fn render_context_menu(
 9511        &self,
 9512        style: &EditorStyle,
 9513        max_height_in_lines: u32,
 9514        window: &mut Window,
 9515        cx: &mut Context<Editor>,
 9516    ) -> Option<AnyElement> {
 9517        let menu = self.context_menu.borrow();
 9518        let menu = menu.as_ref()?;
 9519        if !menu.visible() {
 9520            return None;
 9521        };
 9522        Some(menu.render(style, max_height_in_lines, window, cx))
 9523    }
 9524
 9525    fn render_context_menu_aside(
 9526        &mut self,
 9527        max_size: Size<Pixels>,
 9528        window: &mut Window,
 9529        cx: &mut Context<Editor>,
 9530    ) -> Option<AnyElement> {
 9531        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9532            if menu.visible() {
 9533                menu.render_aside(max_size, window, cx)
 9534            } else {
 9535                None
 9536            }
 9537        })
 9538    }
 9539
 9540    fn hide_context_menu(
 9541        &mut self,
 9542        window: &mut Window,
 9543        cx: &mut Context<Self>,
 9544    ) -> Option<CodeContextMenu> {
 9545        cx.notify();
 9546        self.completion_tasks.clear();
 9547        let context_menu = self.context_menu.borrow_mut().take();
 9548        self.stale_edit_prediction_in_menu.take();
 9549        self.update_visible_edit_prediction(window, cx);
 9550        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9551            && let Some(completion_provider) = &self.completion_provider
 9552        {
 9553            completion_provider.selection_changed(None, window, cx);
 9554        }
 9555        context_menu
 9556    }
 9557
 9558    fn show_snippet_choices(
 9559        &mut self,
 9560        choices: &Vec<String>,
 9561        selection: Range<Anchor>,
 9562        cx: &mut Context<Self>,
 9563    ) {
 9564        let Some((_, buffer, _)) = self
 9565            .buffer()
 9566            .read(cx)
 9567            .excerpt_containing(selection.start, cx)
 9568        else {
 9569            return;
 9570        };
 9571        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9572        else {
 9573            return;
 9574        };
 9575        if buffer != end_buffer {
 9576            log::error!("expected anchor range to have matching buffer IDs");
 9577            return;
 9578        }
 9579
 9580        let id = post_inc(&mut self.next_completion_id);
 9581        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9582        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9583            CompletionsMenu::new_snippet_choices(
 9584                id,
 9585                true,
 9586                choices,
 9587                selection,
 9588                buffer,
 9589                snippet_sort_order,
 9590            ),
 9591        ));
 9592    }
 9593
 9594    pub fn insert_snippet(
 9595        &mut self,
 9596        insertion_ranges: &[Range<usize>],
 9597        snippet: Snippet,
 9598        window: &mut Window,
 9599        cx: &mut Context<Self>,
 9600    ) -> Result<()> {
 9601        struct Tabstop<T> {
 9602            is_end_tabstop: bool,
 9603            ranges: Vec<Range<T>>,
 9604            choices: Option<Vec<String>>,
 9605        }
 9606
 9607        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9608            let snippet_text: Arc<str> = snippet.text.clone().into();
 9609            let edits = insertion_ranges
 9610                .iter()
 9611                .cloned()
 9612                .map(|range| (range, snippet_text.clone()));
 9613            let autoindent_mode = AutoindentMode::Block {
 9614                original_indent_columns: Vec::new(),
 9615            };
 9616            buffer.edit(edits, Some(autoindent_mode), cx);
 9617
 9618            let snapshot = &*buffer.read(cx);
 9619            let snippet = &snippet;
 9620            snippet
 9621                .tabstops
 9622                .iter()
 9623                .map(|tabstop| {
 9624                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9625                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9626                    });
 9627                    let mut tabstop_ranges = tabstop
 9628                        .ranges
 9629                        .iter()
 9630                        .flat_map(|tabstop_range| {
 9631                            let mut delta = 0_isize;
 9632                            insertion_ranges.iter().map(move |insertion_range| {
 9633                                let insertion_start = insertion_range.start as isize + delta;
 9634                                delta +=
 9635                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9636
 9637                                let start = ((insertion_start + tabstop_range.start) as usize)
 9638                                    .min(snapshot.len());
 9639                                let end = ((insertion_start + tabstop_range.end) as usize)
 9640                                    .min(snapshot.len());
 9641                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9642                            })
 9643                        })
 9644                        .collect::<Vec<_>>();
 9645                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9646
 9647                    Tabstop {
 9648                        is_end_tabstop,
 9649                        ranges: tabstop_ranges,
 9650                        choices: tabstop.choices.clone(),
 9651                    }
 9652                })
 9653                .collect::<Vec<_>>()
 9654        });
 9655        if let Some(tabstop) = tabstops.first() {
 9656            self.change_selections(Default::default(), window, cx, |s| {
 9657                // Reverse order so that the first range is the newest created selection.
 9658                // Completions will use it and autoscroll will prioritize it.
 9659                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9660            });
 9661
 9662            if let Some(choices) = &tabstop.choices
 9663                && let Some(selection) = tabstop.ranges.first()
 9664            {
 9665                self.show_snippet_choices(choices, selection.clone(), cx)
 9666            }
 9667
 9668            // If we're already at the last tabstop and it's at the end of the snippet,
 9669            // we're done, we don't need to keep the state around.
 9670            if !tabstop.is_end_tabstop {
 9671                let choices = tabstops
 9672                    .iter()
 9673                    .map(|tabstop| tabstop.choices.clone())
 9674                    .collect();
 9675
 9676                let ranges = tabstops
 9677                    .into_iter()
 9678                    .map(|tabstop| tabstop.ranges)
 9679                    .collect::<Vec<_>>();
 9680
 9681                self.snippet_stack.push(SnippetState {
 9682                    active_index: 0,
 9683                    ranges,
 9684                    choices,
 9685                });
 9686            }
 9687
 9688            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9689            if self.autoclose_regions.is_empty() {
 9690                let snapshot = self.buffer.read(cx).snapshot(cx);
 9691                let mut all_selections = self.selections.all::<Point>(cx);
 9692                for selection in &mut all_selections {
 9693                    let selection_head = selection.head();
 9694                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9695                        continue;
 9696                    };
 9697
 9698                    let mut bracket_pair = None;
 9699                    let max_lookup_length = scope
 9700                        .brackets()
 9701                        .map(|(pair, _)| {
 9702                            pair.start
 9703                                .as_str()
 9704                                .chars()
 9705                                .count()
 9706                                .max(pair.end.as_str().chars().count())
 9707                        })
 9708                        .max();
 9709                    if let Some(max_lookup_length) = max_lookup_length {
 9710                        let next_text = snapshot
 9711                            .chars_at(selection_head)
 9712                            .take(max_lookup_length)
 9713                            .collect::<String>();
 9714                        let prev_text = snapshot
 9715                            .reversed_chars_at(selection_head)
 9716                            .take(max_lookup_length)
 9717                            .collect::<String>();
 9718
 9719                        for (pair, enabled) in scope.brackets() {
 9720                            if enabled
 9721                                && pair.close
 9722                                && prev_text.starts_with(pair.start.as_str())
 9723                                && next_text.starts_with(pair.end.as_str())
 9724                            {
 9725                                bracket_pair = Some(pair.clone());
 9726                                break;
 9727                            }
 9728                        }
 9729                    }
 9730
 9731                    if let Some(pair) = bracket_pair {
 9732                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9733                        let autoclose_enabled =
 9734                            self.use_autoclose && snapshot_settings.use_autoclose;
 9735                        if autoclose_enabled {
 9736                            let start = snapshot.anchor_after(selection_head);
 9737                            let end = snapshot.anchor_after(selection_head);
 9738                            self.autoclose_regions.push(AutocloseRegion {
 9739                                selection_id: selection.id,
 9740                                range: start..end,
 9741                                pair,
 9742                            });
 9743                        }
 9744                    }
 9745                }
 9746            }
 9747        }
 9748        Ok(())
 9749    }
 9750
 9751    pub fn move_to_next_snippet_tabstop(
 9752        &mut self,
 9753        window: &mut Window,
 9754        cx: &mut Context<Self>,
 9755    ) -> bool {
 9756        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9757    }
 9758
 9759    pub fn move_to_prev_snippet_tabstop(
 9760        &mut self,
 9761        window: &mut Window,
 9762        cx: &mut Context<Self>,
 9763    ) -> bool {
 9764        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9765    }
 9766
 9767    pub fn move_to_snippet_tabstop(
 9768        &mut self,
 9769        bias: Bias,
 9770        window: &mut Window,
 9771        cx: &mut Context<Self>,
 9772    ) -> bool {
 9773        if let Some(mut snippet) = self.snippet_stack.pop() {
 9774            match bias {
 9775                Bias::Left => {
 9776                    if snippet.active_index > 0 {
 9777                        snippet.active_index -= 1;
 9778                    } else {
 9779                        self.snippet_stack.push(snippet);
 9780                        return false;
 9781                    }
 9782                }
 9783                Bias::Right => {
 9784                    if snippet.active_index + 1 < snippet.ranges.len() {
 9785                        snippet.active_index += 1;
 9786                    } else {
 9787                        self.snippet_stack.push(snippet);
 9788                        return false;
 9789                    }
 9790                }
 9791            }
 9792            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9793                self.change_selections(Default::default(), window, cx, |s| {
 9794                    // Reverse order so that the first range is the newest created selection.
 9795                    // Completions will use it and autoscroll will prioritize it.
 9796                    s.select_ranges(current_ranges.iter().rev().cloned())
 9797                });
 9798
 9799                if let Some(choices) = &snippet.choices[snippet.active_index]
 9800                    && let Some(selection) = current_ranges.first()
 9801                {
 9802                    self.show_snippet_choices(choices, selection.clone(), cx);
 9803                }
 9804
 9805                // If snippet state is not at the last tabstop, push it back on the stack
 9806                if snippet.active_index + 1 < snippet.ranges.len() {
 9807                    self.snippet_stack.push(snippet);
 9808                }
 9809                return true;
 9810            }
 9811        }
 9812
 9813        false
 9814    }
 9815
 9816    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9817        self.transact(window, cx, |this, window, cx| {
 9818            this.select_all(&SelectAll, window, cx);
 9819            this.insert("", window, cx);
 9820        });
 9821    }
 9822
 9823    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9824        if self.read_only(cx) {
 9825            return;
 9826        }
 9827        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9828        self.transact(window, cx, |this, window, cx| {
 9829            this.select_autoclose_pair(window, cx);
 9830            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9831            if !this.linked_edit_ranges.is_empty() {
 9832                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9833                let snapshot = this.buffer.read(cx).snapshot(cx);
 9834
 9835                for selection in selections.iter() {
 9836                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9837                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9838                    if selection_start.buffer_id != selection_end.buffer_id {
 9839                        continue;
 9840                    }
 9841                    if let Some(ranges) =
 9842                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9843                    {
 9844                        for (buffer, entries) in ranges {
 9845                            linked_ranges.entry(buffer).or_default().extend(entries);
 9846                        }
 9847                    }
 9848                }
 9849            }
 9850
 9851            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9852            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9853            for selection in &mut selections {
 9854                if selection.is_empty() {
 9855                    let old_head = selection.head();
 9856                    let mut new_head =
 9857                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9858                            .to_point(&display_map);
 9859                    if let Some((buffer, line_buffer_range)) = display_map
 9860                        .buffer_snapshot
 9861                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9862                    {
 9863                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9864                        let indent_len = match indent_size.kind {
 9865                            IndentKind::Space => {
 9866                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9867                            }
 9868                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9869                        };
 9870                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9871                            let indent_len = indent_len.get();
 9872                            new_head = cmp::min(
 9873                                new_head,
 9874                                MultiBufferPoint::new(
 9875                                    old_head.row,
 9876                                    ((old_head.column - 1) / indent_len) * indent_len,
 9877                                ),
 9878                            );
 9879                        }
 9880                    }
 9881
 9882                    selection.set_head(new_head, SelectionGoal::None);
 9883                }
 9884            }
 9885
 9886            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9887            this.insert("", window, cx);
 9888            let empty_str: Arc<str> = Arc::from("");
 9889            for (buffer, edits) in linked_ranges {
 9890                let snapshot = buffer.read(cx).snapshot();
 9891                use text::ToPoint as TP;
 9892
 9893                let edits = edits
 9894                    .into_iter()
 9895                    .map(|range| {
 9896                        let end_point = TP::to_point(&range.end, &snapshot);
 9897                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9898
 9899                        if end_point == start_point {
 9900                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9901                                .saturating_sub(1);
 9902                            start_point =
 9903                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9904                        };
 9905
 9906                        (start_point..end_point, empty_str.clone())
 9907                    })
 9908                    .sorted_by_key(|(range, _)| range.start)
 9909                    .collect::<Vec<_>>();
 9910                buffer.update(cx, |this, cx| {
 9911                    this.edit(edits, None, cx);
 9912                })
 9913            }
 9914            this.refresh_edit_prediction(true, false, window, cx);
 9915            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9916        });
 9917    }
 9918
 9919    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9920        if self.read_only(cx) {
 9921            return;
 9922        }
 9923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9924        self.transact(window, cx, |this, window, cx| {
 9925            this.change_selections(Default::default(), window, cx, |s| {
 9926                s.move_with(|map, selection| {
 9927                    if selection.is_empty() {
 9928                        let cursor = movement::right(map, selection.head());
 9929                        selection.end = cursor;
 9930                        selection.reversed = true;
 9931                        selection.goal = SelectionGoal::None;
 9932                    }
 9933                })
 9934            });
 9935            this.insert("", window, cx);
 9936            this.refresh_edit_prediction(true, false, window, cx);
 9937        });
 9938    }
 9939
 9940    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9941        if self.mode.is_single_line() {
 9942            cx.propagate();
 9943            return;
 9944        }
 9945
 9946        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9947        if self.move_to_prev_snippet_tabstop(window, cx) {
 9948            return;
 9949        }
 9950        self.outdent(&Outdent, window, cx);
 9951    }
 9952
 9953    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9954        if self.mode.is_single_line() {
 9955            cx.propagate();
 9956            return;
 9957        }
 9958
 9959        if self.move_to_next_snippet_tabstop(window, cx) {
 9960            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9961            return;
 9962        }
 9963        if self.read_only(cx) {
 9964            return;
 9965        }
 9966        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9967        let mut selections = self.selections.all_adjusted(cx);
 9968        let buffer = self.buffer.read(cx);
 9969        let snapshot = buffer.snapshot(cx);
 9970        let rows_iter = selections.iter().map(|s| s.head().row);
 9971        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9972
 9973        let has_some_cursor_in_whitespace = selections
 9974            .iter()
 9975            .filter(|selection| selection.is_empty())
 9976            .any(|selection| {
 9977                let cursor = selection.head();
 9978                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9979                cursor.column < current_indent.len
 9980            });
 9981
 9982        let mut edits = Vec::new();
 9983        let mut prev_edited_row = 0;
 9984        let mut row_delta = 0;
 9985        for selection in &mut selections {
 9986            if selection.start.row != prev_edited_row {
 9987                row_delta = 0;
 9988            }
 9989            prev_edited_row = selection.end.row;
 9990
 9991            // If the selection is non-empty, then increase the indentation of the selected lines.
 9992            if !selection.is_empty() {
 9993                row_delta =
 9994                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9995                continue;
 9996            }
 9997
 9998            let cursor = selection.head();
 9999            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10000            if let Some(suggested_indent) =
10001                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10002            {
10003                // Don't do anything if already at suggested indent
10004                // and there is any other cursor which is not
10005                if has_some_cursor_in_whitespace
10006                    && cursor.column == current_indent.len
10007                    && current_indent.len == suggested_indent.len
10008                {
10009                    continue;
10010                }
10011
10012                // Adjust line and move cursor to suggested indent
10013                // if cursor is not at suggested indent
10014                if cursor.column < suggested_indent.len
10015                    && cursor.column <= current_indent.len
10016                    && current_indent.len <= suggested_indent.len
10017                {
10018                    selection.start = Point::new(cursor.row, suggested_indent.len);
10019                    selection.end = selection.start;
10020                    if row_delta == 0 {
10021                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10022                            cursor.row,
10023                            current_indent,
10024                            suggested_indent,
10025                        ));
10026                        row_delta = suggested_indent.len - current_indent.len;
10027                    }
10028                    continue;
10029                }
10030
10031                // If current indent is more than suggested indent
10032                // only move cursor to current indent and skip indent
10033                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10034                    selection.start = Point::new(cursor.row, current_indent.len);
10035                    selection.end = selection.start;
10036                    continue;
10037                }
10038            }
10039
10040            // Otherwise, insert a hard or soft tab.
10041            let settings = buffer.language_settings_at(cursor, cx);
10042            let tab_size = if settings.hard_tabs {
10043                IndentSize::tab()
10044            } else {
10045                let tab_size = settings.tab_size.get();
10046                let indent_remainder = snapshot
10047                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10048                    .flat_map(str::chars)
10049                    .fold(row_delta % tab_size, |counter: u32, c| {
10050                        if c == '\t' {
10051                            0
10052                        } else {
10053                            (counter + 1) % tab_size
10054                        }
10055                    });
10056
10057                let chars_to_next_tab_stop = tab_size - indent_remainder;
10058                IndentSize::spaces(chars_to_next_tab_stop)
10059            };
10060            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10061            selection.end = selection.start;
10062            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10063            row_delta += tab_size.len;
10064        }
10065
10066        self.transact(window, cx, |this, window, cx| {
10067            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10068            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10069            this.refresh_edit_prediction(true, false, window, cx);
10070        });
10071    }
10072
10073    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10074        if self.read_only(cx) {
10075            return;
10076        }
10077        if self.mode.is_single_line() {
10078            cx.propagate();
10079            return;
10080        }
10081
10082        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10083        let mut selections = self.selections.all::<Point>(cx);
10084        let mut prev_edited_row = 0;
10085        let mut row_delta = 0;
10086        let mut edits = Vec::new();
10087        let buffer = self.buffer.read(cx);
10088        let snapshot = buffer.snapshot(cx);
10089        for selection in &mut selections {
10090            if selection.start.row != prev_edited_row {
10091                row_delta = 0;
10092            }
10093            prev_edited_row = selection.end.row;
10094
10095            row_delta =
10096                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10097        }
10098
10099        self.transact(window, cx, |this, window, cx| {
10100            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10101            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10102        });
10103    }
10104
10105    fn indent_selection(
10106        buffer: &MultiBuffer,
10107        snapshot: &MultiBufferSnapshot,
10108        selection: &mut Selection<Point>,
10109        edits: &mut Vec<(Range<Point>, String)>,
10110        delta_for_start_row: u32,
10111        cx: &App,
10112    ) -> u32 {
10113        let settings = buffer.language_settings_at(selection.start, cx);
10114        let tab_size = settings.tab_size.get();
10115        let indent_kind = if settings.hard_tabs {
10116            IndentKind::Tab
10117        } else {
10118            IndentKind::Space
10119        };
10120        let mut start_row = selection.start.row;
10121        let mut end_row = selection.end.row + 1;
10122
10123        // If a selection ends at the beginning of a line, don't indent
10124        // that last line.
10125        if selection.end.column == 0 && selection.end.row > selection.start.row {
10126            end_row -= 1;
10127        }
10128
10129        // Avoid re-indenting a row that has already been indented by a
10130        // previous selection, but still update this selection's column
10131        // to reflect that indentation.
10132        if delta_for_start_row > 0 {
10133            start_row += 1;
10134            selection.start.column += delta_for_start_row;
10135            if selection.end.row == selection.start.row {
10136                selection.end.column += delta_for_start_row;
10137            }
10138        }
10139
10140        let mut delta_for_end_row = 0;
10141        let has_multiple_rows = start_row + 1 != end_row;
10142        for row in start_row..end_row {
10143            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10144            let indent_delta = match (current_indent.kind, indent_kind) {
10145                (IndentKind::Space, IndentKind::Space) => {
10146                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10147                    IndentSize::spaces(columns_to_next_tab_stop)
10148                }
10149                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10150                (_, IndentKind::Tab) => IndentSize::tab(),
10151            };
10152
10153            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10154                0
10155            } else {
10156                selection.start.column
10157            };
10158            let row_start = Point::new(row, start);
10159            edits.push((
10160                row_start..row_start,
10161                indent_delta.chars().collect::<String>(),
10162            ));
10163
10164            // Update this selection's endpoints to reflect the indentation.
10165            if row == selection.start.row {
10166                selection.start.column += indent_delta.len;
10167            }
10168            if row == selection.end.row {
10169                selection.end.column += indent_delta.len;
10170                delta_for_end_row = indent_delta.len;
10171            }
10172        }
10173
10174        if selection.start.row == selection.end.row {
10175            delta_for_start_row + delta_for_end_row
10176        } else {
10177            delta_for_end_row
10178        }
10179    }
10180
10181    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10182        if self.read_only(cx) {
10183            return;
10184        }
10185        if self.mode.is_single_line() {
10186            cx.propagate();
10187            return;
10188        }
10189
10190        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10191        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10192        let selections = self.selections.all::<Point>(cx);
10193        let mut deletion_ranges = Vec::new();
10194        let mut last_outdent = None;
10195        {
10196            let buffer = self.buffer.read(cx);
10197            let snapshot = buffer.snapshot(cx);
10198            for selection in &selections {
10199                let settings = buffer.language_settings_at(selection.start, cx);
10200                let tab_size = settings.tab_size.get();
10201                let mut rows = selection.spanned_rows(false, &display_map);
10202
10203                // Avoid re-outdenting a row that has already been outdented by a
10204                // previous selection.
10205                if let Some(last_row) = last_outdent
10206                    && last_row == rows.start
10207                {
10208                    rows.start = rows.start.next_row();
10209                }
10210                let has_multiple_rows = rows.len() > 1;
10211                for row in rows.iter_rows() {
10212                    let indent_size = snapshot.indent_size_for_line(row);
10213                    if indent_size.len > 0 {
10214                        let deletion_len = match indent_size.kind {
10215                            IndentKind::Space => {
10216                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10217                                if columns_to_prev_tab_stop == 0 {
10218                                    tab_size
10219                                } else {
10220                                    columns_to_prev_tab_stop
10221                                }
10222                            }
10223                            IndentKind::Tab => 1,
10224                        };
10225                        let start = if has_multiple_rows
10226                            || deletion_len > selection.start.column
10227                            || indent_size.len < selection.start.column
10228                        {
10229                            0
10230                        } else {
10231                            selection.start.column - deletion_len
10232                        };
10233                        deletion_ranges.push(
10234                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10235                        );
10236                        last_outdent = Some(row);
10237                    }
10238                }
10239            }
10240        }
10241
10242        self.transact(window, cx, |this, window, cx| {
10243            this.buffer.update(cx, |buffer, cx| {
10244                let empty_str: Arc<str> = Arc::default();
10245                buffer.edit(
10246                    deletion_ranges
10247                        .into_iter()
10248                        .map(|range| (range, empty_str.clone())),
10249                    None,
10250                    cx,
10251                );
10252            });
10253            let selections = this.selections.all::<usize>(cx);
10254            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10255        });
10256    }
10257
10258    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10259        if self.read_only(cx) {
10260            return;
10261        }
10262        if self.mode.is_single_line() {
10263            cx.propagate();
10264            return;
10265        }
10266
10267        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10268        let selections = self
10269            .selections
10270            .all::<usize>(cx)
10271            .into_iter()
10272            .map(|s| s.range());
10273
10274        self.transact(window, cx, |this, window, cx| {
10275            this.buffer.update(cx, |buffer, cx| {
10276                buffer.autoindent_ranges(selections, cx);
10277            });
10278            let selections = this.selections.all::<usize>(cx);
10279            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10280        });
10281    }
10282
10283    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10284        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10285        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10286        let selections = self.selections.all::<Point>(cx);
10287
10288        let mut new_cursors = Vec::new();
10289        let mut edit_ranges = Vec::new();
10290        let mut selections = selections.iter().peekable();
10291        while let Some(selection) = selections.next() {
10292            let mut rows = selection.spanned_rows(false, &display_map);
10293            let goal_display_column = selection.head().to_display_point(&display_map).column();
10294
10295            // Accumulate contiguous regions of rows that we want to delete.
10296            while let Some(next_selection) = selections.peek() {
10297                let next_rows = next_selection.spanned_rows(false, &display_map);
10298                if next_rows.start <= rows.end {
10299                    rows.end = next_rows.end;
10300                    selections.next().unwrap();
10301                } else {
10302                    break;
10303                }
10304            }
10305
10306            let buffer = &display_map.buffer_snapshot;
10307            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10308            let edit_end;
10309            let cursor_buffer_row;
10310            if buffer.max_point().row >= rows.end.0 {
10311                // If there's a line after the range, delete the \n from the end of the row range
10312                // and position the cursor on the next line.
10313                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10314                cursor_buffer_row = rows.end;
10315            } else {
10316                // If there isn't a line after the range, delete the \n from the line before the
10317                // start of the row range and position the cursor there.
10318                edit_start = edit_start.saturating_sub(1);
10319                edit_end = buffer.len();
10320                cursor_buffer_row = rows.start.previous_row();
10321            }
10322
10323            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10324            *cursor.column_mut() =
10325                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10326
10327            new_cursors.push((
10328                selection.id,
10329                buffer.anchor_after(cursor.to_point(&display_map)),
10330            ));
10331            edit_ranges.push(edit_start..edit_end);
10332        }
10333
10334        self.transact(window, cx, |this, window, cx| {
10335            let buffer = this.buffer.update(cx, |buffer, cx| {
10336                let empty_str: Arc<str> = Arc::default();
10337                buffer.edit(
10338                    edit_ranges
10339                        .into_iter()
10340                        .map(|range| (range, empty_str.clone())),
10341                    None,
10342                    cx,
10343                );
10344                buffer.snapshot(cx)
10345            });
10346            let new_selections = new_cursors
10347                .into_iter()
10348                .map(|(id, cursor)| {
10349                    let cursor = cursor.to_point(&buffer);
10350                    Selection {
10351                        id,
10352                        start: cursor,
10353                        end: cursor,
10354                        reversed: false,
10355                        goal: SelectionGoal::None,
10356                    }
10357                })
10358                .collect();
10359
10360            this.change_selections(Default::default(), window, cx, |s| {
10361                s.select(new_selections);
10362            });
10363        });
10364    }
10365
10366    pub fn join_lines_impl(
10367        &mut self,
10368        insert_whitespace: bool,
10369        window: &mut Window,
10370        cx: &mut Context<Self>,
10371    ) {
10372        if self.read_only(cx) {
10373            return;
10374        }
10375        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10376        for selection in self.selections.all::<Point>(cx) {
10377            let start = MultiBufferRow(selection.start.row);
10378            // Treat single line selections as if they include the next line. Otherwise this action
10379            // would do nothing for single line selections individual cursors.
10380            let end = if selection.start.row == selection.end.row {
10381                MultiBufferRow(selection.start.row + 1)
10382            } else {
10383                MultiBufferRow(selection.end.row)
10384            };
10385
10386            if let Some(last_row_range) = row_ranges.last_mut()
10387                && start <= last_row_range.end
10388            {
10389                last_row_range.end = end;
10390                continue;
10391            }
10392            row_ranges.push(start..end);
10393        }
10394
10395        let snapshot = self.buffer.read(cx).snapshot(cx);
10396        let mut cursor_positions = Vec::new();
10397        for row_range in &row_ranges {
10398            let anchor = snapshot.anchor_before(Point::new(
10399                row_range.end.previous_row().0,
10400                snapshot.line_len(row_range.end.previous_row()),
10401            ));
10402            cursor_positions.push(anchor..anchor);
10403        }
10404
10405        self.transact(window, cx, |this, window, cx| {
10406            for row_range in row_ranges.into_iter().rev() {
10407                for row in row_range.iter_rows().rev() {
10408                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10409                    let next_line_row = row.next_row();
10410                    let indent = snapshot.indent_size_for_line(next_line_row);
10411                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10412
10413                    let replace =
10414                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10415                            " "
10416                        } else {
10417                            ""
10418                        };
10419
10420                    this.buffer.update(cx, |buffer, cx| {
10421                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10422                    });
10423                }
10424            }
10425
10426            this.change_selections(Default::default(), window, cx, |s| {
10427                s.select_anchor_ranges(cursor_positions)
10428            });
10429        });
10430    }
10431
10432    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10433        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10434        self.join_lines_impl(true, window, cx);
10435    }
10436
10437    pub fn sort_lines_case_sensitive(
10438        &mut self,
10439        _: &SortLinesCaseSensitive,
10440        window: &mut Window,
10441        cx: &mut Context<Self>,
10442    ) {
10443        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10444    }
10445
10446    pub fn sort_lines_by_length(
10447        &mut self,
10448        _: &SortLinesByLength,
10449        window: &mut Window,
10450        cx: &mut Context<Self>,
10451    ) {
10452        self.manipulate_immutable_lines(window, cx, |lines| {
10453            lines.sort_by_key(|&line| line.chars().count())
10454        })
10455    }
10456
10457    pub fn sort_lines_case_insensitive(
10458        &mut self,
10459        _: &SortLinesCaseInsensitive,
10460        window: &mut Window,
10461        cx: &mut Context<Self>,
10462    ) {
10463        self.manipulate_immutable_lines(window, cx, |lines| {
10464            lines.sort_by_key(|line| line.to_lowercase())
10465        })
10466    }
10467
10468    pub fn unique_lines_case_insensitive(
10469        &mut self,
10470        _: &UniqueLinesCaseInsensitive,
10471        window: &mut Window,
10472        cx: &mut Context<Self>,
10473    ) {
10474        self.manipulate_immutable_lines(window, cx, |lines| {
10475            let mut seen = HashSet::default();
10476            lines.retain(|line| seen.insert(line.to_lowercase()));
10477        })
10478    }
10479
10480    pub fn unique_lines_case_sensitive(
10481        &mut self,
10482        _: &UniqueLinesCaseSensitive,
10483        window: &mut Window,
10484        cx: &mut Context<Self>,
10485    ) {
10486        self.manipulate_immutable_lines(window, cx, |lines| {
10487            let mut seen = HashSet::default();
10488            lines.retain(|line| seen.insert(*line));
10489        })
10490    }
10491
10492    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10493        let snapshot = self.buffer.read(cx).snapshot(cx);
10494        for selection in self.selections.disjoint_anchors().iter() {
10495            if snapshot
10496                .language_at(selection.start)
10497                .and_then(|lang| lang.config().wrap_characters.as_ref())
10498                .is_some()
10499            {
10500                return true;
10501            }
10502        }
10503        false
10504    }
10505
10506    fn wrap_selections_in_tag(
10507        &mut self,
10508        _: &WrapSelectionsInTag,
10509        window: &mut Window,
10510        cx: &mut Context<Self>,
10511    ) {
10512        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10513
10514        let snapshot = self.buffer.read(cx).snapshot(cx);
10515
10516        let mut edits = Vec::new();
10517        let mut boundaries = Vec::new();
10518
10519        for selection in self.selections.all::<Point>(cx).iter() {
10520            let Some(wrap_config) = snapshot
10521                .language_at(selection.start)
10522                .and_then(|lang| lang.config().wrap_characters.clone())
10523            else {
10524                continue;
10525            };
10526
10527            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10528            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10529
10530            let start_before = snapshot.anchor_before(selection.start);
10531            let end_after = snapshot.anchor_after(selection.end);
10532
10533            edits.push((start_before..start_before, open_tag));
10534            edits.push((end_after..end_after, close_tag));
10535
10536            boundaries.push((
10537                start_before,
10538                end_after,
10539                wrap_config.start_prefix.len(),
10540                wrap_config.end_suffix.len(),
10541            ));
10542        }
10543
10544        if edits.is_empty() {
10545            return;
10546        }
10547
10548        self.transact(window, cx, |this, window, cx| {
10549            let buffer = this.buffer.update(cx, |buffer, cx| {
10550                buffer.edit(edits, None, cx);
10551                buffer.snapshot(cx)
10552            });
10553
10554            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10555            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10556                boundaries.into_iter()
10557            {
10558                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10559                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10560                new_selections.push(open_offset..open_offset);
10561                new_selections.push(close_offset..close_offset);
10562            }
10563
10564            this.change_selections(Default::default(), window, cx, |s| {
10565                s.select_ranges(new_selections);
10566            });
10567
10568            this.request_autoscroll(Autoscroll::fit(), cx);
10569        });
10570    }
10571
10572    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10573        let Some(project) = self.project.clone() else {
10574            return;
10575        };
10576        self.reload(project, window, cx)
10577            .detach_and_notify_err(window, cx);
10578    }
10579
10580    pub fn restore_file(
10581        &mut self,
10582        _: &::git::RestoreFile,
10583        window: &mut Window,
10584        cx: &mut Context<Self>,
10585    ) {
10586        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10587        let mut buffer_ids = HashSet::default();
10588        let snapshot = self.buffer().read(cx).snapshot(cx);
10589        for selection in self.selections.all::<usize>(cx) {
10590            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10591        }
10592
10593        let buffer = self.buffer().read(cx);
10594        let ranges = buffer_ids
10595            .into_iter()
10596            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10597            .collect::<Vec<_>>();
10598
10599        self.restore_hunks_in_ranges(ranges, window, cx);
10600    }
10601
10602    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10603        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10604        let selections = self
10605            .selections
10606            .all(cx)
10607            .into_iter()
10608            .map(|s| s.range())
10609            .collect();
10610        self.restore_hunks_in_ranges(selections, window, cx);
10611    }
10612
10613    pub fn restore_hunks_in_ranges(
10614        &mut self,
10615        ranges: Vec<Range<Point>>,
10616        window: &mut Window,
10617        cx: &mut Context<Editor>,
10618    ) {
10619        let mut revert_changes = HashMap::default();
10620        let chunk_by = self
10621            .snapshot(window, cx)
10622            .hunks_for_ranges(ranges)
10623            .into_iter()
10624            .chunk_by(|hunk| hunk.buffer_id);
10625        for (buffer_id, hunks) in &chunk_by {
10626            let hunks = hunks.collect::<Vec<_>>();
10627            for hunk in &hunks {
10628                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10629            }
10630            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10631        }
10632        drop(chunk_by);
10633        if !revert_changes.is_empty() {
10634            self.transact(window, cx, |editor, window, cx| {
10635                editor.restore(revert_changes, window, cx);
10636            });
10637        }
10638    }
10639
10640    pub fn open_active_item_in_terminal(
10641        &mut self,
10642        _: &OpenInTerminal,
10643        window: &mut Window,
10644        cx: &mut Context<Self>,
10645    ) {
10646        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10647            let project_path = buffer.read(cx).project_path(cx)?;
10648            let project = self.project()?.read(cx);
10649            let entry = project.entry_for_path(&project_path, cx)?;
10650            let parent = match &entry.canonical_path {
10651                Some(canonical_path) => canonical_path.to_path_buf(),
10652                None => project.absolute_path(&project_path, cx)?,
10653            }
10654            .parent()?
10655            .to_path_buf();
10656            Some(parent)
10657        }) {
10658            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10659        }
10660    }
10661
10662    fn set_breakpoint_context_menu(
10663        &mut self,
10664        display_row: DisplayRow,
10665        position: Option<Anchor>,
10666        clicked_point: gpui::Point<Pixels>,
10667        window: &mut Window,
10668        cx: &mut Context<Self>,
10669    ) {
10670        let source = self
10671            .buffer
10672            .read(cx)
10673            .snapshot(cx)
10674            .anchor_before(Point::new(display_row.0, 0u32));
10675
10676        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10677
10678        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10679            self,
10680            source,
10681            clicked_point,
10682            context_menu,
10683            window,
10684            cx,
10685        );
10686    }
10687
10688    fn add_edit_breakpoint_block(
10689        &mut self,
10690        anchor: Anchor,
10691        breakpoint: &Breakpoint,
10692        edit_action: BreakpointPromptEditAction,
10693        window: &mut Window,
10694        cx: &mut Context<Self>,
10695    ) {
10696        let weak_editor = cx.weak_entity();
10697        let bp_prompt = cx.new(|cx| {
10698            BreakpointPromptEditor::new(
10699                weak_editor,
10700                anchor,
10701                breakpoint.clone(),
10702                edit_action,
10703                window,
10704                cx,
10705            )
10706        });
10707
10708        let height = bp_prompt.update(cx, |this, cx| {
10709            this.prompt
10710                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10711        });
10712        let cloned_prompt = bp_prompt.clone();
10713        let blocks = vec![BlockProperties {
10714            style: BlockStyle::Sticky,
10715            placement: BlockPlacement::Above(anchor),
10716            height: Some(height),
10717            render: Arc::new(move |cx| {
10718                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10719                cloned_prompt.clone().into_any_element()
10720            }),
10721            priority: 0,
10722        }];
10723
10724        let focus_handle = bp_prompt.focus_handle(cx);
10725        window.focus(&focus_handle);
10726
10727        let block_ids = self.insert_blocks(blocks, None, cx);
10728        bp_prompt.update(cx, |prompt, _| {
10729            prompt.add_block_ids(block_ids);
10730        });
10731    }
10732
10733    pub(crate) fn breakpoint_at_row(
10734        &self,
10735        row: u32,
10736        window: &mut Window,
10737        cx: &mut Context<Self>,
10738    ) -> Option<(Anchor, Breakpoint)> {
10739        let snapshot = self.snapshot(window, cx);
10740        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10741
10742        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10743    }
10744
10745    pub(crate) fn breakpoint_at_anchor(
10746        &self,
10747        breakpoint_position: Anchor,
10748        snapshot: &EditorSnapshot,
10749        cx: &mut Context<Self>,
10750    ) -> Option<(Anchor, Breakpoint)> {
10751        let buffer = self
10752            .buffer
10753            .read(cx)
10754            .buffer_for_anchor(breakpoint_position, cx)?;
10755
10756        let enclosing_excerpt = breakpoint_position.excerpt_id;
10757        let buffer_snapshot = buffer.read(cx).snapshot();
10758
10759        let row = buffer_snapshot
10760            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10761            .row;
10762
10763        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10764        let anchor_end = snapshot
10765            .buffer_snapshot
10766            .anchor_after(Point::new(row, line_len));
10767
10768        self.breakpoint_store
10769            .as_ref()?
10770            .read_with(cx, |breakpoint_store, cx| {
10771                breakpoint_store
10772                    .breakpoints(
10773                        &buffer,
10774                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10775                        &buffer_snapshot,
10776                        cx,
10777                    )
10778                    .next()
10779                    .and_then(|(bp, _)| {
10780                        let breakpoint_row = buffer_snapshot
10781                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10782                            .row;
10783
10784                        if breakpoint_row == row {
10785                            snapshot
10786                                .buffer_snapshot
10787                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10788                                .map(|position| (position, bp.bp.clone()))
10789                        } else {
10790                            None
10791                        }
10792                    })
10793            })
10794    }
10795
10796    pub fn edit_log_breakpoint(
10797        &mut self,
10798        _: &EditLogBreakpoint,
10799        window: &mut Window,
10800        cx: &mut Context<Self>,
10801    ) {
10802        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10803            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10804                message: None,
10805                state: BreakpointState::Enabled,
10806                condition: None,
10807                hit_condition: None,
10808            });
10809
10810            self.add_edit_breakpoint_block(
10811                anchor,
10812                &breakpoint,
10813                BreakpointPromptEditAction::Log,
10814                window,
10815                cx,
10816            );
10817        }
10818    }
10819
10820    fn breakpoints_at_cursors(
10821        &self,
10822        window: &mut Window,
10823        cx: &mut Context<Self>,
10824    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10825        let snapshot = self.snapshot(window, cx);
10826        let cursors = self
10827            .selections
10828            .disjoint_anchors()
10829            .iter()
10830            .map(|selection| {
10831                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10832
10833                let breakpoint_position = self
10834                    .breakpoint_at_row(cursor_position.row, window, cx)
10835                    .map(|bp| bp.0)
10836                    .unwrap_or_else(|| {
10837                        snapshot
10838                            .display_snapshot
10839                            .buffer_snapshot
10840                            .anchor_after(Point::new(cursor_position.row, 0))
10841                    });
10842
10843                let breakpoint = self
10844                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10845                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10846
10847                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10848            })
10849            // There might be multiple cursors on the same line; all of them should have the same anchors though as their breakpoints positions, which makes it possible to sort and dedup the list.
10850            .collect::<HashMap<Anchor, _>>();
10851
10852        cursors.into_iter().collect()
10853    }
10854
10855    pub fn enable_breakpoint(
10856        &mut self,
10857        _: &crate::actions::EnableBreakpoint,
10858        window: &mut Window,
10859        cx: &mut Context<Self>,
10860    ) {
10861        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10862            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10863                continue;
10864            };
10865            self.edit_breakpoint_at_anchor(
10866                anchor,
10867                breakpoint,
10868                BreakpointEditAction::InvertState,
10869                cx,
10870            );
10871        }
10872    }
10873
10874    pub fn disable_breakpoint(
10875        &mut self,
10876        _: &crate::actions::DisableBreakpoint,
10877        window: &mut Window,
10878        cx: &mut Context<Self>,
10879    ) {
10880        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10881            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10882                continue;
10883            };
10884            self.edit_breakpoint_at_anchor(
10885                anchor,
10886                breakpoint,
10887                BreakpointEditAction::InvertState,
10888                cx,
10889            );
10890        }
10891    }
10892
10893    pub fn toggle_breakpoint(
10894        &mut self,
10895        _: &crate::actions::ToggleBreakpoint,
10896        window: &mut Window,
10897        cx: &mut Context<Self>,
10898    ) {
10899        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10900            if let Some(breakpoint) = breakpoint {
10901                self.edit_breakpoint_at_anchor(
10902                    anchor,
10903                    breakpoint,
10904                    BreakpointEditAction::Toggle,
10905                    cx,
10906                );
10907            } else {
10908                self.edit_breakpoint_at_anchor(
10909                    anchor,
10910                    Breakpoint::new_standard(),
10911                    BreakpointEditAction::Toggle,
10912                    cx,
10913                );
10914            }
10915        }
10916    }
10917
10918    pub fn edit_breakpoint_at_anchor(
10919        &mut self,
10920        breakpoint_position: Anchor,
10921        breakpoint: Breakpoint,
10922        edit_action: BreakpointEditAction,
10923        cx: &mut Context<Self>,
10924    ) {
10925        let Some(breakpoint_store) = &self.breakpoint_store else {
10926            return;
10927        };
10928
10929        let Some(buffer) = self
10930            .buffer
10931            .read(cx)
10932            .buffer_for_anchor(breakpoint_position, cx)
10933        else {
10934            return;
10935        };
10936
10937        breakpoint_store.update(cx, |breakpoint_store, cx| {
10938            breakpoint_store.toggle_breakpoint(
10939                buffer,
10940                BreakpointWithPosition {
10941                    position: breakpoint_position.text_anchor,
10942                    bp: breakpoint,
10943                },
10944                edit_action,
10945                cx,
10946            );
10947        });
10948
10949        cx.notify();
10950    }
10951
10952    #[cfg(any(test, feature = "test-support"))]
10953    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10954        self.breakpoint_store.clone()
10955    }
10956
10957    pub fn prepare_restore_change(
10958        &self,
10959        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10960        hunk: &MultiBufferDiffHunk,
10961        cx: &mut App,
10962    ) -> Option<()> {
10963        if hunk.is_created_file() {
10964            return None;
10965        }
10966        let buffer = self.buffer.read(cx);
10967        let diff = buffer.diff_for(hunk.buffer_id)?;
10968        let buffer = buffer.buffer(hunk.buffer_id)?;
10969        let buffer = buffer.read(cx);
10970        let original_text = diff
10971            .read(cx)
10972            .base_text()
10973            .as_rope()
10974            .slice(hunk.diff_base_byte_range.clone());
10975        let buffer_snapshot = buffer.snapshot();
10976        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10977        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10978            probe
10979                .0
10980                .start
10981                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10982                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10983        }) {
10984            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10985            Some(())
10986        } else {
10987            None
10988        }
10989    }
10990
10991    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10992        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10993    }
10994
10995    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10996        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
10997    }
10998
10999    fn manipulate_lines<M>(
11000        &mut self,
11001        window: &mut Window,
11002        cx: &mut Context<Self>,
11003        mut manipulate: M,
11004    ) where
11005        M: FnMut(&str) -> LineManipulationResult,
11006    {
11007        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11008
11009        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11010        let buffer = self.buffer.read(cx).snapshot(cx);
11011
11012        let mut edits = Vec::new();
11013
11014        let selections = self.selections.all::<Point>(cx);
11015        let mut selections = selections.iter().peekable();
11016        let mut contiguous_row_selections = Vec::new();
11017        let mut new_selections = Vec::new();
11018        let mut added_lines = 0;
11019        let mut removed_lines = 0;
11020
11021        while let Some(selection) = selections.next() {
11022            let (start_row, end_row) = consume_contiguous_rows(
11023                &mut contiguous_row_selections,
11024                selection,
11025                &display_map,
11026                &mut selections,
11027            );
11028
11029            let start_point = Point::new(start_row.0, 0);
11030            let end_point = Point::new(
11031                end_row.previous_row().0,
11032                buffer.line_len(end_row.previous_row()),
11033            );
11034            let text = buffer
11035                .text_for_range(start_point..end_point)
11036                .collect::<String>();
11037
11038            let LineManipulationResult {
11039                new_text,
11040                line_count_before,
11041                line_count_after,
11042            } = manipulate(&text);
11043
11044            edits.push((start_point..end_point, new_text));
11045
11046            // Selections must change based on added and removed line count
11047            let start_row =
11048                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11049            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11050            new_selections.push(Selection {
11051                id: selection.id,
11052                start: start_row,
11053                end: end_row,
11054                goal: SelectionGoal::None,
11055                reversed: selection.reversed,
11056            });
11057
11058            if line_count_after > line_count_before {
11059                added_lines += line_count_after - line_count_before;
11060            } else if line_count_before > line_count_after {
11061                removed_lines += line_count_before - line_count_after;
11062            }
11063        }
11064
11065        self.transact(window, cx, |this, window, cx| {
11066            let buffer = this.buffer.update(cx, |buffer, cx| {
11067                buffer.edit(edits, None, cx);
11068                buffer.snapshot(cx)
11069            });
11070
11071            // Recalculate offsets on newly edited buffer
11072            let new_selections = new_selections
11073                .iter()
11074                .map(|s| {
11075                    let start_point = Point::new(s.start.0, 0);
11076                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11077                    Selection {
11078                        id: s.id,
11079                        start: buffer.point_to_offset(start_point),
11080                        end: buffer.point_to_offset(end_point),
11081                        goal: s.goal,
11082                        reversed: s.reversed,
11083                    }
11084                })
11085                .collect();
11086
11087            this.change_selections(Default::default(), window, cx, |s| {
11088                s.select(new_selections);
11089            });
11090
11091            this.request_autoscroll(Autoscroll::fit(), cx);
11092        });
11093    }
11094
11095    fn manipulate_immutable_lines<Fn>(
11096        &mut self,
11097        window: &mut Window,
11098        cx: &mut Context<Self>,
11099        mut callback: Fn,
11100    ) where
11101        Fn: FnMut(&mut Vec<&str>),
11102    {
11103        self.manipulate_lines(window, cx, |text| {
11104            let mut lines: Vec<&str> = text.split('\n').collect();
11105            let line_count_before = lines.len();
11106
11107            callback(&mut lines);
11108
11109            LineManipulationResult {
11110                new_text: lines.join("\n"),
11111                line_count_before,
11112                line_count_after: lines.len(),
11113            }
11114        });
11115    }
11116
11117    fn manipulate_mutable_lines<Fn>(
11118        &mut self,
11119        window: &mut Window,
11120        cx: &mut Context<Self>,
11121        mut callback: Fn,
11122    ) where
11123        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11124    {
11125        self.manipulate_lines(window, cx, |text| {
11126            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11127            let line_count_before = lines.len();
11128
11129            callback(&mut lines);
11130
11131            LineManipulationResult {
11132                new_text: lines.join("\n"),
11133                line_count_before,
11134                line_count_after: lines.len(),
11135            }
11136        });
11137    }
11138
11139    pub fn convert_indentation_to_spaces(
11140        &mut self,
11141        _: &ConvertIndentationToSpaces,
11142        window: &mut Window,
11143        cx: &mut Context<Self>,
11144    ) {
11145        let settings = self.buffer.read(cx).language_settings(cx);
11146        let tab_size = settings.tab_size.get() as usize;
11147
11148        self.manipulate_mutable_lines(window, cx, |lines| {
11149            // Allocates a reasonably sized scratch buffer once for the whole loop
11150            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11151            // Avoids recomputing spaces that could be inserted many times
11152            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11153                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11154                .collect();
11155
11156            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11157                let mut chars = line.as_ref().chars();
11158                let mut col = 0;
11159                let mut changed = false;
11160
11161                for ch in chars.by_ref() {
11162                    match ch {
11163                        ' ' => {
11164                            reindented_line.push(' ');
11165                            col += 1;
11166                        }
11167                        '\t' => {
11168                            // \t are converted to spaces depending on the current column
11169                            let spaces_len = tab_size - (col % tab_size);
11170                            reindented_line.extend(&space_cache[spaces_len - 1]);
11171                            col += spaces_len;
11172                            changed = true;
11173                        }
11174                        _ => {
11175                            // If we dont append before break, the character is consumed
11176                            reindented_line.push(ch);
11177                            break;
11178                        }
11179                    }
11180                }
11181
11182                if !changed {
11183                    reindented_line.clear();
11184                    continue;
11185                }
11186                // Append the rest of the line and replace old reference with new one
11187                reindented_line.extend(chars);
11188                *line = Cow::Owned(reindented_line.clone());
11189                reindented_line.clear();
11190            }
11191        });
11192    }
11193
11194    pub fn convert_indentation_to_tabs(
11195        &mut self,
11196        _: &ConvertIndentationToTabs,
11197        window: &mut Window,
11198        cx: &mut Context<Self>,
11199    ) {
11200        let settings = self.buffer.read(cx).language_settings(cx);
11201        let tab_size = settings.tab_size.get() as usize;
11202
11203        self.manipulate_mutable_lines(window, cx, |lines| {
11204            // Allocates a reasonably sized buffer once for the whole loop
11205            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11206            // Avoids recomputing spaces that could be inserted many times
11207            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11208                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11209                .collect();
11210
11211            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11212                let mut chars = line.chars();
11213                let mut spaces_count = 0;
11214                let mut first_non_indent_char = None;
11215                let mut changed = false;
11216
11217                for ch in chars.by_ref() {
11218                    match ch {
11219                        ' ' => {
11220                            // Keep track of spaces. Append \t when we reach tab_size
11221                            spaces_count += 1;
11222                            changed = true;
11223                            if spaces_count == tab_size {
11224                                reindented_line.push('\t');
11225                                spaces_count = 0;
11226                            }
11227                        }
11228                        '\t' => {
11229                            reindented_line.push('\t');
11230                            spaces_count = 0;
11231                        }
11232                        _ => {
11233                            // Dont append it yet, we might have remaining spaces
11234                            first_non_indent_char = Some(ch);
11235                            break;
11236                        }
11237                    }
11238                }
11239
11240                if !changed {
11241                    reindented_line.clear();
11242                    continue;
11243                }
11244                // Remaining spaces that didn't make a full tab stop
11245                if spaces_count > 0 {
11246                    reindented_line.extend(&space_cache[spaces_count - 1]);
11247                }
11248                // If we consume an extra character that was not indentation, add it back
11249                if let Some(extra_char) = first_non_indent_char {
11250                    reindented_line.push(extra_char);
11251                }
11252                // Append the rest of the line and replace old reference with new one
11253                reindented_line.extend(chars);
11254                *line = Cow::Owned(reindented_line.clone());
11255                reindented_line.clear();
11256            }
11257        });
11258    }
11259
11260    pub fn convert_to_upper_case(
11261        &mut self,
11262        _: &ConvertToUpperCase,
11263        window: &mut Window,
11264        cx: &mut Context<Self>,
11265    ) {
11266        self.manipulate_text(window, cx, |text| text.to_uppercase())
11267    }
11268
11269    pub fn convert_to_lower_case(
11270        &mut self,
11271        _: &ConvertToLowerCase,
11272        window: &mut Window,
11273        cx: &mut Context<Self>,
11274    ) {
11275        self.manipulate_text(window, cx, |text| text.to_lowercase())
11276    }
11277
11278    pub fn convert_to_title_case(
11279        &mut self,
11280        _: &ConvertToTitleCase,
11281        window: &mut Window,
11282        cx: &mut Context<Self>,
11283    ) {
11284        self.manipulate_text(window, cx, |text| {
11285            text.split('\n')
11286                .map(|line| line.to_case(Case::Title))
11287                .join("\n")
11288        })
11289    }
11290
11291    pub fn convert_to_snake_case(
11292        &mut self,
11293        _: &ConvertToSnakeCase,
11294        window: &mut Window,
11295        cx: &mut Context<Self>,
11296    ) {
11297        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11298    }
11299
11300    pub fn convert_to_kebab_case(
11301        &mut self,
11302        _: &ConvertToKebabCase,
11303        window: &mut Window,
11304        cx: &mut Context<Self>,
11305    ) {
11306        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11307    }
11308
11309    pub fn convert_to_upper_camel_case(
11310        &mut self,
11311        _: &ConvertToUpperCamelCase,
11312        window: &mut Window,
11313        cx: &mut Context<Self>,
11314    ) {
11315        self.manipulate_text(window, cx, |text| {
11316            text.split('\n')
11317                .map(|line| line.to_case(Case::UpperCamel))
11318                .join("\n")
11319        })
11320    }
11321
11322    pub fn convert_to_lower_camel_case(
11323        &mut self,
11324        _: &ConvertToLowerCamelCase,
11325        window: &mut Window,
11326        cx: &mut Context<Self>,
11327    ) {
11328        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11329    }
11330
11331    pub fn convert_to_opposite_case(
11332        &mut self,
11333        _: &ConvertToOppositeCase,
11334        window: &mut Window,
11335        cx: &mut Context<Self>,
11336    ) {
11337        self.manipulate_text(window, cx, |text| {
11338            text.chars()
11339                .fold(String::with_capacity(text.len()), |mut t, c| {
11340                    if c.is_uppercase() {
11341                        t.extend(c.to_lowercase());
11342                    } else {
11343                        t.extend(c.to_uppercase());
11344                    }
11345                    t
11346                })
11347        })
11348    }
11349
11350    pub fn convert_to_sentence_case(
11351        &mut self,
11352        _: &ConvertToSentenceCase,
11353        window: &mut Window,
11354        cx: &mut Context<Self>,
11355    ) {
11356        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11357    }
11358
11359    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11360        self.manipulate_text(window, cx, |text| {
11361            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11362            if has_upper_case_characters {
11363                text.to_lowercase()
11364            } else {
11365                text.to_uppercase()
11366            }
11367        })
11368    }
11369
11370    pub fn convert_to_rot13(
11371        &mut self,
11372        _: &ConvertToRot13,
11373        window: &mut Window,
11374        cx: &mut Context<Self>,
11375    ) {
11376        self.manipulate_text(window, cx, |text| {
11377            text.chars()
11378                .map(|c| match c {
11379                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11380                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11381                    _ => c,
11382                })
11383                .collect()
11384        })
11385    }
11386
11387    pub fn convert_to_rot47(
11388        &mut self,
11389        _: &ConvertToRot47,
11390        window: &mut Window,
11391        cx: &mut Context<Self>,
11392    ) {
11393        self.manipulate_text(window, cx, |text| {
11394            text.chars()
11395                .map(|c| {
11396                    let code_point = c as u32;
11397                    if code_point >= 33 && code_point <= 126 {
11398                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11399                    }
11400                    c
11401                })
11402                .collect()
11403        })
11404    }
11405
11406    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11407    where
11408        Fn: FnMut(&str) -> String,
11409    {
11410        let buffer = self.buffer.read(cx).snapshot(cx);
11411
11412        let mut new_selections = Vec::new();
11413        let mut edits = Vec::new();
11414        let mut selection_adjustment = 0i32;
11415
11416        for selection in self.selections.all_adjusted(cx) {
11417            let selection_is_empty = selection.is_empty();
11418
11419            let (start, end) = if selection_is_empty {
11420                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11421                (word_range.start, word_range.end)
11422            } else {
11423                (
11424                    buffer.point_to_offset(selection.start),
11425                    buffer.point_to_offset(selection.end),
11426                )
11427            };
11428
11429            let text = buffer.text_for_range(start..end).collect::<String>();
11430            let old_length = text.len() as i32;
11431            let text = callback(&text);
11432
11433            new_selections.push(Selection {
11434                start: (start as i32 - selection_adjustment) as usize,
11435                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11436                goal: SelectionGoal::None,
11437                id: selection.id,
11438                reversed: selection.reversed,
11439            });
11440
11441            selection_adjustment += old_length - text.len() as i32;
11442
11443            edits.push((start..end, text));
11444        }
11445
11446        self.transact(window, cx, |this, window, cx| {
11447            this.buffer.update(cx, |buffer, cx| {
11448                buffer.edit(edits, None, cx);
11449            });
11450
11451            this.change_selections(Default::default(), window, cx, |s| {
11452                s.select(new_selections);
11453            });
11454
11455            this.request_autoscroll(Autoscroll::fit(), cx);
11456        });
11457    }
11458
11459    pub fn move_selection_on_drop(
11460        &mut self,
11461        selection: &Selection<Anchor>,
11462        target: DisplayPoint,
11463        is_cut: bool,
11464        window: &mut Window,
11465        cx: &mut Context<Self>,
11466    ) {
11467        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11468        let buffer = &display_map.buffer_snapshot;
11469        let mut edits = Vec::new();
11470        let insert_point = display_map
11471            .clip_point(target, Bias::Left)
11472            .to_point(&display_map);
11473        let text = buffer
11474            .text_for_range(selection.start..selection.end)
11475            .collect::<String>();
11476        if is_cut {
11477            edits.push(((selection.start..selection.end), String::new()));
11478        }
11479        let insert_anchor = buffer.anchor_before(insert_point);
11480        edits.push(((insert_anchor..insert_anchor), text));
11481        let last_edit_start = insert_anchor.bias_left(buffer);
11482        let last_edit_end = insert_anchor.bias_right(buffer);
11483        self.transact(window, cx, |this, window, cx| {
11484            this.buffer.update(cx, |buffer, cx| {
11485                buffer.edit(edits, None, cx);
11486            });
11487            this.change_selections(Default::default(), window, cx, |s| {
11488                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11489            });
11490        });
11491    }
11492
11493    pub fn clear_selection_drag_state(&mut self) {
11494        self.selection_drag_state = SelectionDragState::None;
11495    }
11496
11497    pub fn duplicate(
11498        &mut self,
11499        upwards: bool,
11500        whole_lines: bool,
11501        window: &mut Window,
11502        cx: &mut Context<Self>,
11503    ) {
11504        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11505
11506        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11507        let buffer = &display_map.buffer_snapshot;
11508        let selections = self.selections.all::<Point>(cx);
11509
11510        let mut edits = Vec::new();
11511        let mut selections_iter = selections.iter().peekable();
11512        while let Some(selection) = selections_iter.next() {
11513            let mut rows = selection.spanned_rows(false, &display_map);
11514            // duplicate line-wise
11515            if whole_lines || selection.start == selection.end {
11516                // Avoid duplicating the same lines twice.
11517                while let Some(next_selection) = selections_iter.peek() {
11518                    let next_rows = next_selection.spanned_rows(false, &display_map);
11519                    if next_rows.start < rows.end {
11520                        rows.end = next_rows.end;
11521                        selections_iter.next().unwrap();
11522                    } else {
11523                        break;
11524                    }
11525                }
11526
11527                // Copy the text from the selected row region and splice it either at the start
11528                // or end of the region.
11529                let start = Point::new(rows.start.0, 0);
11530                let end = Point::new(
11531                    rows.end.previous_row().0,
11532                    buffer.line_len(rows.end.previous_row()),
11533                );
11534                let text = buffer
11535                    .text_for_range(start..end)
11536                    .chain(Some("\n"))
11537                    .collect::<String>();
11538                let insert_location = if upwards {
11539                    Point::new(rows.end.0, 0)
11540                } else {
11541                    start
11542                };
11543                edits.push((insert_location..insert_location, text));
11544            } else {
11545                // duplicate character-wise
11546                let start = selection.start;
11547                let end = selection.end;
11548                let text = buffer.text_for_range(start..end).collect::<String>();
11549                edits.push((selection.end..selection.end, text));
11550            }
11551        }
11552
11553        self.transact(window, cx, |this, _, cx| {
11554            this.buffer.update(cx, |buffer, cx| {
11555                buffer.edit(edits, None, cx);
11556            });
11557
11558            this.request_autoscroll(Autoscroll::fit(), cx);
11559        });
11560    }
11561
11562    pub fn duplicate_line_up(
11563        &mut self,
11564        _: &DuplicateLineUp,
11565        window: &mut Window,
11566        cx: &mut Context<Self>,
11567    ) {
11568        self.duplicate(true, true, window, cx);
11569    }
11570
11571    pub fn duplicate_line_down(
11572        &mut self,
11573        _: &DuplicateLineDown,
11574        window: &mut Window,
11575        cx: &mut Context<Self>,
11576    ) {
11577        self.duplicate(false, true, window, cx);
11578    }
11579
11580    pub fn duplicate_selection(
11581        &mut self,
11582        _: &DuplicateSelection,
11583        window: &mut Window,
11584        cx: &mut Context<Self>,
11585    ) {
11586        self.duplicate(false, false, window, cx);
11587    }
11588
11589    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11590        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11591        if self.mode.is_single_line() {
11592            cx.propagate();
11593            return;
11594        }
11595
11596        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11597        let buffer = self.buffer.read(cx).snapshot(cx);
11598
11599        let mut edits = Vec::new();
11600        let mut unfold_ranges = Vec::new();
11601        let mut refold_creases = Vec::new();
11602
11603        let selections = self.selections.all::<Point>(cx);
11604        let mut selections = selections.iter().peekable();
11605        let mut contiguous_row_selections = Vec::new();
11606        let mut new_selections = Vec::new();
11607
11608        while let Some(selection) = selections.next() {
11609            // Find all the selections that span a contiguous row range
11610            let (start_row, end_row) = consume_contiguous_rows(
11611                &mut contiguous_row_selections,
11612                selection,
11613                &display_map,
11614                &mut selections,
11615            );
11616
11617            // Move the text spanned by the row range to be before the line preceding the row range
11618            if start_row.0 > 0 {
11619                let range_to_move = Point::new(
11620                    start_row.previous_row().0,
11621                    buffer.line_len(start_row.previous_row()),
11622                )
11623                    ..Point::new(
11624                        end_row.previous_row().0,
11625                        buffer.line_len(end_row.previous_row()),
11626                    );
11627                let insertion_point = display_map
11628                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11629                    .0;
11630
11631                // Don't move lines across excerpts
11632                if buffer
11633                    .excerpt_containing(insertion_point..range_to_move.end)
11634                    .is_some()
11635                {
11636                    let text = buffer
11637                        .text_for_range(range_to_move.clone())
11638                        .flat_map(|s| s.chars())
11639                        .skip(1)
11640                        .chain(['\n'])
11641                        .collect::<String>();
11642
11643                    edits.push((
11644                        buffer.anchor_after(range_to_move.start)
11645                            ..buffer.anchor_before(range_to_move.end),
11646                        String::new(),
11647                    ));
11648                    let insertion_anchor = buffer.anchor_after(insertion_point);
11649                    edits.push((insertion_anchor..insertion_anchor, text));
11650
11651                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11652
11653                    // Move selections up
11654                    new_selections.extend(contiguous_row_selections.drain(..).map(
11655                        |mut selection| {
11656                            selection.start.row -= row_delta;
11657                            selection.end.row -= row_delta;
11658                            selection
11659                        },
11660                    ));
11661
11662                    // Move folds up
11663                    unfold_ranges.push(range_to_move.clone());
11664                    for fold in display_map.folds_in_range(
11665                        buffer.anchor_before(range_to_move.start)
11666                            ..buffer.anchor_after(range_to_move.end),
11667                    ) {
11668                        let mut start = fold.range.start.to_point(&buffer);
11669                        let mut end = fold.range.end.to_point(&buffer);
11670                        start.row -= row_delta;
11671                        end.row -= row_delta;
11672                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11673                    }
11674                }
11675            }
11676
11677            // If we didn't move line(s), preserve the existing selections
11678            new_selections.append(&mut contiguous_row_selections);
11679        }
11680
11681        self.transact(window, cx, |this, window, cx| {
11682            this.unfold_ranges(&unfold_ranges, true, true, cx);
11683            this.buffer.update(cx, |buffer, cx| {
11684                for (range, text) in edits {
11685                    buffer.edit([(range, text)], None, cx);
11686                }
11687            });
11688            this.fold_creases(refold_creases, true, window, cx);
11689            this.change_selections(Default::default(), window, cx, |s| {
11690                s.select(new_selections);
11691            })
11692        });
11693    }
11694
11695    pub fn move_line_down(
11696        &mut self,
11697        _: &MoveLineDown,
11698        window: &mut Window,
11699        cx: &mut Context<Self>,
11700    ) {
11701        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11702        if self.mode.is_single_line() {
11703            cx.propagate();
11704            return;
11705        }
11706
11707        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11708        let buffer = self.buffer.read(cx).snapshot(cx);
11709
11710        let mut edits = Vec::new();
11711        let mut unfold_ranges = Vec::new();
11712        let mut refold_creases = Vec::new();
11713
11714        let selections = self.selections.all::<Point>(cx);
11715        let mut selections = selections.iter().peekable();
11716        let mut contiguous_row_selections = Vec::new();
11717        let mut new_selections = Vec::new();
11718
11719        while let Some(selection) = selections.next() {
11720            // Find all the selections that span a contiguous row range
11721            let (start_row, end_row) = consume_contiguous_rows(
11722                &mut contiguous_row_selections,
11723                selection,
11724                &display_map,
11725                &mut selections,
11726            );
11727
11728            // Move the text spanned by the row range to be after the last line of the row range
11729            if end_row.0 <= buffer.max_point().row {
11730                let range_to_move =
11731                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11732                let insertion_point = display_map
11733                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11734                    .0;
11735
11736                // Don't move lines across excerpt boundaries
11737                if buffer
11738                    .excerpt_containing(range_to_move.start..insertion_point)
11739                    .is_some()
11740                {
11741                    let mut text = String::from("\n");
11742                    text.extend(buffer.text_for_range(range_to_move.clone()));
11743                    text.pop(); // Drop trailing newline
11744                    edits.push((
11745                        buffer.anchor_after(range_to_move.start)
11746                            ..buffer.anchor_before(range_to_move.end),
11747                        String::new(),
11748                    ));
11749                    let insertion_anchor = buffer.anchor_after(insertion_point);
11750                    edits.push((insertion_anchor..insertion_anchor, text));
11751
11752                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11753
11754                    // Move selections down
11755                    new_selections.extend(contiguous_row_selections.drain(..).map(
11756                        |mut selection| {
11757                            selection.start.row += row_delta;
11758                            selection.end.row += row_delta;
11759                            selection
11760                        },
11761                    ));
11762
11763                    // Move folds down
11764                    unfold_ranges.push(range_to_move.clone());
11765                    for fold in display_map.folds_in_range(
11766                        buffer.anchor_before(range_to_move.start)
11767                            ..buffer.anchor_after(range_to_move.end),
11768                    ) {
11769                        let mut start = fold.range.start.to_point(&buffer);
11770                        let mut end = fold.range.end.to_point(&buffer);
11771                        start.row += row_delta;
11772                        end.row += row_delta;
11773                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11774                    }
11775                }
11776            }
11777
11778            // If we didn't move line(s), preserve the existing selections
11779            new_selections.append(&mut contiguous_row_selections);
11780        }
11781
11782        self.transact(window, cx, |this, window, cx| {
11783            this.unfold_ranges(&unfold_ranges, true, true, cx);
11784            this.buffer.update(cx, |buffer, cx| {
11785                for (range, text) in edits {
11786                    buffer.edit([(range, text)], None, cx);
11787                }
11788            });
11789            this.fold_creases(refold_creases, true, window, cx);
11790            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11791        });
11792    }
11793
11794    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11795        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11796        let text_layout_details = &self.text_layout_details(window);
11797        self.transact(window, cx, |this, window, cx| {
11798            let edits = this.change_selections(Default::default(), window, cx, |s| {
11799                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11800                s.move_with(|display_map, selection| {
11801                    if !selection.is_empty() {
11802                        return;
11803                    }
11804
11805                    let mut head = selection.head();
11806                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11807                    if head.column() == display_map.line_len(head.row()) {
11808                        transpose_offset = display_map
11809                            .buffer_snapshot
11810                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11811                    }
11812
11813                    if transpose_offset == 0 {
11814                        return;
11815                    }
11816
11817                    *head.column_mut() += 1;
11818                    head = display_map.clip_point(head, Bias::Right);
11819                    let goal = SelectionGoal::HorizontalPosition(
11820                        display_map
11821                            .x_for_display_point(head, text_layout_details)
11822                            .into(),
11823                    );
11824                    selection.collapse_to(head, goal);
11825
11826                    let transpose_start = display_map
11827                        .buffer_snapshot
11828                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11829                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11830                        let transpose_end = display_map
11831                            .buffer_snapshot
11832                            .clip_offset(transpose_offset + 1, Bias::Right);
11833                        if let Some(ch) =
11834                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11835                        {
11836                            edits.push((transpose_start..transpose_offset, String::new()));
11837                            edits.push((transpose_end..transpose_end, ch.to_string()));
11838                        }
11839                    }
11840                });
11841                edits
11842            });
11843            this.buffer
11844                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11845            let selections = this.selections.all::<usize>(cx);
11846            this.change_selections(Default::default(), window, cx, |s| {
11847                s.select(selections);
11848            });
11849        });
11850    }
11851
11852    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11854        if self.mode.is_single_line() {
11855            cx.propagate();
11856            return;
11857        }
11858
11859        self.rewrap_impl(RewrapOptions::default(), cx)
11860    }
11861
11862    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11863        let buffer = self.buffer.read(cx).snapshot(cx);
11864        let selections = self.selections.all::<Point>(cx);
11865
11866        #[derive(Clone, Debug, PartialEq)]
11867        enum CommentFormat {
11868            /// single line comment, with prefix for line
11869            Line(String),
11870            /// single line within a block comment, with prefix for line
11871            BlockLine(String),
11872            /// a single line of a block comment that includes the initial delimiter
11873            BlockCommentWithStart(BlockCommentConfig),
11874            /// a single line of a block comment that includes the ending delimiter
11875            BlockCommentWithEnd(BlockCommentConfig),
11876        }
11877
11878        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11879        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11880            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11881                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11882                .peekable();
11883
11884            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11885                row
11886            } else {
11887                return Vec::new();
11888            };
11889
11890            let language_settings = buffer.language_settings_at(selection.head(), cx);
11891            let language_scope = buffer.language_scope_at(selection.head());
11892
11893            let indent_and_prefix_for_row =
11894                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11895                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11896                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11897                        &language_scope
11898                    {
11899                        let indent_end = Point::new(row, indent.len);
11900                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11901                        let line_text_after_indent = buffer
11902                            .text_for_range(indent_end..line_end)
11903                            .collect::<String>();
11904
11905                        let is_within_comment_override = buffer
11906                            .language_scope_at(indent_end)
11907                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11908                        let comment_delimiters = if is_within_comment_override {
11909                            // we are within a comment syntax node, but we don't
11910                            // yet know what kind of comment: block, doc or line
11911                            match (
11912                                language_scope.documentation_comment(),
11913                                language_scope.block_comment(),
11914                            ) {
11915                                (Some(config), _) | (_, Some(config))
11916                                    if buffer.contains_str_at(indent_end, &config.start) =>
11917                                {
11918                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11919                                }
11920                                (Some(config), _) | (_, Some(config))
11921                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11922                                {
11923                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11924                                }
11925                                (Some(config), _) | (_, Some(config))
11926                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11927                                {
11928                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11929                                }
11930                                (_, _) => language_scope
11931                                    .line_comment_prefixes()
11932                                    .iter()
11933                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11934                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11935                            }
11936                        } else {
11937                            // we not in an overridden comment node, but we may
11938                            // be within a non-overridden line comment node
11939                            language_scope
11940                                .line_comment_prefixes()
11941                                .iter()
11942                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11943                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11944                        };
11945
11946                        let rewrap_prefix = language_scope
11947                            .rewrap_prefixes()
11948                            .iter()
11949                            .find_map(|prefix_regex| {
11950                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11951                                    if mat.start() == 0 {
11952                                        Some(mat.as_str().to_string())
11953                                    } else {
11954                                        None
11955                                    }
11956                                })
11957                            })
11958                            .flatten();
11959                        (comment_delimiters, rewrap_prefix)
11960                    } else {
11961                        (None, None)
11962                    };
11963                    (indent, comment_prefix, rewrap_prefix)
11964                };
11965
11966            let mut ranges = Vec::new();
11967            let from_empty_selection = selection.is_empty();
11968
11969            let mut current_range_start = first_row;
11970            let mut prev_row = first_row;
11971            let (
11972                mut current_range_indent,
11973                mut current_range_comment_delimiters,
11974                mut current_range_rewrap_prefix,
11975            ) = indent_and_prefix_for_row(first_row);
11976
11977            for row in non_blank_rows_iter.skip(1) {
11978                let has_paragraph_break = row > prev_row + 1;
11979
11980                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
11981                    indent_and_prefix_for_row(row);
11982
11983                let has_indent_change = row_indent != current_range_indent;
11984                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
11985
11986                let has_boundary_change = has_comment_change
11987                    || row_rewrap_prefix.is_some()
11988                    || (has_indent_change && current_range_comment_delimiters.is_some());
11989
11990                if has_paragraph_break || has_boundary_change {
11991                    ranges.push((
11992                        language_settings.clone(),
11993                        Point::new(current_range_start, 0)
11994                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11995                        current_range_indent,
11996                        current_range_comment_delimiters.clone(),
11997                        current_range_rewrap_prefix.clone(),
11998                        from_empty_selection,
11999                    ));
12000                    current_range_start = row;
12001                    current_range_indent = row_indent;
12002                    current_range_comment_delimiters = row_comment_delimiters;
12003                    current_range_rewrap_prefix = row_rewrap_prefix;
12004                }
12005                prev_row = row;
12006            }
12007
12008            ranges.push((
12009                language_settings.clone(),
12010                Point::new(current_range_start, 0)
12011                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12012                current_range_indent,
12013                current_range_comment_delimiters,
12014                current_range_rewrap_prefix,
12015                from_empty_selection,
12016            ));
12017
12018            ranges
12019        });
12020
12021        let mut edits = Vec::new();
12022        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12023
12024        for (
12025            language_settings,
12026            wrap_range,
12027            mut indent_size,
12028            comment_prefix,
12029            rewrap_prefix,
12030            from_empty_selection,
12031        ) in wrap_ranges
12032        {
12033            let mut start_row = wrap_range.start.row;
12034            let mut end_row = wrap_range.end.row;
12035
12036            // Skip selections that overlap with a range that has already been rewrapped.
12037            let selection_range = start_row..end_row;
12038            if rewrapped_row_ranges
12039                .iter()
12040                .any(|range| range.overlaps(&selection_range))
12041            {
12042                continue;
12043            }
12044
12045            let tab_size = language_settings.tab_size;
12046
12047            let (line_prefix, inside_comment) = match &comment_prefix {
12048                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12049                    (Some(prefix.as_str()), true)
12050                }
12051                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12052                    (Some(prefix.as_ref()), true)
12053                }
12054                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12055                    start: _,
12056                    end: _,
12057                    prefix,
12058                    tab_size,
12059                })) => {
12060                    indent_size.len += tab_size;
12061                    (Some(prefix.as_ref()), true)
12062                }
12063                None => (None, false),
12064            };
12065            let indent_prefix = indent_size.chars().collect::<String>();
12066            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12067
12068            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12069                RewrapBehavior::InComments => inside_comment,
12070                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12071                RewrapBehavior::Anywhere => true,
12072            };
12073
12074            let should_rewrap = options.override_language_settings
12075                || allow_rewrap_based_on_language
12076                || self.hard_wrap.is_some();
12077            if !should_rewrap {
12078                continue;
12079            }
12080
12081            if from_empty_selection {
12082                'expand_upwards: while start_row > 0 {
12083                    let prev_row = start_row - 1;
12084                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12085                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12086                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12087                    {
12088                        start_row = prev_row;
12089                    } else {
12090                        break 'expand_upwards;
12091                    }
12092                }
12093
12094                'expand_downwards: while end_row < buffer.max_point().row {
12095                    let next_row = end_row + 1;
12096                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12097                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12098                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12099                    {
12100                        end_row = next_row;
12101                    } else {
12102                        break 'expand_downwards;
12103                    }
12104                }
12105            }
12106
12107            let start = Point::new(start_row, 0);
12108            let start_offset = start.to_offset(&buffer);
12109            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12110            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12111            let mut first_line_delimiter = None;
12112            let mut last_line_delimiter = None;
12113            let Some(lines_without_prefixes) = selection_text
12114                .lines()
12115                .enumerate()
12116                .map(|(ix, line)| {
12117                    let line_trimmed = line.trim_start();
12118                    if rewrap_prefix.is_some() && ix > 0 {
12119                        Ok(line_trimmed)
12120                    } else if let Some(
12121                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12122                            start,
12123                            prefix,
12124                            end,
12125                            tab_size,
12126                        })
12127                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12128                            start,
12129                            prefix,
12130                            end,
12131                            tab_size,
12132                        }),
12133                    ) = &comment_prefix
12134                    {
12135                        let line_trimmed = line_trimmed
12136                            .strip_prefix(start.as_ref())
12137                            .map(|s| {
12138                                let mut indent_size = indent_size;
12139                                indent_size.len -= tab_size;
12140                                let indent_prefix: String = indent_size.chars().collect();
12141                                first_line_delimiter = Some((indent_prefix, start));
12142                                s.trim_start()
12143                            })
12144                            .unwrap_or(line_trimmed);
12145                        let line_trimmed = line_trimmed
12146                            .strip_suffix(end.as_ref())
12147                            .map(|s| {
12148                                last_line_delimiter = Some(end);
12149                                s.trim_end()
12150                            })
12151                            .unwrap_or(line_trimmed);
12152                        let line_trimmed = line_trimmed
12153                            .strip_prefix(prefix.as_ref())
12154                            .unwrap_or(line_trimmed);
12155                        Ok(line_trimmed)
12156                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12157                        line_trimmed.strip_prefix(prefix).with_context(|| {
12158                            format!("line did not start with prefix {prefix:?}: {line:?}")
12159                        })
12160                    } else {
12161                        line_trimmed
12162                            .strip_prefix(&line_prefix.trim_start())
12163                            .with_context(|| {
12164                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12165                            })
12166                    }
12167                })
12168                .collect::<Result<Vec<_>, _>>()
12169                .log_err()
12170            else {
12171                continue;
12172            };
12173
12174            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12175                buffer
12176                    .language_settings_at(Point::new(start_row, 0), cx)
12177                    .preferred_line_length as usize
12178            });
12179
12180            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12181                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12182            } else {
12183                line_prefix.clone()
12184            };
12185
12186            let wrapped_text = {
12187                let mut wrapped_text = wrap_with_prefix(
12188                    line_prefix,
12189                    subsequent_lines_prefix,
12190                    lines_without_prefixes.join("\n"),
12191                    wrap_column,
12192                    tab_size,
12193                    options.preserve_existing_whitespace,
12194                );
12195
12196                if let Some((indent, delimiter)) = first_line_delimiter {
12197                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12198                }
12199                if let Some(last_line) = last_line_delimiter {
12200                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12201                }
12202
12203                wrapped_text
12204            };
12205
12206            // TODO: should always use char-based diff while still supporting cursor behavior that
12207            // matches vim.
12208            let mut diff_options = DiffOptions::default();
12209            if options.override_language_settings {
12210                diff_options.max_word_diff_len = 0;
12211                diff_options.max_word_diff_line_count = 0;
12212            } else {
12213                diff_options.max_word_diff_len = usize::MAX;
12214                diff_options.max_word_diff_line_count = usize::MAX;
12215            }
12216
12217            for (old_range, new_text) in
12218                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12219            {
12220                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12221                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12222                edits.push((edit_start..edit_end, new_text));
12223            }
12224
12225            rewrapped_row_ranges.push(start_row..=end_row);
12226        }
12227
12228        self.buffer
12229            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12230    }
12231
12232    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
12233        let mut text = String::new();
12234        let buffer = self.buffer.read(cx).snapshot(cx);
12235        let mut selections = self.selections.all::<Point>(cx);
12236        let mut clipboard_selections = Vec::with_capacity(selections.len());
12237        {
12238            let max_point = buffer.max_point();
12239            let mut is_first = true;
12240            for selection in &mut selections {
12241                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12242                if is_entire_line {
12243                    selection.start = Point::new(selection.start.row, 0);
12244                    if !selection.is_empty() && selection.end.column == 0 {
12245                        selection.end = cmp::min(max_point, selection.end);
12246                    } else {
12247                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12248                    }
12249                    selection.goal = SelectionGoal::None;
12250                }
12251                if is_first {
12252                    is_first = false;
12253                } else {
12254                    text += "\n";
12255                }
12256                let mut len = 0;
12257                for chunk in buffer.text_for_range(selection.start..selection.end) {
12258                    text.push_str(chunk);
12259                    len += chunk.len();
12260                }
12261                clipboard_selections.push(ClipboardSelection {
12262                    len,
12263                    is_entire_line,
12264                    first_line_indent: buffer
12265                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12266                        .len,
12267                });
12268            }
12269        }
12270
12271        self.transact(window, cx, |this, window, cx| {
12272            this.change_selections(Default::default(), window, cx, |s| {
12273                s.select(selections);
12274            });
12275            this.insert("", window, cx);
12276        });
12277        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12278    }
12279
12280    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12281        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12282        let item = self.cut_common(window, cx);
12283        cx.write_to_clipboard(item);
12284    }
12285
12286    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12287        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12288        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12289            s.move_with(|snapshot, sel| {
12290                if sel.is_empty() {
12291                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12292                }
12293            });
12294        });
12295        let item = self.cut_common(window, cx);
12296        cx.set_global(KillRing(item))
12297    }
12298
12299    pub fn kill_ring_yank(
12300        &mut self,
12301        _: &KillRingYank,
12302        window: &mut Window,
12303        cx: &mut Context<Self>,
12304    ) {
12305        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12306        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12307            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12308                (kill_ring.text().to_string(), kill_ring.metadata_json())
12309            } else {
12310                return;
12311            }
12312        } else {
12313            return;
12314        };
12315        self.do_paste(&text, metadata, false, window, cx);
12316    }
12317
12318    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12319        self.do_copy(true, cx);
12320    }
12321
12322    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12323        self.do_copy(false, cx);
12324    }
12325
12326    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12327        let selections = self.selections.all::<Point>(cx);
12328        let buffer = self.buffer.read(cx).read(cx);
12329        let mut text = String::new();
12330
12331        let mut clipboard_selections = Vec::with_capacity(selections.len());
12332        {
12333            let max_point = buffer.max_point();
12334            let mut is_first = true;
12335            for selection in &selections {
12336                let mut start = selection.start;
12337                let mut end = selection.end;
12338                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12339                if is_entire_line {
12340                    start = Point::new(start.row, 0);
12341                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12342                }
12343
12344                let mut trimmed_selections = Vec::new();
12345                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12346                    let row = MultiBufferRow(start.row);
12347                    let first_indent = buffer.indent_size_for_line(row);
12348                    if first_indent.len == 0 || start.column > first_indent.len {
12349                        trimmed_selections.push(start..end);
12350                    } else {
12351                        trimmed_selections.push(
12352                            Point::new(row.0, first_indent.len)
12353                                ..Point::new(row.0, buffer.line_len(row)),
12354                        );
12355                        for row in start.row + 1..=end.row {
12356                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12357                            if row == end.row {
12358                                line_len = end.column;
12359                            }
12360                            if line_len == 0 {
12361                                trimmed_selections
12362                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12363                                continue;
12364                            }
12365                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12366                            if row_indent_size.len >= first_indent.len {
12367                                trimmed_selections.push(
12368                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12369                                );
12370                            } else {
12371                                trimmed_selections.clear();
12372                                trimmed_selections.push(start..end);
12373                                break;
12374                            }
12375                        }
12376                    }
12377                } else {
12378                    trimmed_selections.push(start..end);
12379                }
12380
12381                for trimmed_range in trimmed_selections {
12382                    if is_first {
12383                        is_first = false;
12384                    } else {
12385                        text += "\n";
12386                    }
12387                    let mut len = 0;
12388                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12389                        text.push_str(chunk);
12390                        len += chunk.len();
12391                    }
12392                    clipboard_selections.push(ClipboardSelection {
12393                        len,
12394                        is_entire_line,
12395                        first_line_indent: buffer
12396                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12397                            .len,
12398                    });
12399                }
12400            }
12401        }
12402
12403        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12404            text,
12405            clipboard_selections,
12406        ));
12407    }
12408
12409    pub fn do_paste(
12410        &mut self,
12411        text: &String,
12412        clipboard_selections: Option<Vec<ClipboardSelection>>,
12413        handle_entire_lines: bool,
12414        window: &mut Window,
12415        cx: &mut Context<Self>,
12416    ) {
12417        if self.read_only(cx) {
12418            return;
12419        }
12420
12421        let clipboard_text = Cow::Borrowed(text);
12422
12423        self.transact(window, cx, |this, window, cx| {
12424            let had_active_edit_prediction = this.has_active_edit_prediction();
12425
12426            if let Some(mut clipboard_selections) = clipboard_selections {
12427                let old_selections = this.selections.all::<usize>(cx);
12428                let all_selections_were_entire_line =
12429                    clipboard_selections.iter().all(|s| s.is_entire_line);
12430                let first_selection_indent_column =
12431                    clipboard_selections.first().map(|s| s.first_line_indent);
12432                if clipboard_selections.len() != old_selections.len() {
12433                    clipboard_selections.drain(..);
12434                }
12435                let cursor_offset = this.selections.last::<usize>(cx).head();
12436                let mut auto_indent_on_paste = true;
12437
12438                this.buffer.update(cx, |buffer, cx| {
12439                    let snapshot = buffer.read(cx);
12440                    auto_indent_on_paste = snapshot
12441                        .language_settings_at(cursor_offset, cx)
12442                        .auto_indent_on_paste;
12443
12444                    let mut start_offset = 0;
12445                    let mut edits = Vec::new();
12446                    let mut original_indent_columns = Vec::new();
12447                    for (ix, selection) in old_selections.iter().enumerate() {
12448                        let to_insert;
12449                        let entire_line;
12450                        let original_indent_column;
12451                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12452                            let end_offset = start_offset + clipboard_selection.len;
12453                            to_insert = &clipboard_text[start_offset..end_offset];
12454                            entire_line = clipboard_selection.is_entire_line;
12455                            start_offset = end_offset + 1;
12456                            original_indent_column = Some(clipboard_selection.first_line_indent);
12457                        } else {
12458                            to_insert = clipboard_text.as_str();
12459                            entire_line = all_selections_were_entire_line;
12460                            original_indent_column = first_selection_indent_column
12461                        }
12462
12463                        // If the corresponding selection was empty when this slice of the
12464                        // clipboard text was written, then the entire line containing the
12465                        // selection was copied. If this selection is also currently empty,
12466                        // then paste the line before the current line of the buffer.
12467                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12468                            let column = selection.start.to_point(&snapshot).column as usize;
12469                            let line_start = selection.start - column;
12470                            line_start..line_start
12471                        } else {
12472                            selection.range()
12473                        };
12474
12475                        edits.push((range, to_insert));
12476                        original_indent_columns.push(original_indent_column);
12477                    }
12478                    drop(snapshot);
12479
12480                    buffer.edit(
12481                        edits,
12482                        if auto_indent_on_paste {
12483                            Some(AutoindentMode::Block {
12484                                original_indent_columns,
12485                            })
12486                        } else {
12487                            None
12488                        },
12489                        cx,
12490                    );
12491                });
12492
12493                let selections = this.selections.all::<usize>(cx);
12494                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12495            } else {
12496                this.insert(&clipboard_text, window, cx);
12497            }
12498
12499            let trigger_in_words =
12500                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12501
12502            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12503        });
12504    }
12505
12506    pub fn diff_clipboard_with_selection(
12507        &mut self,
12508        _: &DiffClipboardWithSelection,
12509        window: &mut Window,
12510        cx: &mut Context<Self>,
12511    ) {
12512        let selections = self.selections.all::<usize>(cx);
12513
12514        if selections.is_empty() {
12515            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12516            return;
12517        };
12518
12519        let clipboard_text = match cx.read_from_clipboard() {
12520            Some(item) => match item.entries().first() {
12521                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12522                _ => None,
12523            },
12524            None => None,
12525        };
12526
12527        let Some(clipboard_text) = clipboard_text else {
12528            log::warn!("Clipboard doesn't contain text.");
12529            return;
12530        };
12531
12532        window.dispatch_action(
12533            Box::new(DiffClipboardWithSelectionData {
12534                clipboard_text,
12535                editor: cx.entity(),
12536            }),
12537            cx,
12538        );
12539    }
12540
12541    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12542        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12543        if let Some(item) = cx.read_from_clipboard() {
12544            let entries = item.entries();
12545
12546            match entries.first() {
12547                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12548                // of all the pasted entries.
12549                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12550                    .do_paste(
12551                        clipboard_string.text(),
12552                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12553                        true,
12554                        window,
12555                        cx,
12556                    ),
12557                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12558            }
12559        }
12560    }
12561
12562    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12563        if self.read_only(cx) {
12564            return;
12565        }
12566
12567        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12568
12569        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12570            if let Some((selections, _)) =
12571                self.selection_history.transaction(transaction_id).cloned()
12572            {
12573                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12574                    s.select_anchors(selections.to_vec());
12575                });
12576            } else {
12577                log::error!(
12578                    "No entry in selection_history found for undo. \
12579                     This may correspond to a bug where undo does not update the selection. \
12580                     If this is occurring, please add details to \
12581                     https://github.com/zed-industries/zed/issues/22692"
12582                );
12583            }
12584            self.request_autoscroll(Autoscroll::fit(), cx);
12585            self.unmark_text(window, cx);
12586            self.refresh_edit_prediction(true, false, window, cx);
12587            cx.emit(EditorEvent::Edited { transaction_id });
12588            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12589        }
12590    }
12591
12592    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12593        if self.read_only(cx) {
12594            return;
12595        }
12596
12597        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12598
12599        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12600            if let Some((_, Some(selections))) =
12601                self.selection_history.transaction(transaction_id).cloned()
12602            {
12603                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12604                    s.select_anchors(selections.to_vec());
12605                });
12606            } else {
12607                log::error!(
12608                    "No entry in selection_history found for redo. \
12609                     This may correspond to a bug where undo does not update the selection. \
12610                     If this is occurring, please add details to \
12611                     https://github.com/zed-industries/zed/issues/22692"
12612                );
12613            }
12614            self.request_autoscroll(Autoscroll::fit(), cx);
12615            self.unmark_text(window, cx);
12616            self.refresh_edit_prediction(true, false, window, cx);
12617            cx.emit(EditorEvent::Edited { transaction_id });
12618        }
12619    }
12620
12621    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12622        self.buffer
12623            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12624    }
12625
12626    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12627        self.buffer
12628            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12629    }
12630
12631    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12632        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12633        self.change_selections(Default::default(), window, cx, |s| {
12634            s.move_with(|map, selection| {
12635                let cursor = if selection.is_empty() {
12636                    movement::left(map, selection.start)
12637                } else {
12638                    selection.start
12639                };
12640                selection.collapse_to(cursor, SelectionGoal::None);
12641            });
12642        })
12643    }
12644
12645    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12646        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12647        self.change_selections(Default::default(), window, cx, |s| {
12648            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12649        })
12650    }
12651
12652    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12653        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12654        self.change_selections(Default::default(), window, cx, |s| {
12655            s.move_with(|map, selection| {
12656                let cursor = if selection.is_empty() {
12657                    movement::right(map, selection.end)
12658                } else {
12659                    selection.end
12660                };
12661                selection.collapse_to(cursor, SelectionGoal::None)
12662            });
12663        })
12664    }
12665
12666    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12667        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12668        self.change_selections(Default::default(), window, cx, |s| {
12669            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12670        })
12671    }
12672
12673    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12674        if self.take_rename(true, window, cx).is_some() {
12675            return;
12676        }
12677
12678        if self.mode.is_single_line() {
12679            cx.propagate();
12680            return;
12681        }
12682
12683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12684
12685        let text_layout_details = &self.text_layout_details(window);
12686        let selection_count = self.selections.count();
12687        let first_selection = self.selections.first_anchor();
12688
12689        self.change_selections(Default::default(), window, cx, |s| {
12690            s.move_with(|map, selection| {
12691                if !selection.is_empty() {
12692                    selection.goal = SelectionGoal::None;
12693                }
12694                let (cursor, goal) = movement::up(
12695                    map,
12696                    selection.start,
12697                    selection.goal,
12698                    false,
12699                    text_layout_details,
12700                );
12701                selection.collapse_to(cursor, goal);
12702            });
12703        });
12704
12705        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12706        {
12707            cx.propagate();
12708        }
12709    }
12710
12711    pub fn move_up_by_lines(
12712        &mut self,
12713        action: &MoveUpByLines,
12714        window: &mut Window,
12715        cx: &mut Context<Self>,
12716    ) {
12717        if self.take_rename(true, window, cx).is_some() {
12718            return;
12719        }
12720
12721        if self.mode.is_single_line() {
12722            cx.propagate();
12723            return;
12724        }
12725
12726        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12727
12728        let text_layout_details = &self.text_layout_details(window);
12729
12730        self.change_selections(Default::default(), window, cx, |s| {
12731            s.move_with(|map, selection| {
12732                if !selection.is_empty() {
12733                    selection.goal = SelectionGoal::None;
12734                }
12735                let (cursor, goal) = movement::up_by_rows(
12736                    map,
12737                    selection.start,
12738                    action.lines,
12739                    selection.goal,
12740                    false,
12741                    text_layout_details,
12742                );
12743                selection.collapse_to(cursor, goal);
12744            });
12745        })
12746    }
12747
12748    pub fn move_down_by_lines(
12749        &mut self,
12750        action: &MoveDownByLines,
12751        window: &mut Window,
12752        cx: &mut Context<Self>,
12753    ) {
12754        if self.take_rename(true, window, cx).is_some() {
12755            return;
12756        }
12757
12758        if self.mode.is_single_line() {
12759            cx.propagate();
12760            return;
12761        }
12762
12763        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12764
12765        let text_layout_details = &self.text_layout_details(window);
12766
12767        self.change_selections(Default::default(), window, cx, |s| {
12768            s.move_with(|map, selection| {
12769                if !selection.is_empty() {
12770                    selection.goal = SelectionGoal::None;
12771                }
12772                let (cursor, goal) = movement::down_by_rows(
12773                    map,
12774                    selection.start,
12775                    action.lines,
12776                    selection.goal,
12777                    false,
12778                    text_layout_details,
12779                );
12780                selection.collapse_to(cursor, goal);
12781            });
12782        })
12783    }
12784
12785    pub fn select_down_by_lines(
12786        &mut self,
12787        action: &SelectDownByLines,
12788        window: &mut Window,
12789        cx: &mut Context<Self>,
12790    ) {
12791        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12792        let text_layout_details = &self.text_layout_details(window);
12793        self.change_selections(Default::default(), window, cx, |s| {
12794            s.move_heads_with(|map, head, goal| {
12795                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12796            })
12797        })
12798    }
12799
12800    pub fn select_up_by_lines(
12801        &mut self,
12802        action: &SelectUpByLines,
12803        window: &mut Window,
12804        cx: &mut Context<Self>,
12805    ) {
12806        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12807        let text_layout_details = &self.text_layout_details(window);
12808        self.change_selections(Default::default(), window, cx, |s| {
12809            s.move_heads_with(|map, head, goal| {
12810                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12811            })
12812        })
12813    }
12814
12815    pub fn select_page_up(
12816        &mut self,
12817        _: &SelectPageUp,
12818        window: &mut Window,
12819        cx: &mut Context<Self>,
12820    ) {
12821        let Some(row_count) = self.visible_row_count() else {
12822            return;
12823        };
12824
12825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12826
12827        let text_layout_details = &self.text_layout_details(window);
12828
12829        self.change_selections(Default::default(), window, cx, |s| {
12830            s.move_heads_with(|map, head, goal| {
12831                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12832            })
12833        })
12834    }
12835
12836    pub fn move_page_up(
12837        &mut self,
12838        action: &MovePageUp,
12839        window: &mut Window,
12840        cx: &mut Context<Self>,
12841    ) {
12842        if self.take_rename(true, window, cx).is_some() {
12843            return;
12844        }
12845
12846        if self
12847            .context_menu
12848            .borrow_mut()
12849            .as_mut()
12850            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12851            .unwrap_or(false)
12852        {
12853            return;
12854        }
12855
12856        if matches!(self.mode, EditorMode::SingleLine) {
12857            cx.propagate();
12858            return;
12859        }
12860
12861        let Some(row_count) = self.visible_row_count() else {
12862            return;
12863        };
12864
12865        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12866
12867        let effects = if action.center_cursor {
12868            SelectionEffects::scroll(Autoscroll::center())
12869        } else {
12870            SelectionEffects::default()
12871        };
12872
12873        let text_layout_details = &self.text_layout_details(window);
12874
12875        self.change_selections(effects, window, cx, |s| {
12876            s.move_with(|map, selection| {
12877                if !selection.is_empty() {
12878                    selection.goal = SelectionGoal::None;
12879                }
12880                let (cursor, goal) = movement::up_by_rows(
12881                    map,
12882                    selection.end,
12883                    row_count,
12884                    selection.goal,
12885                    false,
12886                    text_layout_details,
12887                );
12888                selection.collapse_to(cursor, goal);
12889            });
12890        });
12891    }
12892
12893    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12894        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12895        let text_layout_details = &self.text_layout_details(window);
12896        self.change_selections(Default::default(), window, cx, |s| {
12897            s.move_heads_with(|map, head, goal| {
12898                movement::up(map, head, goal, false, text_layout_details)
12899            })
12900        })
12901    }
12902
12903    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12904        self.take_rename(true, window, cx);
12905
12906        if self.mode.is_single_line() {
12907            cx.propagate();
12908            return;
12909        }
12910
12911        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12912
12913        let text_layout_details = &self.text_layout_details(window);
12914        let selection_count = self.selections.count();
12915        let first_selection = self.selections.first_anchor();
12916
12917        self.change_selections(Default::default(), window, cx, |s| {
12918            s.move_with(|map, selection| {
12919                if !selection.is_empty() {
12920                    selection.goal = SelectionGoal::None;
12921                }
12922                let (cursor, goal) = movement::down(
12923                    map,
12924                    selection.end,
12925                    selection.goal,
12926                    false,
12927                    text_layout_details,
12928                );
12929                selection.collapse_to(cursor, goal);
12930            });
12931        });
12932
12933        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12934        {
12935            cx.propagate();
12936        }
12937    }
12938
12939    pub fn select_page_down(
12940        &mut self,
12941        _: &SelectPageDown,
12942        window: &mut Window,
12943        cx: &mut Context<Self>,
12944    ) {
12945        let Some(row_count) = self.visible_row_count() else {
12946            return;
12947        };
12948
12949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12950
12951        let text_layout_details = &self.text_layout_details(window);
12952
12953        self.change_selections(Default::default(), window, cx, |s| {
12954            s.move_heads_with(|map, head, goal| {
12955                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12956            })
12957        })
12958    }
12959
12960    pub fn move_page_down(
12961        &mut self,
12962        action: &MovePageDown,
12963        window: &mut Window,
12964        cx: &mut Context<Self>,
12965    ) {
12966        if self.take_rename(true, window, cx).is_some() {
12967            return;
12968        }
12969
12970        if self
12971            .context_menu
12972            .borrow_mut()
12973            .as_mut()
12974            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12975            .unwrap_or(false)
12976        {
12977            return;
12978        }
12979
12980        if matches!(self.mode, EditorMode::SingleLine) {
12981            cx.propagate();
12982            return;
12983        }
12984
12985        let Some(row_count) = self.visible_row_count() else {
12986            return;
12987        };
12988
12989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12990
12991        let effects = if action.center_cursor {
12992            SelectionEffects::scroll(Autoscroll::center())
12993        } else {
12994            SelectionEffects::default()
12995        };
12996
12997        let text_layout_details = &self.text_layout_details(window);
12998        self.change_selections(effects, window, cx, |s| {
12999            s.move_with(|map, selection| {
13000                if !selection.is_empty() {
13001                    selection.goal = SelectionGoal::None;
13002                }
13003                let (cursor, goal) = movement::down_by_rows(
13004                    map,
13005                    selection.end,
13006                    row_count,
13007                    selection.goal,
13008                    false,
13009                    text_layout_details,
13010                );
13011                selection.collapse_to(cursor, goal);
13012            });
13013        });
13014    }
13015
13016    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13017        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13018        let text_layout_details = &self.text_layout_details(window);
13019        self.change_selections(Default::default(), window, cx, |s| {
13020            s.move_heads_with(|map, head, goal| {
13021                movement::down(map, head, goal, false, text_layout_details)
13022            })
13023        });
13024    }
13025
13026    pub fn context_menu_first(
13027        &mut self,
13028        _: &ContextMenuFirst,
13029        window: &mut Window,
13030        cx: &mut Context<Self>,
13031    ) {
13032        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13033            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13034        }
13035    }
13036
13037    pub fn context_menu_prev(
13038        &mut self,
13039        _: &ContextMenuPrevious,
13040        window: &mut Window,
13041        cx: &mut Context<Self>,
13042    ) {
13043        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13044            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13045        }
13046    }
13047
13048    pub fn context_menu_next(
13049        &mut self,
13050        _: &ContextMenuNext,
13051        window: &mut Window,
13052        cx: &mut Context<Self>,
13053    ) {
13054        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13055            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13056        }
13057    }
13058
13059    pub fn context_menu_last(
13060        &mut self,
13061        _: &ContextMenuLast,
13062        window: &mut Window,
13063        cx: &mut Context<Self>,
13064    ) {
13065        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13066            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13067        }
13068    }
13069
13070    pub fn signature_help_prev(
13071        &mut self,
13072        _: &SignatureHelpPrevious,
13073        _: &mut Window,
13074        cx: &mut Context<Self>,
13075    ) {
13076        if let Some(popover) = self.signature_help_state.popover_mut() {
13077            if popover.current_signature == 0 {
13078                popover.current_signature = popover.signatures.len() - 1;
13079            } else {
13080                popover.current_signature -= 1;
13081            }
13082            cx.notify();
13083        }
13084    }
13085
13086    pub fn signature_help_next(
13087        &mut self,
13088        _: &SignatureHelpNext,
13089        _: &mut Window,
13090        cx: &mut Context<Self>,
13091    ) {
13092        if let Some(popover) = self.signature_help_state.popover_mut() {
13093            if popover.current_signature + 1 == popover.signatures.len() {
13094                popover.current_signature = 0;
13095            } else {
13096                popover.current_signature += 1;
13097            }
13098            cx.notify();
13099        }
13100    }
13101
13102    pub fn move_to_previous_word_start(
13103        &mut self,
13104        _: &MoveToPreviousWordStart,
13105        window: &mut Window,
13106        cx: &mut Context<Self>,
13107    ) {
13108        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13109        self.change_selections(Default::default(), window, cx, |s| {
13110            s.move_cursors_with(|map, head, _| {
13111                (
13112                    movement::previous_word_start(map, head),
13113                    SelectionGoal::None,
13114                )
13115            });
13116        })
13117    }
13118
13119    pub fn move_to_previous_subword_start(
13120        &mut self,
13121        _: &MoveToPreviousSubwordStart,
13122        window: &mut Window,
13123        cx: &mut Context<Self>,
13124    ) {
13125        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13126        self.change_selections(Default::default(), window, cx, |s| {
13127            s.move_cursors_with(|map, head, _| {
13128                (
13129                    movement::previous_subword_start(map, head),
13130                    SelectionGoal::None,
13131                )
13132            });
13133        })
13134    }
13135
13136    pub fn select_to_previous_word_start(
13137        &mut self,
13138        _: &SelectToPreviousWordStart,
13139        window: &mut Window,
13140        cx: &mut Context<Self>,
13141    ) {
13142        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13143        self.change_selections(Default::default(), window, cx, |s| {
13144            s.move_heads_with(|map, head, _| {
13145                (
13146                    movement::previous_word_start(map, head),
13147                    SelectionGoal::None,
13148                )
13149            });
13150        })
13151    }
13152
13153    pub fn select_to_previous_subword_start(
13154        &mut self,
13155        _: &SelectToPreviousSubwordStart,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13160        self.change_selections(Default::default(), window, cx, |s| {
13161            s.move_heads_with(|map, head, _| {
13162                (
13163                    movement::previous_subword_start(map, head),
13164                    SelectionGoal::None,
13165                )
13166            });
13167        })
13168    }
13169
13170    pub fn delete_to_previous_word_start(
13171        &mut self,
13172        action: &DeleteToPreviousWordStart,
13173        window: &mut Window,
13174        cx: &mut Context<Self>,
13175    ) {
13176        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13177        self.transact(window, cx, |this, window, cx| {
13178            this.select_autoclose_pair(window, cx);
13179            this.change_selections(Default::default(), window, cx, |s| {
13180                s.move_with(|map, selection| {
13181                    if selection.is_empty() {
13182                        let mut cursor = if action.ignore_newlines {
13183                            movement::previous_word_start(map, selection.head())
13184                        } else {
13185                            movement::previous_word_start_or_newline(map, selection.head())
13186                        };
13187                        cursor = movement::adjust_greedy_deletion(
13188                            map,
13189                            selection.head(),
13190                            cursor,
13191                            action.ignore_brackets,
13192                        );
13193                        selection.set_head(cursor, SelectionGoal::None);
13194                    }
13195                });
13196            });
13197            this.insert("", window, cx);
13198        });
13199    }
13200
13201    pub fn delete_to_previous_subword_start(
13202        &mut self,
13203        _: &DeleteToPreviousSubwordStart,
13204        window: &mut Window,
13205        cx: &mut Context<Self>,
13206    ) {
13207        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13208        self.transact(window, cx, |this, window, cx| {
13209            this.select_autoclose_pair(window, cx);
13210            this.change_selections(Default::default(), window, cx, |s| {
13211                s.move_with(|map, selection| {
13212                    if selection.is_empty() {
13213                        let mut cursor = movement::previous_subword_start(map, selection.head());
13214                        cursor =
13215                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13216                        selection.set_head(cursor, SelectionGoal::None);
13217                    }
13218                });
13219            });
13220            this.insert("", window, cx);
13221        });
13222    }
13223
13224    pub fn move_to_next_word_end(
13225        &mut self,
13226        _: &MoveToNextWordEnd,
13227        window: &mut Window,
13228        cx: &mut Context<Self>,
13229    ) {
13230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13231        self.change_selections(Default::default(), window, cx, |s| {
13232            s.move_cursors_with(|map, head, _| {
13233                (movement::next_word_end(map, head), SelectionGoal::None)
13234            });
13235        })
13236    }
13237
13238    pub fn move_to_next_subword_end(
13239        &mut self,
13240        _: &MoveToNextSubwordEnd,
13241        window: &mut Window,
13242        cx: &mut Context<Self>,
13243    ) {
13244        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13245        self.change_selections(Default::default(), window, cx, |s| {
13246            s.move_cursors_with(|map, head, _| {
13247                (movement::next_subword_end(map, head), SelectionGoal::None)
13248            });
13249        })
13250    }
13251
13252    pub fn select_to_next_word_end(
13253        &mut self,
13254        _: &SelectToNextWordEnd,
13255        window: &mut Window,
13256        cx: &mut Context<Self>,
13257    ) {
13258        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13259        self.change_selections(Default::default(), window, cx, |s| {
13260            s.move_heads_with(|map, head, _| {
13261                (movement::next_word_end(map, head), SelectionGoal::None)
13262            });
13263        })
13264    }
13265
13266    pub fn select_to_next_subword_end(
13267        &mut self,
13268        _: &SelectToNextSubwordEnd,
13269        window: &mut Window,
13270        cx: &mut Context<Self>,
13271    ) {
13272        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13273        self.change_selections(Default::default(), window, cx, |s| {
13274            s.move_heads_with(|map, head, _| {
13275                (movement::next_subword_end(map, head), SelectionGoal::None)
13276            });
13277        })
13278    }
13279
13280    pub fn delete_to_next_word_end(
13281        &mut self,
13282        action: &DeleteToNextWordEnd,
13283        window: &mut Window,
13284        cx: &mut Context<Self>,
13285    ) {
13286        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13287        self.transact(window, cx, |this, window, cx| {
13288            this.change_selections(Default::default(), window, cx, |s| {
13289                s.move_with(|map, selection| {
13290                    if selection.is_empty() {
13291                        let mut cursor = if action.ignore_newlines {
13292                            movement::next_word_end(map, selection.head())
13293                        } else {
13294                            movement::next_word_end_or_newline(map, selection.head())
13295                        };
13296                        cursor = movement::adjust_greedy_deletion(
13297                            map,
13298                            selection.head(),
13299                            cursor,
13300                            action.ignore_brackets,
13301                        );
13302                        selection.set_head(cursor, SelectionGoal::None);
13303                    }
13304                });
13305            });
13306            this.insert("", window, cx);
13307        });
13308    }
13309
13310    pub fn delete_to_next_subword_end(
13311        &mut self,
13312        _: &DeleteToNextSubwordEnd,
13313        window: &mut Window,
13314        cx: &mut Context<Self>,
13315    ) {
13316        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13317        self.transact(window, cx, |this, window, cx| {
13318            this.change_selections(Default::default(), window, cx, |s| {
13319                s.move_with(|map, selection| {
13320                    if selection.is_empty() {
13321                        let mut cursor = movement::next_subword_end(map, selection.head());
13322                        cursor =
13323                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13324                        selection.set_head(cursor, SelectionGoal::None);
13325                    }
13326                });
13327            });
13328            this.insert("", window, cx);
13329        });
13330    }
13331
13332    pub fn move_to_beginning_of_line(
13333        &mut self,
13334        action: &MoveToBeginningOfLine,
13335        window: &mut Window,
13336        cx: &mut Context<Self>,
13337    ) {
13338        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13339        self.change_selections(Default::default(), window, cx, |s| {
13340            s.move_cursors_with(|map, head, _| {
13341                (
13342                    movement::indented_line_beginning(
13343                        map,
13344                        head,
13345                        action.stop_at_soft_wraps,
13346                        action.stop_at_indent,
13347                    ),
13348                    SelectionGoal::None,
13349                )
13350            });
13351        })
13352    }
13353
13354    pub fn select_to_beginning_of_line(
13355        &mut self,
13356        action: &SelectToBeginningOfLine,
13357        window: &mut Window,
13358        cx: &mut Context<Self>,
13359    ) {
13360        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13361        self.change_selections(Default::default(), window, cx, |s| {
13362            s.move_heads_with(|map, head, _| {
13363                (
13364                    movement::indented_line_beginning(
13365                        map,
13366                        head,
13367                        action.stop_at_soft_wraps,
13368                        action.stop_at_indent,
13369                    ),
13370                    SelectionGoal::None,
13371                )
13372            });
13373        });
13374    }
13375
13376    pub fn delete_to_beginning_of_line(
13377        &mut self,
13378        action: &DeleteToBeginningOfLine,
13379        window: &mut Window,
13380        cx: &mut Context<Self>,
13381    ) {
13382        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13383        self.transact(window, cx, |this, window, cx| {
13384            this.change_selections(Default::default(), window, cx, |s| {
13385                s.move_with(|_, selection| {
13386                    selection.reversed = true;
13387                });
13388            });
13389
13390            this.select_to_beginning_of_line(
13391                &SelectToBeginningOfLine {
13392                    stop_at_soft_wraps: false,
13393                    stop_at_indent: action.stop_at_indent,
13394                },
13395                window,
13396                cx,
13397            );
13398            this.backspace(&Backspace, window, cx);
13399        });
13400    }
13401
13402    pub fn move_to_end_of_line(
13403        &mut self,
13404        action: &MoveToEndOfLine,
13405        window: &mut Window,
13406        cx: &mut Context<Self>,
13407    ) {
13408        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13409        self.change_selections(Default::default(), window, cx, |s| {
13410            s.move_cursors_with(|map, head, _| {
13411                (
13412                    movement::line_end(map, head, action.stop_at_soft_wraps),
13413                    SelectionGoal::None,
13414                )
13415            });
13416        })
13417    }
13418
13419    pub fn select_to_end_of_line(
13420        &mut self,
13421        action: &SelectToEndOfLine,
13422        window: &mut Window,
13423        cx: &mut Context<Self>,
13424    ) {
13425        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13426        self.change_selections(Default::default(), window, cx, |s| {
13427            s.move_heads_with(|map, head, _| {
13428                (
13429                    movement::line_end(map, head, action.stop_at_soft_wraps),
13430                    SelectionGoal::None,
13431                )
13432            });
13433        })
13434    }
13435
13436    pub fn delete_to_end_of_line(
13437        &mut self,
13438        _: &DeleteToEndOfLine,
13439        window: &mut Window,
13440        cx: &mut Context<Self>,
13441    ) {
13442        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13443        self.transact(window, cx, |this, window, cx| {
13444            this.select_to_end_of_line(
13445                &SelectToEndOfLine {
13446                    stop_at_soft_wraps: false,
13447                },
13448                window,
13449                cx,
13450            );
13451            this.delete(&Delete, window, cx);
13452        });
13453    }
13454
13455    pub fn cut_to_end_of_line(
13456        &mut self,
13457        _: &CutToEndOfLine,
13458        window: &mut Window,
13459        cx: &mut Context<Self>,
13460    ) {
13461        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13462        self.transact(window, cx, |this, window, cx| {
13463            this.select_to_end_of_line(
13464                &SelectToEndOfLine {
13465                    stop_at_soft_wraps: false,
13466                },
13467                window,
13468                cx,
13469            );
13470            this.cut(&Cut, window, cx);
13471        });
13472    }
13473
13474    pub fn move_to_start_of_paragraph(
13475        &mut self,
13476        _: &MoveToStartOfParagraph,
13477        window: &mut Window,
13478        cx: &mut Context<Self>,
13479    ) {
13480        if matches!(self.mode, EditorMode::SingleLine) {
13481            cx.propagate();
13482            return;
13483        }
13484        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13485        self.change_selections(Default::default(), window, cx, |s| {
13486            s.move_with(|map, selection| {
13487                selection.collapse_to(
13488                    movement::start_of_paragraph(map, selection.head(), 1),
13489                    SelectionGoal::None,
13490                )
13491            });
13492        })
13493    }
13494
13495    pub fn move_to_end_of_paragraph(
13496        &mut self,
13497        _: &MoveToEndOfParagraph,
13498        window: &mut Window,
13499        cx: &mut Context<Self>,
13500    ) {
13501        if matches!(self.mode, EditorMode::SingleLine) {
13502            cx.propagate();
13503            return;
13504        }
13505        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13506        self.change_selections(Default::default(), window, cx, |s| {
13507            s.move_with(|map, selection| {
13508                selection.collapse_to(
13509                    movement::end_of_paragraph(map, selection.head(), 1),
13510                    SelectionGoal::None,
13511                )
13512            });
13513        })
13514    }
13515
13516    pub fn select_to_start_of_paragraph(
13517        &mut self,
13518        _: &SelectToStartOfParagraph,
13519        window: &mut Window,
13520        cx: &mut Context<Self>,
13521    ) {
13522        if matches!(self.mode, EditorMode::SingleLine) {
13523            cx.propagate();
13524            return;
13525        }
13526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13527        self.change_selections(Default::default(), window, cx, |s| {
13528            s.move_heads_with(|map, head, _| {
13529                (
13530                    movement::start_of_paragraph(map, head, 1),
13531                    SelectionGoal::None,
13532                )
13533            });
13534        })
13535    }
13536
13537    pub fn select_to_end_of_paragraph(
13538        &mut self,
13539        _: &SelectToEndOfParagraph,
13540        window: &mut Window,
13541        cx: &mut Context<Self>,
13542    ) {
13543        if matches!(self.mode, EditorMode::SingleLine) {
13544            cx.propagate();
13545            return;
13546        }
13547        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13548        self.change_selections(Default::default(), window, cx, |s| {
13549            s.move_heads_with(|map, head, _| {
13550                (
13551                    movement::end_of_paragraph(map, head, 1),
13552                    SelectionGoal::None,
13553                )
13554            });
13555        })
13556    }
13557
13558    pub fn move_to_start_of_excerpt(
13559        &mut self,
13560        _: &MoveToStartOfExcerpt,
13561        window: &mut Window,
13562        cx: &mut Context<Self>,
13563    ) {
13564        if matches!(self.mode, EditorMode::SingleLine) {
13565            cx.propagate();
13566            return;
13567        }
13568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13569        self.change_selections(Default::default(), window, cx, |s| {
13570            s.move_with(|map, selection| {
13571                selection.collapse_to(
13572                    movement::start_of_excerpt(
13573                        map,
13574                        selection.head(),
13575                        workspace::searchable::Direction::Prev,
13576                    ),
13577                    SelectionGoal::None,
13578                )
13579            });
13580        })
13581    }
13582
13583    pub fn move_to_start_of_next_excerpt(
13584        &mut self,
13585        _: &MoveToStartOfNextExcerpt,
13586        window: &mut Window,
13587        cx: &mut Context<Self>,
13588    ) {
13589        if matches!(self.mode, EditorMode::SingleLine) {
13590            cx.propagate();
13591            return;
13592        }
13593
13594        self.change_selections(Default::default(), window, cx, |s| {
13595            s.move_with(|map, selection| {
13596                selection.collapse_to(
13597                    movement::start_of_excerpt(
13598                        map,
13599                        selection.head(),
13600                        workspace::searchable::Direction::Next,
13601                    ),
13602                    SelectionGoal::None,
13603                )
13604            });
13605        })
13606    }
13607
13608    pub fn move_to_end_of_excerpt(
13609        &mut self,
13610        _: &MoveToEndOfExcerpt,
13611        window: &mut Window,
13612        cx: &mut Context<Self>,
13613    ) {
13614        if matches!(self.mode, EditorMode::SingleLine) {
13615            cx.propagate();
13616            return;
13617        }
13618        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13619        self.change_selections(Default::default(), window, cx, |s| {
13620            s.move_with(|map, selection| {
13621                selection.collapse_to(
13622                    movement::end_of_excerpt(
13623                        map,
13624                        selection.head(),
13625                        workspace::searchable::Direction::Next,
13626                    ),
13627                    SelectionGoal::None,
13628                )
13629            });
13630        })
13631    }
13632
13633    pub fn move_to_end_of_previous_excerpt(
13634        &mut self,
13635        _: &MoveToEndOfPreviousExcerpt,
13636        window: &mut Window,
13637        cx: &mut Context<Self>,
13638    ) {
13639        if matches!(self.mode, EditorMode::SingleLine) {
13640            cx.propagate();
13641            return;
13642        }
13643        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13644        self.change_selections(Default::default(), window, cx, |s| {
13645            s.move_with(|map, selection| {
13646                selection.collapse_to(
13647                    movement::end_of_excerpt(
13648                        map,
13649                        selection.head(),
13650                        workspace::searchable::Direction::Prev,
13651                    ),
13652                    SelectionGoal::None,
13653                )
13654            });
13655        })
13656    }
13657
13658    pub fn select_to_start_of_excerpt(
13659        &mut self,
13660        _: &SelectToStartOfExcerpt,
13661        window: &mut Window,
13662        cx: &mut Context<Self>,
13663    ) {
13664        if matches!(self.mode, EditorMode::SingleLine) {
13665            cx.propagate();
13666            return;
13667        }
13668        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13669        self.change_selections(Default::default(), window, cx, |s| {
13670            s.move_heads_with(|map, head, _| {
13671                (
13672                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13673                    SelectionGoal::None,
13674                )
13675            });
13676        })
13677    }
13678
13679    pub fn select_to_start_of_next_excerpt(
13680        &mut self,
13681        _: &SelectToStartOfNextExcerpt,
13682        window: &mut Window,
13683        cx: &mut Context<Self>,
13684    ) {
13685        if matches!(self.mode, EditorMode::SingleLine) {
13686            cx.propagate();
13687            return;
13688        }
13689        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13690        self.change_selections(Default::default(), window, cx, |s| {
13691            s.move_heads_with(|map, head, _| {
13692                (
13693                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13694                    SelectionGoal::None,
13695                )
13696            });
13697        })
13698    }
13699
13700    pub fn select_to_end_of_excerpt(
13701        &mut self,
13702        _: &SelectToEndOfExcerpt,
13703        window: &mut Window,
13704        cx: &mut Context<Self>,
13705    ) {
13706        if matches!(self.mode, EditorMode::SingleLine) {
13707            cx.propagate();
13708            return;
13709        }
13710        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13711        self.change_selections(Default::default(), window, cx, |s| {
13712            s.move_heads_with(|map, head, _| {
13713                (
13714                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13715                    SelectionGoal::None,
13716                )
13717            });
13718        })
13719    }
13720
13721    pub fn select_to_end_of_previous_excerpt(
13722        &mut self,
13723        _: &SelectToEndOfPreviousExcerpt,
13724        window: &mut Window,
13725        cx: &mut Context<Self>,
13726    ) {
13727        if matches!(self.mode, EditorMode::SingleLine) {
13728            cx.propagate();
13729            return;
13730        }
13731        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13732        self.change_selections(Default::default(), window, cx, |s| {
13733            s.move_heads_with(|map, head, _| {
13734                (
13735                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13736                    SelectionGoal::None,
13737                )
13738            });
13739        })
13740    }
13741
13742    pub fn move_to_beginning(
13743        &mut self,
13744        _: &MoveToBeginning,
13745        window: &mut Window,
13746        cx: &mut Context<Self>,
13747    ) {
13748        if matches!(self.mode, EditorMode::SingleLine) {
13749            cx.propagate();
13750            return;
13751        }
13752        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13753        self.change_selections(Default::default(), window, cx, |s| {
13754            s.select_ranges(vec![0..0]);
13755        });
13756    }
13757
13758    pub fn select_to_beginning(
13759        &mut self,
13760        _: &SelectToBeginning,
13761        window: &mut Window,
13762        cx: &mut Context<Self>,
13763    ) {
13764        let mut selection = self.selections.last::<Point>(cx);
13765        selection.set_head(Point::zero(), SelectionGoal::None);
13766        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13767        self.change_selections(Default::default(), window, cx, |s| {
13768            s.select(vec![selection]);
13769        });
13770    }
13771
13772    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13773        if matches!(self.mode, EditorMode::SingleLine) {
13774            cx.propagate();
13775            return;
13776        }
13777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13778        let cursor = self.buffer.read(cx).read(cx).len();
13779        self.change_selections(Default::default(), window, cx, |s| {
13780            s.select_ranges(vec![cursor..cursor])
13781        });
13782    }
13783
13784    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13785        self.nav_history = nav_history;
13786    }
13787
13788    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13789        self.nav_history.as_ref()
13790    }
13791
13792    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13793        self.push_to_nav_history(
13794            self.selections.newest_anchor().head(),
13795            None,
13796            false,
13797            true,
13798            cx,
13799        );
13800    }
13801
13802    fn push_to_nav_history(
13803        &mut self,
13804        cursor_anchor: Anchor,
13805        new_position: Option<Point>,
13806        is_deactivate: bool,
13807        always: bool,
13808        cx: &mut Context<Self>,
13809    ) {
13810        if let Some(nav_history) = self.nav_history.as_mut() {
13811            let buffer = self.buffer.read(cx).read(cx);
13812            let cursor_position = cursor_anchor.to_point(&buffer);
13813            let scroll_state = self.scroll_manager.anchor();
13814            let scroll_top_row = scroll_state.top_row(&buffer);
13815            drop(buffer);
13816
13817            if let Some(new_position) = new_position {
13818                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13819                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13820                    return;
13821                }
13822            }
13823
13824            nav_history.push(
13825                Some(NavigationData {
13826                    cursor_anchor,
13827                    cursor_position,
13828                    scroll_anchor: scroll_state,
13829                    scroll_top_row,
13830                }),
13831                cx,
13832            );
13833            cx.emit(EditorEvent::PushedToNavHistory {
13834                anchor: cursor_anchor,
13835                is_deactivate,
13836            })
13837        }
13838    }
13839
13840    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13841        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13842        let buffer = self.buffer.read(cx).snapshot(cx);
13843        let mut selection = self.selections.first::<usize>(cx);
13844        selection.set_head(buffer.len(), SelectionGoal::None);
13845        self.change_selections(Default::default(), window, cx, |s| {
13846            s.select(vec![selection]);
13847        });
13848    }
13849
13850    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13851        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13852        let end = self.buffer.read(cx).read(cx).len();
13853        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13854            s.select_ranges(vec![0..end]);
13855        });
13856    }
13857
13858    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13859        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13860        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13861        let mut selections = self.selections.all::<Point>(cx);
13862        let max_point = display_map.buffer_snapshot.max_point();
13863        for selection in &mut selections {
13864            let rows = selection.spanned_rows(true, &display_map);
13865            selection.start = Point::new(rows.start.0, 0);
13866            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13867            selection.reversed = false;
13868        }
13869        self.change_selections(Default::default(), window, cx, |s| {
13870            s.select(selections);
13871        });
13872    }
13873
13874    pub fn split_selection_into_lines(
13875        &mut self,
13876        action: &SplitSelectionIntoLines,
13877        window: &mut Window,
13878        cx: &mut Context<Self>,
13879    ) {
13880        let selections = self
13881            .selections
13882            .all::<Point>(cx)
13883            .into_iter()
13884            .map(|selection| selection.start..selection.end)
13885            .collect::<Vec<_>>();
13886        self.unfold_ranges(&selections, true, true, cx);
13887
13888        let mut new_selection_ranges = Vec::new();
13889        {
13890            let buffer = self.buffer.read(cx).read(cx);
13891            for selection in selections {
13892                for row in selection.start.row..selection.end.row {
13893                    let line_start = Point::new(row, 0);
13894                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13895
13896                    if action.keep_selections {
13897                        // Keep the selection range for each line
13898                        let selection_start = if row == selection.start.row {
13899                            selection.start
13900                        } else {
13901                            line_start
13902                        };
13903                        new_selection_ranges.push(selection_start..line_end);
13904                    } else {
13905                        // Collapse to cursor at end of line
13906                        new_selection_ranges.push(line_end..line_end);
13907                    }
13908                }
13909
13910                let is_multiline_selection = selection.start.row != selection.end.row;
13911                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13912                // so this action feels more ergonomic when paired with other selection operations
13913                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13914                if !should_skip_last {
13915                    if action.keep_selections {
13916                        if is_multiline_selection {
13917                            let line_start = Point::new(selection.end.row, 0);
13918                            new_selection_ranges.push(line_start..selection.end);
13919                        } else {
13920                            new_selection_ranges.push(selection.start..selection.end);
13921                        }
13922                    } else {
13923                        new_selection_ranges.push(selection.end..selection.end);
13924                    }
13925                }
13926            }
13927        }
13928        self.change_selections(Default::default(), window, cx, |s| {
13929            s.select_ranges(new_selection_ranges);
13930        });
13931    }
13932
13933    pub fn add_selection_above(
13934        &mut self,
13935        _: &AddSelectionAbove,
13936        window: &mut Window,
13937        cx: &mut Context<Self>,
13938    ) {
13939        self.add_selection(true, window, cx);
13940    }
13941
13942    pub fn add_selection_below(
13943        &mut self,
13944        _: &AddSelectionBelow,
13945        window: &mut Window,
13946        cx: &mut Context<Self>,
13947    ) {
13948        self.add_selection(false, window, cx);
13949    }
13950
13951    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13952        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13953
13954        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13955        let all_selections = self.selections.all::<Point>(cx);
13956        let text_layout_details = self.text_layout_details(window);
13957
13958        let (mut columnar_selections, new_selections_to_columnarize) = {
13959            if let Some(state) = self.add_selections_state.as_ref() {
13960                let columnar_selection_ids: HashSet<_> = state
13961                    .groups
13962                    .iter()
13963                    .flat_map(|group| group.stack.iter())
13964                    .copied()
13965                    .collect();
13966
13967                all_selections
13968                    .into_iter()
13969                    .partition(|s| columnar_selection_ids.contains(&s.id))
13970            } else {
13971                (Vec::new(), all_selections)
13972            }
13973        };
13974
13975        let mut state = self
13976            .add_selections_state
13977            .take()
13978            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13979
13980        for selection in new_selections_to_columnarize {
13981            let range = selection.display_range(&display_map).sorted();
13982            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13983            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13984            let positions = start_x.min(end_x)..start_x.max(end_x);
13985            let mut stack = Vec::new();
13986            for row in range.start.row().0..=range.end.row().0 {
13987                if let Some(selection) = self.selections.build_columnar_selection(
13988                    &display_map,
13989                    DisplayRow(row),
13990                    &positions,
13991                    selection.reversed,
13992                    &text_layout_details,
13993                ) {
13994                    stack.push(selection.id);
13995                    columnar_selections.push(selection);
13996                }
13997            }
13998            if !stack.is_empty() {
13999                if above {
14000                    stack.reverse();
14001                }
14002                state.groups.push(AddSelectionsGroup { above, stack });
14003            }
14004        }
14005
14006        let mut final_selections = Vec::new();
14007        let end_row = if above {
14008            DisplayRow(0)
14009        } else {
14010            display_map.max_point().row()
14011        };
14012
14013        let mut last_added_item_per_group = HashMap::default();
14014        for group in state.groups.iter_mut() {
14015            if let Some(last_id) = group.stack.last() {
14016                last_added_item_per_group.insert(*last_id, group);
14017            }
14018        }
14019
14020        for selection in columnar_selections {
14021            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14022                if above == group.above {
14023                    let range = selection.display_range(&display_map).sorted();
14024                    debug_assert_eq!(range.start.row(), range.end.row());
14025                    let mut row = range.start.row();
14026                    let positions =
14027                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14028                            px(start)..px(end)
14029                        } else {
14030                            let start_x =
14031                                display_map.x_for_display_point(range.start, &text_layout_details);
14032                            let end_x =
14033                                display_map.x_for_display_point(range.end, &text_layout_details);
14034                            start_x.min(end_x)..start_x.max(end_x)
14035                        };
14036
14037                    let mut maybe_new_selection = None;
14038                    while row != end_row {
14039                        if above {
14040                            row.0 -= 1;
14041                        } else {
14042                            row.0 += 1;
14043                        }
14044                        if let Some(new_selection) = self.selections.build_columnar_selection(
14045                            &display_map,
14046                            row,
14047                            &positions,
14048                            selection.reversed,
14049                            &text_layout_details,
14050                        ) {
14051                            maybe_new_selection = Some(new_selection);
14052                            break;
14053                        }
14054                    }
14055
14056                    if let Some(new_selection) = maybe_new_selection {
14057                        group.stack.push(new_selection.id);
14058                        if above {
14059                            final_selections.push(new_selection);
14060                            final_selections.push(selection);
14061                        } else {
14062                            final_selections.push(selection);
14063                            final_selections.push(new_selection);
14064                        }
14065                    } else {
14066                        final_selections.push(selection);
14067                    }
14068                } else {
14069                    group.stack.pop();
14070                }
14071            } else {
14072                final_selections.push(selection);
14073            }
14074        }
14075
14076        self.change_selections(Default::default(), window, cx, |s| {
14077            s.select(final_selections);
14078        });
14079
14080        let final_selection_ids: HashSet<_> = self
14081            .selections
14082            .all::<Point>(cx)
14083            .iter()
14084            .map(|s| s.id)
14085            .collect();
14086        state.groups.retain_mut(|group| {
14087            // selections might get merged above so we remove invalid items from stacks
14088            group.stack.retain(|id| final_selection_ids.contains(id));
14089
14090            // single selection in stack can be treated as initial state
14091            group.stack.len() > 1
14092        });
14093
14094        if !state.groups.is_empty() {
14095            self.add_selections_state = Some(state);
14096        }
14097    }
14098
14099    fn select_match_ranges(
14100        &mut self,
14101        range: Range<usize>,
14102        reversed: bool,
14103        replace_newest: bool,
14104        auto_scroll: Option<Autoscroll>,
14105        window: &mut Window,
14106        cx: &mut Context<Editor>,
14107    ) {
14108        self.unfold_ranges(
14109            std::slice::from_ref(&range),
14110            false,
14111            auto_scroll.is_some(),
14112            cx,
14113        );
14114        let effects = if let Some(scroll) = auto_scroll {
14115            SelectionEffects::scroll(scroll)
14116        } else {
14117            SelectionEffects::no_scroll()
14118        };
14119        self.change_selections(effects, window, cx, |s| {
14120            if replace_newest {
14121                s.delete(s.newest_anchor().id);
14122            }
14123            if reversed {
14124                s.insert_range(range.end..range.start);
14125            } else {
14126                s.insert_range(range);
14127            }
14128        });
14129    }
14130
14131    pub fn select_next_match_internal(
14132        &mut self,
14133        display_map: &DisplaySnapshot,
14134        replace_newest: bool,
14135        autoscroll: Option<Autoscroll>,
14136        window: &mut Window,
14137        cx: &mut Context<Self>,
14138    ) -> Result<()> {
14139        let buffer = &display_map.buffer_snapshot;
14140        let mut selections = self.selections.all::<usize>(cx);
14141        if let Some(mut select_next_state) = self.select_next_state.take() {
14142            let query = &select_next_state.query;
14143            if !select_next_state.done {
14144                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14145                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14146                let mut next_selected_range = None;
14147
14148                let bytes_after_last_selection =
14149                    buffer.bytes_in_range(last_selection.end..buffer.len());
14150                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14151                let query_matches = query
14152                    .stream_find_iter(bytes_after_last_selection)
14153                    .map(|result| (last_selection.end, result))
14154                    .chain(
14155                        query
14156                            .stream_find_iter(bytes_before_first_selection)
14157                            .map(|result| (0, result)),
14158                    );
14159
14160                for (start_offset, query_match) in query_matches {
14161                    let query_match = query_match.unwrap(); // can only fail due to I/O
14162                    let offset_range =
14163                        start_offset + query_match.start()..start_offset + query_match.end();
14164
14165                    if !select_next_state.wordwise
14166                        || (!buffer.is_inside_word(offset_range.start, false)
14167                            && !buffer.is_inside_word(offset_range.end, false))
14168                    {
14169                        // TODO: This is n^2, because we might check all the selections
14170                        if !selections
14171                            .iter()
14172                            .any(|selection| selection.range().overlaps(&offset_range))
14173                        {
14174                            next_selected_range = Some(offset_range);
14175                            break;
14176                        }
14177                    }
14178                }
14179
14180                if let Some(next_selected_range) = next_selected_range {
14181                    self.select_match_ranges(
14182                        next_selected_range,
14183                        last_selection.reversed,
14184                        replace_newest,
14185                        autoscroll,
14186                        window,
14187                        cx,
14188                    );
14189                } else {
14190                    select_next_state.done = true;
14191                }
14192            }
14193
14194            self.select_next_state = Some(select_next_state);
14195        } else {
14196            let mut only_carets = true;
14197            let mut same_text_selected = true;
14198            let mut selected_text = None;
14199
14200            let mut selections_iter = selections.iter().peekable();
14201            while let Some(selection) = selections_iter.next() {
14202                if selection.start != selection.end {
14203                    only_carets = false;
14204                }
14205
14206                if same_text_selected {
14207                    if selected_text.is_none() {
14208                        selected_text =
14209                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14210                    }
14211
14212                    if let Some(next_selection) = selections_iter.peek() {
14213                        if next_selection.range().len() == selection.range().len() {
14214                            let next_selected_text = buffer
14215                                .text_for_range(next_selection.range())
14216                                .collect::<String>();
14217                            if Some(next_selected_text) != selected_text {
14218                                same_text_selected = false;
14219                                selected_text = None;
14220                            }
14221                        } else {
14222                            same_text_selected = false;
14223                            selected_text = None;
14224                        }
14225                    }
14226                }
14227            }
14228
14229            if only_carets {
14230                for selection in &mut selections {
14231                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14232                    selection.start = word_range.start;
14233                    selection.end = word_range.end;
14234                    selection.goal = SelectionGoal::None;
14235                    selection.reversed = false;
14236                    self.select_match_ranges(
14237                        selection.start..selection.end,
14238                        selection.reversed,
14239                        replace_newest,
14240                        autoscroll,
14241                        window,
14242                        cx,
14243                    );
14244                }
14245
14246                if selections.len() == 1 {
14247                    let selection = selections
14248                        .last()
14249                        .expect("ensured that there's only one selection");
14250                    let query = buffer
14251                        .text_for_range(selection.start..selection.end)
14252                        .collect::<String>();
14253                    let is_empty = query.is_empty();
14254                    let select_state = SelectNextState {
14255                        query: AhoCorasick::new(&[query])?,
14256                        wordwise: true,
14257                        done: is_empty,
14258                    };
14259                    self.select_next_state = Some(select_state);
14260                } else {
14261                    self.select_next_state = None;
14262                }
14263            } else if let Some(selected_text) = selected_text {
14264                self.select_next_state = Some(SelectNextState {
14265                    query: AhoCorasick::new(&[selected_text])?,
14266                    wordwise: false,
14267                    done: false,
14268                });
14269                self.select_next_match_internal(
14270                    display_map,
14271                    replace_newest,
14272                    autoscroll,
14273                    window,
14274                    cx,
14275                )?;
14276            }
14277        }
14278        Ok(())
14279    }
14280
14281    pub fn select_all_matches(
14282        &mut self,
14283        _action: &SelectAllMatches,
14284        window: &mut Window,
14285        cx: &mut Context<Self>,
14286    ) -> Result<()> {
14287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14288
14289        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14290
14291        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14292        let Some(select_next_state) = self.select_next_state.as_mut() else {
14293            return Ok(());
14294        };
14295        if select_next_state.done {
14296            return Ok(());
14297        }
14298
14299        let mut new_selections = Vec::new();
14300
14301        let reversed = self.selections.oldest::<usize>(cx).reversed;
14302        let buffer = &display_map.buffer_snapshot;
14303        let query_matches = select_next_state
14304            .query
14305            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14306
14307        for query_match in query_matches.into_iter() {
14308            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14309            let offset_range = if reversed {
14310                query_match.end()..query_match.start()
14311            } else {
14312                query_match.start()..query_match.end()
14313            };
14314
14315            if !select_next_state.wordwise
14316                || (!buffer.is_inside_word(offset_range.start, false)
14317                    && !buffer.is_inside_word(offset_range.end, false))
14318            {
14319                new_selections.push(offset_range.start..offset_range.end);
14320            }
14321        }
14322
14323        select_next_state.done = true;
14324
14325        if new_selections.is_empty() {
14326            log::error!("bug: new_selections is empty in select_all_matches");
14327            return Ok(());
14328        }
14329
14330        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14331        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14332            selections.select_ranges(new_selections)
14333        });
14334
14335        Ok(())
14336    }
14337
14338    pub fn select_next(
14339        &mut self,
14340        action: &SelectNext,
14341        window: &mut Window,
14342        cx: &mut Context<Self>,
14343    ) -> Result<()> {
14344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14345        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14346        self.select_next_match_internal(
14347            &display_map,
14348            action.replace_newest,
14349            Some(Autoscroll::newest()),
14350            window,
14351            cx,
14352        )?;
14353        Ok(())
14354    }
14355
14356    pub fn select_previous(
14357        &mut self,
14358        action: &SelectPrevious,
14359        window: &mut Window,
14360        cx: &mut Context<Self>,
14361    ) -> Result<()> {
14362        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14363        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14364        let buffer = &display_map.buffer_snapshot;
14365        let mut selections = self.selections.all::<usize>(cx);
14366        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14367            let query = &select_prev_state.query;
14368            if !select_prev_state.done {
14369                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14370                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14371                let mut next_selected_range = None;
14372                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14373                let bytes_before_last_selection =
14374                    buffer.reversed_bytes_in_range(0..last_selection.start);
14375                let bytes_after_first_selection =
14376                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14377                let query_matches = query
14378                    .stream_find_iter(bytes_before_last_selection)
14379                    .map(|result| (last_selection.start, result))
14380                    .chain(
14381                        query
14382                            .stream_find_iter(bytes_after_first_selection)
14383                            .map(|result| (buffer.len(), result)),
14384                    );
14385                for (end_offset, query_match) in query_matches {
14386                    let query_match = query_match.unwrap(); // can only fail due to I/O
14387                    let offset_range =
14388                        end_offset - query_match.end()..end_offset - query_match.start();
14389
14390                    if !select_prev_state.wordwise
14391                        || (!buffer.is_inside_word(offset_range.start, false)
14392                            && !buffer.is_inside_word(offset_range.end, false))
14393                    {
14394                        next_selected_range = Some(offset_range);
14395                        break;
14396                    }
14397                }
14398
14399                if let Some(next_selected_range) = next_selected_range {
14400                    self.select_match_ranges(
14401                        next_selected_range,
14402                        last_selection.reversed,
14403                        action.replace_newest,
14404                        Some(Autoscroll::newest()),
14405                        window,
14406                        cx,
14407                    );
14408                } else {
14409                    select_prev_state.done = true;
14410                }
14411            }
14412
14413            self.select_prev_state = Some(select_prev_state);
14414        } else {
14415            let mut only_carets = true;
14416            let mut same_text_selected = true;
14417            let mut selected_text = None;
14418
14419            let mut selections_iter = selections.iter().peekable();
14420            while let Some(selection) = selections_iter.next() {
14421                if selection.start != selection.end {
14422                    only_carets = false;
14423                }
14424
14425                if same_text_selected {
14426                    if selected_text.is_none() {
14427                        selected_text =
14428                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14429                    }
14430
14431                    if let Some(next_selection) = selections_iter.peek() {
14432                        if next_selection.range().len() == selection.range().len() {
14433                            let next_selected_text = buffer
14434                                .text_for_range(next_selection.range())
14435                                .collect::<String>();
14436                            if Some(next_selected_text) != selected_text {
14437                                same_text_selected = false;
14438                                selected_text = None;
14439                            }
14440                        } else {
14441                            same_text_selected = false;
14442                            selected_text = None;
14443                        }
14444                    }
14445                }
14446            }
14447
14448            if only_carets {
14449                for selection in &mut selections {
14450                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14451                    selection.start = word_range.start;
14452                    selection.end = word_range.end;
14453                    selection.goal = SelectionGoal::None;
14454                    selection.reversed = false;
14455                    self.select_match_ranges(
14456                        selection.start..selection.end,
14457                        selection.reversed,
14458                        action.replace_newest,
14459                        Some(Autoscroll::newest()),
14460                        window,
14461                        cx,
14462                    );
14463                }
14464                if selections.len() == 1 {
14465                    let selection = selections
14466                        .last()
14467                        .expect("ensured that there's only one selection");
14468                    let query = buffer
14469                        .text_for_range(selection.start..selection.end)
14470                        .collect::<String>();
14471                    let is_empty = query.is_empty();
14472                    let select_state = SelectNextState {
14473                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14474                        wordwise: true,
14475                        done: is_empty,
14476                    };
14477                    self.select_prev_state = Some(select_state);
14478                } else {
14479                    self.select_prev_state = None;
14480                }
14481            } else if let Some(selected_text) = selected_text {
14482                self.select_prev_state = Some(SelectNextState {
14483                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14484                    wordwise: false,
14485                    done: false,
14486                });
14487                self.select_previous(action, window, cx)?;
14488            }
14489        }
14490        Ok(())
14491    }
14492
14493    pub fn find_next_match(
14494        &mut self,
14495        _: &FindNextMatch,
14496        window: &mut Window,
14497        cx: &mut Context<Self>,
14498    ) -> Result<()> {
14499        let selections = self.selections.disjoint_anchors();
14500        match selections.first() {
14501            Some(first) if selections.len() >= 2 => {
14502                self.change_selections(Default::default(), window, cx, |s| {
14503                    s.select_ranges([first.range()]);
14504                });
14505            }
14506            _ => self.select_next(
14507                &SelectNext {
14508                    replace_newest: true,
14509                },
14510                window,
14511                cx,
14512            )?,
14513        }
14514        Ok(())
14515    }
14516
14517    pub fn find_previous_match(
14518        &mut self,
14519        _: &FindPreviousMatch,
14520        window: &mut Window,
14521        cx: &mut Context<Self>,
14522    ) -> Result<()> {
14523        let selections = self.selections.disjoint_anchors();
14524        match selections.last() {
14525            Some(last) if selections.len() >= 2 => {
14526                self.change_selections(Default::default(), window, cx, |s| {
14527                    s.select_ranges([last.range()]);
14528                });
14529            }
14530            _ => self.select_previous(
14531                &SelectPrevious {
14532                    replace_newest: true,
14533                },
14534                window,
14535                cx,
14536            )?,
14537        }
14538        Ok(())
14539    }
14540
14541    pub fn toggle_comments(
14542        &mut self,
14543        action: &ToggleComments,
14544        window: &mut Window,
14545        cx: &mut Context<Self>,
14546    ) {
14547        if self.read_only(cx) {
14548            return;
14549        }
14550        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14551        let text_layout_details = &self.text_layout_details(window);
14552        self.transact(window, cx, |this, window, cx| {
14553            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14554            let mut edits = Vec::new();
14555            let mut selection_edit_ranges = Vec::new();
14556            let mut last_toggled_row = None;
14557            let snapshot = this.buffer.read(cx).read(cx);
14558            let empty_str: Arc<str> = Arc::default();
14559            let mut suffixes_inserted = Vec::new();
14560            let ignore_indent = action.ignore_indent;
14561
14562            fn comment_prefix_range(
14563                snapshot: &MultiBufferSnapshot,
14564                row: MultiBufferRow,
14565                comment_prefix: &str,
14566                comment_prefix_whitespace: &str,
14567                ignore_indent: bool,
14568            ) -> Range<Point> {
14569                let indent_size = if ignore_indent {
14570                    0
14571                } else {
14572                    snapshot.indent_size_for_line(row).len
14573                };
14574
14575                let start = Point::new(row.0, indent_size);
14576
14577                let mut line_bytes = snapshot
14578                    .bytes_in_range(start..snapshot.max_point())
14579                    .flatten()
14580                    .copied();
14581
14582                // If this line currently begins with the line comment prefix, then record
14583                // the range containing the prefix.
14584                if line_bytes
14585                    .by_ref()
14586                    .take(comment_prefix.len())
14587                    .eq(comment_prefix.bytes())
14588                {
14589                    // Include any whitespace that matches the comment prefix.
14590                    let matching_whitespace_len = line_bytes
14591                        .zip(comment_prefix_whitespace.bytes())
14592                        .take_while(|(a, b)| a == b)
14593                        .count() as u32;
14594                    let end = Point::new(
14595                        start.row,
14596                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14597                    );
14598                    start..end
14599                } else {
14600                    start..start
14601                }
14602            }
14603
14604            fn comment_suffix_range(
14605                snapshot: &MultiBufferSnapshot,
14606                row: MultiBufferRow,
14607                comment_suffix: &str,
14608                comment_suffix_has_leading_space: bool,
14609            ) -> Range<Point> {
14610                let end = Point::new(row.0, snapshot.line_len(row));
14611                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14612
14613                let mut line_end_bytes = snapshot
14614                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14615                    .flatten()
14616                    .copied();
14617
14618                let leading_space_len = if suffix_start_column > 0
14619                    && line_end_bytes.next() == Some(b' ')
14620                    && comment_suffix_has_leading_space
14621                {
14622                    1
14623                } else {
14624                    0
14625                };
14626
14627                // If this line currently begins with the line comment prefix, then record
14628                // the range containing the prefix.
14629                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14630                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14631                    start..end
14632                } else {
14633                    end..end
14634                }
14635            }
14636
14637            // TODO: Handle selections that cross excerpts
14638            for selection in &mut selections {
14639                let start_column = snapshot
14640                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14641                    .len;
14642                let language = if let Some(language) =
14643                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14644                {
14645                    language
14646                } else {
14647                    continue;
14648                };
14649
14650                selection_edit_ranges.clear();
14651
14652                // If multiple selections contain a given row, avoid processing that
14653                // row more than once.
14654                let mut start_row = MultiBufferRow(selection.start.row);
14655                if last_toggled_row == Some(start_row) {
14656                    start_row = start_row.next_row();
14657                }
14658                let end_row =
14659                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14660                        MultiBufferRow(selection.end.row - 1)
14661                    } else {
14662                        MultiBufferRow(selection.end.row)
14663                    };
14664                last_toggled_row = Some(end_row);
14665
14666                if start_row > end_row {
14667                    continue;
14668                }
14669
14670                // If the language has line comments, toggle those.
14671                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14672
14673                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14674                if ignore_indent {
14675                    full_comment_prefixes = full_comment_prefixes
14676                        .into_iter()
14677                        .map(|s| Arc::from(s.trim_end()))
14678                        .collect();
14679                }
14680
14681                if !full_comment_prefixes.is_empty() {
14682                    let first_prefix = full_comment_prefixes
14683                        .first()
14684                        .expect("prefixes is non-empty");
14685                    let prefix_trimmed_lengths = full_comment_prefixes
14686                        .iter()
14687                        .map(|p| p.trim_end_matches(' ').len())
14688                        .collect::<SmallVec<[usize; 4]>>();
14689
14690                    let mut all_selection_lines_are_comments = true;
14691
14692                    for row in start_row.0..=end_row.0 {
14693                        let row = MultiBufferRow(row);
14694                        if start_row < end_row && snapshot.is_line_blank(row) {
14695                            continue;
14696                        }
14697
14698                        let prefix_range = full_comment_prefixes
14699                            .iter()
14700                            .zip(prefix_trimmed_lengths.iter().copied())
14701                            .map(|(prefix, trimmed_prefix_len)| {
14702                                comment_prefix_range(
14703                                    snapshot.deref(),
14704                                    row,
14705                                    &prefix[..trimmed_prefix_len],
14706                                    &prefix[trimmed_prefix_len..],
14707                                    ignore_indent,
14708                                )
14709                            })
14710                            .max_by_key(|range| range.end.column - range.start.column)
14711                            .expect("prefixes is non-empty");
14712
14713                        if prefix_range.is_empty() {
14714                            all_selection_lines_are_comments = false;
14715                        }
14716
14717                        selection_edit_ranges.push(prefix_range);
14718                    }
14719
14720                    if all_selection_lines_are_comments {
14721                        edits.extend(
14722                            selection_edit_ranges
14723                                .iter()
14724                                .cloned()
14725                                .map(|range| (range, empty_str.clone())),
14726                        );
14727                    } else {
14728                        let min_column = selection_edit_ranges
14729                            .iter()
14730                            .map(|range| range.start.column)
14731                            .min()
14732                            .unwrap_or(0);
14733                        edits.extend(selection_edit_ranges.iter().map(|range| {
14734                            let position = Point::new(range.start.row, min_column);
14735                            (position..position, first_prefix.clone())
14736                        }));
14737                    }
14738                } else if let Some(BlockCommentConfig {
14739                    start: full_comment_prefix,
14740                    end: comment_suffix,
14741                    ..
14742                }) = language.block_comment()
14743                {
14744                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14745                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14746                    let prefix_range = comment_prefix_range(
14747                        snapshot.deref(),
14748                        start_row,
14749                        comment_prefix,
14750                        comment_prefix_whitespace,
14751                        ignore_indent,
14752                    );
14753                    let suffix_range = comment_suffix_range(
14754                        snapshot.deref(),
14755                        end_row,
14756                        comment_suffix.trim_start_matches(' '),
14757                        comment_suffix.starts_with(' '),
14758                    );
14759
14760                    if prefix_range.is_empty() || suffix_range.is_empty() {
14761                        edits.push((
14762                            prefix_range.start..prefix_range.start,
14763                            full_comment_prefix.clone(),
14764                        ));
14765                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14766                        suffixes_inserted.push((end_row, comment_suffix.len()));
14767                    } else {
14768                        edits.push((prefix_range, empty_str.clone()));
14769                        edits.push((suffix_range, empty_str.clone()));
14770                    }
14771                } else {
14772                    continue;
14773                }
14774            }
14775
14776            drop(snapshot);
14777            this.buffer.update(cx, |buffer, cx| {
14778                buffer.edit(edits, None, cx);
14779            });
14780
14781            // Adjust selections so that they end before any comment suffixes that
14782            // were inserted.
14783            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14784            let mut selections = this.selections.all::<Point>(cx);
14785            let snapshot = this.buffer.read(cx).read(cx);
14786            for selection in &mut selections {
14787                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14788                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14789                        Ordering::Less => {
14790                            suffixes_inserted.next();
14791                            continue;
14792                        }
14793                        Ordering::Greater => break,
14794                        Ordering::Equal => {
14795                            if selection.end.column == snapshot.line_len(row) {
14796                                if selection.is_empty() {
14797                                    selection.start.column -= suffix_len as u32;
14798                                }
14799                                selection.end.column -= suffix_len as u32;
14800                            }
14801                            break;
14802                        }
14803                    }
14804                }
14805            }
14806
14807            drop(snapshot);
14808            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14809
14810            let selections = this.selections.all::<Point>(cx);
14811            let selections_on_single_row = selections.windows(2).all(|selections| {
14812                selections[0].start.row == selections[1].start.row
14813                    && selections[0].end.row == selections[1].end.row
14814                    && selections[0].start.row == selections[0].end.row
14815            });
14816            let selections_selecting = selections
14817                .iter()
14818                .any(|selection| selection.start != selection.end);
14819            let advance_downwards = action.advance_downwards
14820                && selections_on_single_row
14821                && !selections_selecting
14822                && !matches!(this.mode, EditorMode::SingleLine);
14823
14824            if advance_downwards {
14825                let snapshot = this.buffer.read(cx).snapshot(cx);
14826
14827                this.change_selections(Default::default(), window, cx, |s| {
14828                    s.move_cursors_with(|display_snapshot, display_point, _| {
14829                        let mut point = display_point.to_point(display_snapshot);
14830                        point.row += 1;
14831                        point = snapshot.clip_point(point, Bias::Left);
14832                        let display_point = point.to_display_point(display_snapshot);
14833                        let goal = SelectionGoal::HorizontalPosition(
14834                            display_snapshot
14835                                .x_for_display_point(display_point, text_layout_details)
14836                                .into(),
14837                        );
14838                        (display_point, goal)
14839                    })
14840                });
14841            }
14842        });
14843    }
14844
14845    pub fn select_enclosing_symbol(
14846        &mut self,
14847        _: &SelectEnclosingSymbol,
14848        window: &mut Window,
14849        cx: &mut Context<Self>,
14850    ) {
14851        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14852
14853        let buffer = self.buffer.read(cx).snapshot(cx);
14854        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14855
14856        fn update_selection(
14857            selection: &Selection<usize>,
14858            buffer_snap: &MultiBufferSnapshot,
14859        ) -> Option<Selection<usize>> {
14860            let cursor = selection.head();
14861            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14862            for symbol in symbols.iter().rev() {
14863                let start = symbol.range.start.to_offset(buffer_snap);
14864                let end = symbol.range.end.to_offset(buffer_snap);
14865                let new_range = start..end;
14866                if start < selection.start || end > selection.end {
14867                    return Some(Selection {
14868                        id: selection.id,
14869                        start: new_range.start,
14870                        end: new_range.end,
14871                        goal: SelectionGoal::None,
14872                        reversed: selection.reversed,
14873                    });
14874                }
14875            }
14876            None
14877        }
14878
14879        let mut selected_larger_symbol = false;
14880        let new_selections = old_selections
14881            .iter()
14882            .map(|selection| match update_selection(selection, &buffer) {
14883                Some(new_selection) => {
14884                    if new_selection.range() != selection.range() {
14885                        selected_larger_symbol = true;
14886                    }
14887                    new_selection
14888                }
14889                None => selection.clone(),
14890            })
14891            .collect::<Vec<_>>();
14892
14893        if selected_larger_symbol {
14894            self.change_selections(Default::default(), window, cx, |s| {
14895                s.select(new_selections);
14896            });
14897        }
14898    }
14899
14900    pub fn select_larger_syntax_node(
14901        &mut self,
14902        _: &SelectLargerSyntaxNode,
14903        window: &mut Window,
14904        cx: &mut Context<Self>,
14905    ) {
14906        let Some(visible_row_count) = self.visible_row_count() else {
14907            return;
14908        };
14909        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14910        if old_selections.is_empty() {
14911            return;
14912        }
14913
14914        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14915
14916        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14917        let buffer = self.buffer.read(cx).snapshot(cx);
14918
14919        let mut selected_larger_node = false;
14920        let mut new_selections = old_selections
14921            .iter()
14922            .map(|selection| {
14923                let old_range = selection.start..selection.end;
14924
14925                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14926                    // manually select word at selection
14927                    if ["string_content", "inline"].contains(&node.kind()) {
14928                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14929                        // ignore if word is already selected
14930                        if !word_range.is_empty() && old_range != word_range {
14931                            let (last_word_range, _) =
14932                                buffer.surrounding_word(old_range.end, false);
14933                            // only select word if start and end point belongs to same word
14934                            if word_range == last_word_range {
14935                                selected_larger_node = true;
14936                                return Selection {
14937                                    id: selection.id,
14938                                    start: word_range.start,
14939                                    end: word_range.end,
14940                                    goal: SelectionGoal::None,
14941                                    reversed: selection.reversed,
14942                                };
14943                            }
14944                        }
14945                    }
14946                }
14947
14948                let mut new_range = old_range.clone();
14949                while let Some((_node, containing_range)) =
14950                    buffer.syntax_ancestor(new_range.clone())
14951                {
14952                    new_range = match containing_range {
14953                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14954                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14955                    };
14956                    if !display_map.intersects_fold(new_range.start)
14957                        && !display_map.intersects_fold(new_range.end)
14958                    {
14959                        break;
14960                    }
14961                }
14962
14963                selected_larger_node |= new_range != old_range;
14964                Selection {
14965                    id: selection.id,
14966                    start: new_range.start,
14967                    end: new_range.end,
14968                    goal: SelectionGoal::None,
14969                    reversed: selection.reversed,
14970                }
14971            })
14972            .collect::<Vec<_>>();
14973
14974        if !selected_larger_node {
14975            return; // don't put this call in the history
14976        }
14977
14978        // scroll based on transformation done to the last selection created by the user
14979        let (last_old, last_new) = old_selections
14980            .last()
14981            .zip(new_selections.last().cloned())
14982            .expect("old_selections isn't empty");
14983
14984        // revert selection
14985        let is_selection_reversed = {
14986            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14987            new_selections.last_mut().expect("checked above").reversed =
14988                should_newest_selection_be_reversed;
14989            should_newest_selection_be_reversed
14990        };
14991
14992        if selected_larger_node {
14993            self.select_syntax_node_history.disable_clearing = true;
14994            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14995                s.select(new_selections.clone());
14996            });
14997            self.select_syntax_node_history.disable_clearing = false;
14998        }
14999
15000        let start_row = last_new.start.to_display_point(&display_map).row().0;
15001        let end_row = last_new.end.to_display_point(&display_map).row().0;
15002        let selection_height = end_row - start_row + 1;
15003        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15004
15005        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15006        let scroll_behavior = if fits_on_the_screen {
15007            self.request_autoscroll(Autoscroll::fit(), cx);
15008            SelectSyntaxNodeScrollBehavior::FitSelection
15009        } else if is_selection_reversed {
15010            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15011            SelectSyntaxNodeScrollBehavior::CursorTop
15012        } else {
15013            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15014            SelectSyntaxNodeScrollBehavior::CursorBottom
15015        };
15016
15017        self.select_syntax_node_history.push((
15018            old_selections,
15019            scroll_behavior,
15020            is_selection_reversed,
15021        ));
15022    }
15023
15024    pub fn select_smaller_syntax_node(
15025        &mut self,
15026        _: &SelectSmallerSyntaxNode,
15027        window: &mut Window,
15028        cx: &mut Context<Self>,
15029    ) {
15030        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15031
15032        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15033            self.select_syntax_node_history.pop()
15034        {
15035            if let Some(selection) = selections.last_mut() {
15036                selection.reversed = is_selection_reversed;
15037            }
15038
15039            self.select_syntax_node_history.disable_clearing = true;
15040            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15041                s.select(selections.to_vec());
15042            });
15043            self.select_syntax_node_history.disable_clearing = false;
15044
15045            match scroll_behavior {
15046                SelectSyntaxNodeScrollBehavior::CursorTop => {
15047                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15048                }
15049                SelectSyntaxNodeScrollBehavior::FitSelection => {
15050                    self.request_autoscroll(Autoscroll::fit(), cx);
15051                }
15052                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15053                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15054                }
15055            }
15056        }
15057    }
15058
15059    pub fn unwrap_syntax_node(
15060        &mut self,
15061        _: &UnwrapSyntaxNode,
15062        window: &mut Window,
15063        cx: &mut Context<Self>,
15064    ) {
15065        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15066
15067        let buffer = self.buffer.read(cx).snapshot(cx);
15068        let selections = self
15069            .selections
15070            .all::<usize>(cx)
15071            .into_iter()
15072            // subtracting the offset requires sorting
15073            .sorted_by_key(|i| i.start);
15074
15075        let full_edits = selections
15076            .into_iter()
15077            .filter_map(|selection| {
15078                // Only requires two branches once if-let-chains stabilize (#53667)
15079                let child = if !selection.is_empty() {
15080                    selection.range()
15081                } else if let Some((_, ancestor_range)) =
15082                    buffer.syntax_ancestor(selection.start..selection.end)
15083                {
15084                    match ancestor_range {
15085                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15086                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15087                    }
15088                } else {
15089                    selection.range()
15090                };
15091
15092                let mut parent = child.clone();
15093                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15094                    parent = match ancestor_range {
15095                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15096                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15097                    };
15098                    if parent.start < child.start || parent.end > child.end {
15099                        break;
15100                    }
15101                }
15102
15103                if parent == child {
15104                    return None;
15105                }
15106                let text = buffer.text_for_range(child).collect::<String>();
15107                Some((selection.id, parent, text))
15108            })
15109            .collect::<Vec<_>>();
15110
15111        self.transact(window, cx, |this, window, cx| {
15112            this.buffer.update(cx, |buffer, cx| {
15113                buffer.edit(
15114                    full_edits
15115                        .iter()
15116                        .map(|(_, p, t)| (p.clone(), t.clone()))
15117                        .collect::<Vec<_>>(),
15118                    None,
15119                    cx,
15120                );
15121            });
15122            this.change_selections(Default::default(), window, cx, |s| {
15123                let mut offset = 0;
15124                let mut selections = vec![];
15125                for (id, parent, text) in full_edits {
15126                    let start = parent.start - offset;
15127                    offset += parent.len() - text.len();
15128                    selections.push(Selection {
15129                        id,
15130                        start,
15131                        end: start + text.len(),
15132                        reversed: false,
15133                        goal: Default::default(),
15134                    });
15135                }
15136                s.select(selections);
15137            });
15138        });
15139    }
15140
15141    pub fn select_next_syntax_node(
15142        &mut self,
15143        _: &SelectNextSyntaxNode,
15144        window: &mut Window,
15145        cx: &mut Context<Self>,
15146    ) {
15147        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15148        if old_selections.is_empty() {
15149            return;
15150        }
15151
15152        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15153
15154        let buffer = self.buffer.read(cx).snapshot(cx);
15155        let mut selected_sibling = false;
15156
15157        let new_selections = old_selections
15158            .iter()
15159            .map(|selection| {
15160                let old_range = selection.start..selection.end;
15161
15162                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15163                    let new_range = node.byte_range();
15164                    selected_sibling = true;
15165                    Selection {
15166                        id: selection.id,
15167                        start: new_range.start,
15168                        end: new_range.end,
15169                        goal: SelectionGoal::None,
15170                        reversed: selection.reversed,
15171                    }
15172                } else {
15173                    selection.clone()
15174                }
15175            })
15176            .collect::<Vec<_>>();
15177
15178        if selected_sibling {
15179            self.change_selections(
15180                SelectionEffects::scroll(Autoscroll::fit()),
15181                window,
15182                cx,
15183                |s| {
15184                    s.select(new_selections);
15185                },
15186            );
15187        }
15188    }
15189
15190    pub fn select_prev_syntax_node(
15191        &mut self,
15192        _: &SelectPreviousSyntaxNode,
15193        window: &mut Window,
15194        cx: &mut Context<Self>,
15195    ) {
15196        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15197        if old_selections.is_empty() {
15198            return;
15199        }
15200
15201        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15202
15203        let buffer = self.buffer.read(cx).snapshot(cx);
15204        let mut selected_sibling = false;
15205
15206        let new_selections = old_selections
15207            .iter()
15208            .map(|selection| {
15209                let old_range = selection.start..selection.end;
15210
15211                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15212                    let new_range = node.byte_range();
15213                    selected_sibling = true;
15214                    Selection {
15215                        id: selection.id,
15216                        start: new_range.start,
15217                        end: new_range.end,
15218                        goal: SelectionGoal::None,
15219                        reversed: selection.reversed,
15220                    }
15221                } else {
15222                    selection.clone()
15223                }
15224            })
15225            .collect::<Vec<_>>();
15226
15227        if selected_sibling {
15228            self.change_selections(
15229                SelectionEffects::scroll(Autoscroll::fit()),
15230                window,
15231                cx,
15232                |s| {
15233                    s.select(new_selections);
15234                },
15235            );
15236        }
15237    }
15238
15239    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15240        if !EditorSettings::get_global(cx).gutter.runnables {
15241            self.clear_tasks();
15242            return Task::ready(());
15243        }
15244        let project = self.project().map(Entity::downgrade);
15245        let task_sources = self.lsp_task_sources(cx);
15246        let multi_buffer = self.buffer.downgrade();
15247        cx.spawn_in(window, async move |editor, cx| {
15248            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15249            let Some(project) = project.and_then(|p| p.upgrade()) else {
15250                return;
15251            };
15252            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15253                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15254            }) else {
15255                return;
15256            };
15257
15258            let hide_runnables = project
15259                .update(cx, |project, _| project.is_via_collab())
15260                .unwrap_or(true);
15261            if hide_runnables {
15262                return;
15263            }
15264            let new_rows =
15265                cx.background_spawn({
15266                    let snapshot = display_snapshot.clone();
15267                    async move {
15268                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15269                    }
15270                })
15271                    .await;
15272            let Ok(lsp_tasks) =
15273                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15274            else {
15275                return;
15276            };
15277            let lsp_tasks = lsp_tasks.await;
15278
15279            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15280                lsp_tasks
15281                    .into_iter()
15282                    .flat_map(|(kind, tasks)| {
15283                        tasks.into_iter().filter_map(move |(location, task)| {
15284                            Some((kind.clone(), location?, task))
15285                        })
15286                    })
15287                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15288                        let buffer = location.target.buffer;
15289                        let buffer_snapshot = buffer.read(cx).snapshot();
15290                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15291                            |(excerpt_id, snapshot, _)| {
15292                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15293                                    display_snapshot
15294                                        .buffer_snapshot
15295                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15296                                } else {
15297                                    None
15298                                }
15299                            },
15300                        );
15301                        if let Some(offset) = offset {
15302                            let task_buffer_range =
15303                                location.target.range.to_point(&buffer_snapshot);
15304                            let context_buffer_range =
15305                                task_buffer_range.to_offset(&buffer_snapshot);
15306                            let context_range = BufferOffset(context_buffer_range.start)
15307                                ..BufferOffset(context_buffer_range.end);
15308
15309                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15310                                .or_insert_with(|| RunnableTasks {
15311                                    templates: Vec::new(),
15312                                    offset,
15313                                    column: task_buffer_range.start.column,
15314                                    extra_variables: HashMap::default(),
15315                                    context_range,
15316                                })
15317                                .templates
15318                                .push((kind, task.original_task().clone()));
15319                        }
15320
15321                        acc
15322                    })
15323            }) else {
15324                return;
15325            };
15326
15327            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15328                buffer.language_settings(cx).tasks.prefer_lsp
15329            }) else {
15330                return;
15331            };
15332
15333            let rows = Self::runnable_rows(
15334                project,
15335                display_snapshot,
15336                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15337                new_rows,
15338                cx.clone(),
15339            )
15340            .await;
15341            editor
15342                .update(cx, |editor, _| {
15343                    editor.clear_tasks();
15344                    for (key, mut value) in rows {
15345                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15346                            value.templates.extend(lsp_tasks.templates);
15347                        }
15348
15349                        editor.insert_tasks(key, value);
15350                    }
15351                    for (key, value) in lsp_tasks_by_rows {
15352                        editor.insert_tasks(key, value);
15353                    }
15354                })
15355                .ok();
15356        })
15357    }
15358    fn fetch_runnable_ranges(
15359        snapshot: &DisplaySnapshot,
15360        range: Range<Anchor>,
15361    ) -> Vec<language::RunnableRange> {
15362        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15363    }
15364
15365    fn runnable_rows(
15366        project: Entity<Project>,
15367        snapshot: DisplaySnapshot,
15368        prefer_lsp: bool,
15369        runnable_ranges: Vec<RunnableRange>,
15370        cx: AsyncWindowContext,
15371    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15372        cx.spawn(async move |cx| {
15373            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15374            for mut runnable in runnable_ranges {
15375                let Some(tasks) = cx
15376                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15377                    .ok()
15378                else {
15379                    continue;
15380                };
15381                let mut tasks = tasks.await;
15382
15383                if prefer_lsp {
15384                    tasks.retain(|(task_kind, _)| {
15385                        !matches!(task_kind, TaskSourceKind::Language { .. })
15386                    });
15387                }
15388                if tasks.is_empty() {
15389                    continue;
15390                }
15391
15392                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15393                let Some(row) = snapshot
15394                    .buffer_snapshot
15395                    .buffer_line_for_row(MultiBufferRow(point.row))
15396                    .map(|(_, range)| range.start.row)
15397                else {
15398                    continue;
15399                };
15400
15401                let context_range =
15402                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15403                runnable_rows.push((
15404                    (runnable.buffer_id, row),
15405                    RunnableTasks {
15406                        templates: tasks,
15407                        offset: snapshot
15408                            .buffer_snapshot
15409                            .anchor_before(runnable.run_range.start),
15410                        context_range,
15411                        column: point.column,
15412                        extra_variables: runnable.extra_captures,
15413                    },
15414                ));
15415            }
15416            runnable_rows
15417        })
15418    }
15419
15420    fn templates_with_tags(
15421        project: &Entity<Project>,
15422        runnable: &mut Runnable,
15423        cx: &mut App,
15424    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15425        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15426            let (worktree_id, file) = project
15427                .buffer_for_id(runnable.buffer, cx)
15428                .and_then(|buffer| buffer.read(cx).file())
15429                .map(|file| (file.worktree_id(cx), file.clone()))
15430                .unzip();
15431
15432            (
15433                project.task_store().read(cx).task_inventory().cloned(),
15434                worktree_id,
15435                file,
15436            )
15437        });
15438
15439        let tags = mem::take(&mut runnable.tags);
15440        let language = runnable.language.clone();
15441        cx.spawn(async move |cx| {
15442            let mut templates_with_tags = Vec::new();
15443            if let Some(inventory) = inventory {
15444                for RunnableTag(tag) in tags {
15445                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15446                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15447                    }) else {
15448                        return templates_with_tags;
15449                    };
15450                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15451                        move |(_, template)| {
15452                            template.tags.iter().any(|source_tag| source_tag == &tag)
15453                        },
15454                    ));
15455                }
15456            }
15457            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15458
15459            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15460                // Strongest source wins; if we have worktree tag binding, prefer that to
15461                // global and language bindings;
15462                // if we have a global binding, prefer that to language binding.
15463                let first_mismatch = templates_with_tags
15464                    .iter()
15465                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15466                if let Some(index) = first_mismatch {
15467                    templates_with_tags.truncate(index);
15468                }
15469            }
15470
15471            templates_with_tags
15472        })
15473    }
15474
15475    pub fn move_to_enclosing_bracket(
15476        &mut self,
15477        _: &MoveToEnclosingBracket,
15478        window: &mut Window,
15479        cx: &mut Context<Self>,
15480    ) {
15481        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15482        self.change_selections(Default::default(), window, cx, |s| {
15483            s.move_offsets_with(|snapshot, selection| {
15484                let Some(enclosing_bracket_ranges) =
15485                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15486                else {
15487                    return;
15488                };
15489
15490                let mut best_length = usize::MAX;
15491                let mut best_inside = false;
15492                let mut best_in_bracket_range = false;
15493                let mut best_destination = None;
15494                for (open, close) in enclosing_bracket_ranges {
15495                    let close = close.to_inclusive();
15496                    let length = close.end() - open.start;
15497                    let inside = selection.start >= open.end && selection.end <= *close.start();
15498                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15499                        || close.contains(&selection.head());
15500
15501                    // If best is next to a bracket and current isn't, skip
15502                    if !in_bracket_range && best_in_bracket_range {
15503                        continue;
15504                    }
15505
15506                    // Prefer smaller lengths unless best is inside and current isn't
15507                    if length > best_length && (best_inside || !inside) {
15508                        continue;
15509                    }
15510
15511                    best_length = length;
15512                    best_inside = inside;
15513                    best_in_bracket_range = in_bracket_range;
15514                    best_destination = Some(
15515                        if close.contains(&selection.start) && close.contains(&selection.end) {
15516                            if inside { open.end } else { open.start }
15517                        } else if inside {
15518                            *close.start()
15519                        } else {
15520                            *close.end()
15521                        },
15522                    );
15523                }
15524
15525                if let Some(destination) = best_destination {
15526                    selection.collapse_to(destination, SelectionGoal::None);
15527                }
15528            })
15529        });
15530    }
15531
15532    pub fn undo_selection(
15533        &mut self,
15534        _: &UndoSelection,
15535        window: &mut Window,
15536        cx: &mut Context<Self>,
15537    ) {
15538        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15539        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15540            self.selection_history.mode = SelectionHistoryMode::Undoing;
15541            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15542                this.end_selection(window, cx);
15543                this.change_selections(
15544                    SelectionEffects::scroll(Autoscroll::newest()),
15545                    window,
15546                    cx,
15547                    |s| s.select_anchors(entry.selections.to_vec()),
15548                );
15549            });
15550            self.selection_history.mode = SelectionHistoryMode::Normal;
15551
15552            self.select_next_state = entry.select_next_state;
15553            self.select_prev_state = entry.select_prev_state;
15554            self.add_selections_state = entry.add_selections_state;
15555        }
15556    }
15557
15558    pub fn redo_selection(
15559        &mut self,
15560        _: &RedoSelection,
15561        window: &mut Window,
15562        cx: &mut Context<Self>,
15563    ) {
15564        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15565        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15566            self.selection_history.mode = SelectionHistoryMode::Redoing;
15567            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15568                this.end_selection(window, cx);
15569                this.change_selections(
15570                    SelectionEffects::scroll(Autoscroll::newest()),
15571                    window,
15572                    cx,
15573                    |s| s.select_anchors(entry.selections.to_vec()),
15574                );
15575            });
15576            self.selection_history.mode = SelectionHistoryMode::Normal;
15577
15578            self.select_next_state = entry.select_next_state;
15579            self.select_prev_state = entry.select_prev_state;
15580            self.add_selections_state = entry.add_selections_state;
15581        }
15582    }
15583
15584    pub fn expand_excerpts(
15585        &mut self,
15586        action: &ExpandExcerpts,
15587        _: &mut Window,
15588        cx: &mut Context<Self>,
15589    ) {
15590        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15591    }
15592
15593    pub fn expand_excerpts_down(
15594        &mut self,
15595        action: &ExpandExcerptsDown,
15596        _: &mut Window,
15597        cx: &mut Context<Self>,
15598    ) {
15599        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15600    }
15601
15602    pub fn expand_excerpts_up(
15603        &mut self,
15604        action: &ExpandExcerptsUp,
15605        _: &mut Window,
15606        cx: &mut Context<Self>,
15607    ) {
15608        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15609    }
15610
15611    pub fn expand_excerpts_for_direction(
15612        &mut self,
15613        lines: u32,
15614        direction: ExpandExcerptDirection,
15615
15616        cx: &mut Context<Self>,
15617    ) {
15618        let selections = self.selections.disjoint_anchors();
15619
15620        let lines = if lines == 0 {
15621            EditorSettings::get_global(cx).expand_excerpt_lines
15622        } else {
15623            lines
15624        };
15625
15626        self.buffer.update(cx, |buffer, cx| {
15627            let snapshot = buffer.snapshot(cx);
15628            let mut excerpt_ids = selections
15629                .iter()
15630                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15631                .collect::<Vec<_>>();
15632            excerpt_ids.sort();
15633            excerpt_ids.dedup();
15634            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15635        })
15636    }
15637
15638    pub fn expand_excerpt(
15639        &mut self,
15640        excerpt: ExcerptId,
15641        direction: ExpandExcerptDirection,
15642        window: &mut Window,
15643        cx: &mut Context<Self>,
15644    ) {
15645        let current_scroll_position = self.scroll_position(cx);
15646        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15647        let mut should_scroll_up = false;
15648
15649        if direction == ExpandExcerptDirection::Down {
15650            let multi_buffer = self.buffer.read(cx);
15651            let snapshot = multi_buffer.snapshot(cx);
15652            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15653                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15654                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15655            {
15656                let buffer_snapshot = buffer.read(cx).snapshot();
15657                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15658                let last_row = buffer_snapshot.max_point().row;
15659                let lines_below = last_row.saturating_sub(excerpt_end_row);
15660                should_scroll_up = lines_below >= lines_to_expand;
15661            }
15662        }
15663
15664        self.buffer.update(cx, |buffer, cx| {
15665            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15666        });
15667
15668        if should_scroll_up {
15669            let new_scroll_position =
15670                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15671            self.set_scroll_position(new_scroll_position, window, cx);
15672        }
15673    }
15674
15675    pub fn go_to_singleton_buffer_point(
15676        &mut self,
15677        point: Point,
15678        window: &mut Window,
15679        cx: &mut Context<Self>,
15680    ) {
15681        self.go_to_singleton_buffer_range(point..point, window, cx);
15682    }
15683
15684    pub fn go_to_singleton_buffer_range(
15685        &mut self,
15686        range: Range<Point>,
15687        window: &mut Window,
15688        cx: &mut Context<Self>,
15689    ) {
15690        let multibuffer = self.buffer().read(cx);
15691        let Some(buffer) = multibuffer.as_singleton() else {
15692            return;
15693        };
15694        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15695            return;
15696        };
15697        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15698            return;
15699        };
15700        self.change_selections(
15701            SelectionEffects::default().nav_history(true),
15702            window,
15703            cx,
15704            |s| s.select_anchor_ranges([start..end]),
15705        );
15706    }
15707
15708    pub fn go_to_diagnostic(
15709        &mut self,
15710        action: &GoToDiagnostic,
15711        window: &mut Window,
15712        cx: &mut Context<Self>,
15713    ) {
15714        if !self.diagnostics_enabled() {
15715            return;
15716        }
15717        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15718        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15719    }
15720
15721    pub fn go_to_prev_diagnostic(
15722        &mut self,
15723        action: &GoToPreviousDiagnostic,
15724        window: &mut Window,
15725        cx: &mut Context<Self>,
15726    ) {
15727        if !self.diagnostics_enabled() {
15728            return;
15729        }
15730        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15731        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15732    }
15733
15734    pub fn go_to_diagnostic_impl(
15735        &mut self,
15736        direction: Direction,
15737        severity: GoToDiagnosticSeverityFilter,
15738        window: &mut Window,
15739        cx: &mut Context<Self>,
15740    ) {
15741        let buffer = self.buffer.read(cx).snapshot(cx);
15742        let selection = self.selections.newest::<usize>(cx);
15743
15744        let mut active_group_id = None;
15745        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15746            && active_group.active_range.start.to_offset(&buffer) == selection.start
15747        {
15748            active_group_id = Some(active_group.group_id);
15749        }
15750
15751        fn filtered(
15752            snapshot: EditorSnapshot,
15753            severity: GoToDiagnosticSeverityFilter,
15754            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15755        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15756            diagnostics
15757                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15758                .filter(|entry| entry.range.start != entry.range.end)
15759                .filter(|entry| !entry.diagnostic.is_unnecessary)
15760                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15761        }
15762
15763        let snapshot = self.snapshot(window, cx);
15764        let before = filtered(
15765            snapshot.clone(),
15766            severity,
15767            buffer
15768                .diagnostics_in_range(0..selection.start)
15769                .filter(|entry| entry.range.start <= selection.start),
15770        );
15771        let after = filtered(
15772            snapshot,
15773            severity,
15774            buffer
15775                .diagnostics_in_range(selection.start..buffer.len())
15776                .filter(|entry| entry.range.start >= selection.start),
15777        );
15778
15779        let mut found: Option<DiagnosticEntry<usize>> = None;
15780        if direction == Direction::Prev {
15781            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15782            {
15783                for diagnostic in prev_diagnostics.into_iter().rev() {
15784                    if diagnostic.range.start != selection.start
15785                        || active_group_id
15786                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15787                    {
15788                        found = Some(diagnostic);
15789                        break 'outer;
15790                    }
15791                }
15792            }
15793        } else {
15794            for diagnostic in after.chain(before) {
15795                if diagnostic.range.start != selection.start
15796                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15797                {
15798                    found = Some(diagnostic);
15799                    break;
15800                }
15801            }
15802        }
15803        let Some(next_diagnostic) = found else {
15804            return;
15805        };
15806
15807        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15808        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15809            return;
15810        };
15811        self.change_selections(Default::default(), window, cx, |s| {
15812            s.select_ranges(vec![
15813                next_diagnostic.range.start..next_diagnostic.range.start,
15814            ])
15815        });
15816        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15817        self.refresh_edit_prediction(false, true, window, cx);
15818    }
15819
15820    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15821        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15822        let snapshot = self.snapshot(window, cx);
15823        let selection = self.selections.newest::<Point>(cx);
15824        self.go_to_hunk_before_or_after_position(
15825            &snapshot,
15826            selection.head(),
15827            Direction::Next,
15828            window,
15829            cx,
15830        );
15831    }
15832
15833    pub fn go_to_hunk_before_or_after_position(
15834        &mut self,
15835        snapshot: &EditorSnapshot,
15836        position: Point,
15837        direction: Direction,
15838        window: &mut Window,
15839        cx: &mut Context<Editor>,
15840    ) {
15841        let row = if direction == Direction::Next {
15842            self.hunk_after_position(snapshot, position)
15843                .map(|hunk| hunk.row_range.start)
15844        } else {
15845            self.hunk_before_position(snapshot, position)
15846        };
15847
15848        if let Some(row) = row {
15849            let destination = Point::new(row.0, 0);
15850            let autoscroll = Autoscroll::center();
15851
15852            self.unfold_ranges(&[destination..destination], false, false, cx);
15853            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15854                s.select_ranges([destination..destination]);
15855            });
15856        }
15857    }
15858
15859    fn hunk_after_position(
15860        &mut self,
15861        snapshot: &EditorSnapshot,
15862        position: Point,
15863    ) -> Option<MultiBufferDiffHunk> {
15864        snapshot
15865            .buffer_snapshot
15866            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15867            .find(|hunk| hunk.row_range.start.0 > position.row)
15868            .or_else(|| {
15869                snapshot
15870                    .buffer_snapshot
15871                    .diff_hunks_in_range(Point::zero()..position)
15872                    .find(|hunk| hunk.row_range.end.0 < position.row)
15873            })
15874    }
15875
15876    fn go_to_prev_hunk(
15877        &mut self,
15878        _: &GoToPreviousHunk,
15879        window: &mut Window,
15880        cx: &mut Context<Self>,
15881    ) {
15882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15883        let snapshot = self.snapshot(window, cx);
15884        let selection = self.selections.newest::<Point>(cx);
15885        self.go_to_hunk_before_or_after_position(
15886            &snapshot,
15887            selection.head(),
15888            Direction::Prev,
15889            window,
15890            cx,
15891        );
15892    }
15893
15894    fn hunk_before_position(
15895        &mut self,
15896        snapshot: &EditorSnapshot,
15897        position: Point,
15898    ) -> Option<MultiBufferRow> {
15899        snapshot
15900            .buffer_snapshot
15901            .diff_hunk_before(position)
15902            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15903    }
15904
15905    fn go_to_next_change(
15906        &mut self,
15907        _: &GoToNextChange,
15908        window: &mut Window,
15909        cx: &mut Context<Self>,
15910    ) {
15911        if let Some(selections) = self
15912            .change_list
15913            .next_change(1, Direction::Next)
15914            .map(|s| s.to_vec())
15915        {
15916            self.change_selections(Default::default(), window, cx, |s| {
15917                let map = s.display_map();
15918                s.select_display_ranges(selections.iter().map(|a| {
15919                    let point = a.to_display_point(&map);
15920                    point..point
15921                }))
15922            })
15923        }
15924    }
15925
15926    fn go_to_previous_change(
15927        &mut self,
15928        _: &GoToPreviousChange,
15929        window: &mut Window,
15930        cx: &mut Context<Self>,
15931    ) {
15932        if let Some(selections) = self
15933            .change_list
15934            .next_change(1, Direction::Prev)
15935            .map(|s| s.to_vec())
15936        {
15937            self.change_selections(Default::default(), window, cx, |s| {
15938                let map = s.display_map();
15939                s.select_display_ranges(selections.iter().map(|a| {
15940                    let point = a.to_display_point(&map);
15941                    point..point
15942                }))
15943            })
15944        }
15945    }
15946
15947    fn go_to_line<T: 'static>(
15948        &mut self,
15949        position: Anchor,
15950        highlight_color: Option<Hsla>,
15951        window: &mut Window,
15952        cx: &mut Context<Self>,
15953    ) {
15954        let snapshot = self.snapshot(window, cx).display_snapshot;
15955        let position = position.to_point(&snapshot.buffer_snapshot);
15956        let start = snapshot
15957            .buffer_snapshot
15958            .clip_point(Point::new(position.row, 0), Bias::Left);
15959        let end = start + Point::new(1, 0);
15960        let start = snapshot.buffer_snapshot.anchor_before(start);
15961        let end = snapshot.buffer_snapshot.anchor_before(end);
15962
15963        self.highlight_rows::<T>(
15964            start..end,
15965            highlight_color
15966                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15967            Default::default(),
15968            cx,
15969        );
15970
15971        if self.buffer.read(cx).is_singleton() {
15972            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15973        }
15974    }
15975
15976    pub fn go_to_definition(
15977        &mut self,
15978        _: &GoToDefinition,
15979        window: &mut Window,
15980        cx: &mut Context<Self>,
15981    ) -> Task<Result<Navigated>> {
15982        let definition =
15983            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15984        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15985        cx.spawn_in(window, async move |editor, cx| {
15986            if definition.await? == Navigated::Yes {
15987                return Ok(Navigated::Yes);
15988            }
15989            match fallback_strategy {
15990                GoToDefinitionFallback::None => Ok(Navigated::No),
15991                GoToDefinitionFallback::FindAllReferences => {
15992                    match editor.update_in(cx, |editor, window, cx| {
15993                        editor.find_all_references(&FindAllReferences, window, cx)
15994                    })? {
15995                        Some(references) => references.await,
15996                        None => Ok(Navigated::No),
15997                    }
15998                }
15999            }
16000        })
16001    }
16002
16003    pub fn go_to_declaration(
16004        &mut self,
16005        _: &GoToDeclaration,
16006        window: &mut Window,
16007        cx: &mut Context<Self>,
16008    ) -> Task<Result<Navigated>> {
16009        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16010    }
16011
16012    pub fn go_to_declaration_split(
16013        &mut self,
16014        _: &GoToDeclaration,
16015        window: &mut Window,
16016        cx: &mut Context<Self>,
16017    ) -> Task<Result<Navigated>> {
16018        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16019    }
16020
16021    pub fn go_to_implementation(
16022        &mut self,
16023        _: &GoToImplementation,
16024        window: &mut Window,
16025        cx: &mut Context<Self>,
16026    ) -> Task<Result<Navigated>> {
16027        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16028    }
16029
16030    pub fn go_to_implementation_split(
16031        &mut self,
16032        _: &GoToImplementationSplit,
16033        window: &mut Window,
16034        cx: &mut Context<Self>,
16035    ) -> Task<Result<Navigated>> {
16036        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16037    }
16038
16039    pub fn go_to_type_definition(
16040        &mut self,
16041        _: &GoToTypeDefinition,
16042        window: &mut Window,
16043        cx: &mut Context<Self>,
16044    ) -> Task<Result<Navigated>> {
16045        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16046    }
16047
16048    pub fn go_to_definition_split(
16049        &mut self,
16050        _: &GoToDefinitionSplit,
16051        window: &mut Window,
16052        cx: &mut Context<Self>,
16053    ) -> Task<Result<Navigated>> {
16054        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16055    }
16056
16057    pub fn go_to_type_definition_split(
16058        &mut self,
16059        _: &GoToTypeDefinitionSplit,
16060        window: &mut Window,
16061        cx: &mut Context<Self>,
16062    ) -> Task<Result<Navigated>> {
16063        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16064    }
16065
16066    fn go_to_definition_of_kind(
16067        &mut self,
16068        kind: GotoDefinitionKind,
16069        split: bool,
16070        window: &mut Window,
16071        cx: &mut Context<Self>,
16072    ) -> Task<Result<Navigated>> {
16073        let Some(provider) = self.semantics_provider.clone() else {
16074            return Task::ready(Ok(Navigated::No));
16075        };
16076        let head = self.selections.newest::<usize>(cx).head();
16077        let buffer = self.buffer.read(cx);
16078        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16079            return Task::ready(Ok(Navigated::No));
16080        };
16081        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16082            return Task::ready(Ok(Navigated::No));
16083        };
16084
16085        cx.spawn_in(window, async move |editor, cx| {
16086            let Some(definitions) = definitions.await? else {
16087                return Ok(Navigated::No);
16088            };
16089            let navigated = editor
16090                .update_in(cx, |editor, window, cx| {
16091                    editor.navigate_to_hover_links(
16092                        Some(kind),
16093                        definitions
16094                            .into_iter()
16095                            .filter(|location| {
16096                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16097                            })
16098                            .map(HoverLink::Text)
16099                            .collect::<Vec<_>>(),
16100                        split,
16101                        window,
16102                        cx,
16103                    )
16104                })?
16105                .await?;
16106            anyhow::Ok(navigated)
16107        })
16108    }
16109
16110    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16111        let selection = self.selections.newest_anchor();
16112        let head = selection.head();
16113        let tail = selection.tail();
16114
16115        let Some((buffer, start_position)) =
16116            self.buffer.read(cx).text_anchor_for_position(head, cx)
16117        else {
16118            return;
16119        };
16120
16121        let end_position = if head != tail {
16122            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16123                return;
16124            };
16125            Some(pos)
16126        } else {
16127            None
16128        };
16129
16130        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16131            let url = if let Some(end_pos) = end_position {
16132                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16133            } else {
16134                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16135            };
16136
16137            if let Some(url) = url {
16138                editor.update(cx, |_, cx| {
16139                    cx.open_url(&url);
16140                })
16141            } else {
16142                Ok(())
16143            }
16144        });
16145
16146        url_finder.detach();
16147    }
16148
16149    pub fn open_selected_filename(
16150        &mut self,
16151        _: &OpenSelectedFilename,
16152        window: &mut Window,
16153        cx: &mut Context<Self>,
16154    ) {
16155        let Some(workspace) = self.workspace() else {
16156            return;
16157        };
16158
16159        let position = self.selections.newest_anchor().head();
16160
16161        let Some((buffer, buffer_position)) =
16162            self.buffer.read(cx).text_anchor_for_position(position, cx)
16163        else {
16164            return;
16165        };
16166
16167        let project = self.project.clone();
16168
16169        cx.spawn_in(window, async move |_, cx| {
16170            let result = find_file(&buffer, project, buffer_position, cx).await;
16171
16172            if let Some((_, path)) = result {
16173                workspace
16174                    .update_in(cx, |workspace, window, cx| {
16175                        workspace.open_resolved_path(path, window, cx)
16176                    })?
16177                    .await?;
16178            }
16179            anyhow::Ok(())
16180        })
16181        .detach();
16182    }
16183
16184    pub(crate) fn navigate_to_hover_links(
16185        &mut self,
16186        kind: Option<GotoDefinitionKind>,
16187        definitions: Vec<HoverLink>,
16188        split: bool,
16189        window: &mut Window,
16190        cx: &mut Context<Editor>,
16191    ) -> Task<Result<Navigated>> {
16192        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16193        let mut first_url_or_file = None;
16194        let definitions: Vec<_> = definitions
16195            .into_iter()
16196            .filter_map(|def| match def {
16197                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16198                HoverLink::InlayHint(lsp_location, server_id) => {
16199                    let computation =
16200                        self.compute_target_location(lsp_location, server_id, window, cx);
16201                    Some(cx.background_spawn(computation))
16202                }
16203                HoverLink::Url(url) => {
16204                    first_url_or_file = Some(Either::Left(url));
16205                    None
16206                }
16207                HoverLink::File(path) => {
16208                    first_url_or_file = Some(Either::Right(path));
16209                    None
16210                }
16211            })
16212            .collect();
16213
16214        let workspace = self.workspace();
16215
16216        cx.spawn_in(window, async move |editor, acx| {
16217            let mut locations: Vec<Location> = future::join_all(definitions)
16218                .await
16219                .into_iter()
16220                .filter_map(|location| location.transpose())
16221                .collect::<Result<_>>()
16222                .context("location tasks")?;
16223
16224            if locations.len() > 1 {
16225                let Some(workspace) = workspace else {
16226                    return Ok(Navigated::No);
16227                };
16228
16229                let tab_kind = match kind {
16230                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16231                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16232                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16233                    Some(GotoDefinitionKind::Type) => "Types",
16234                };
16235                let title = editor
16236                    .update_in(acx, |_, _, cx| {
16237                        let target = locations
16238                            .iter()
16239                            .map(|location| {
16240                                location
16241                                    .buffer
16242                                    .read(cx)
16243                                    .text_for_range(location.range.clone())
16244                                    .collect::<String>()
16245                            })
16246                            .filter(|text| !text.contains('\n'))
16247                            .unique()
16248                            .take(3)
16249                            .join(", ");
16250                        if target.is_empty() {
16251                            tab_kind.to_owned()
16252                        } else {
16253                            format!("{tab_kind} for {target}")
16254                        }
16255                    })
16256                    .context("buffer title")?;
16257
16258                let opened = workspace
16259                    .update_in(acx, |workspace, window, cx| {
16260                        Self::open_locations_in_multibuffer(
16261                            workspace,
16262                            locations,
16263                            title,
16264                            split,
16265                            MultibufferSelectionMode::First,
16266                            window,
16267                            cx,
16268                        )
16269                    })
16270                    .is_ok();
16271
16272                anyhow::Ok(Navigated::from_bool(opened))
16273            } else if locations.is_empty() {
16274                // If there is one definition, just open it directly
16275                match first_url_or_file {
16276                    Some(Either::Left(url)) => {
16277                        acx.update(|_, cx| cx.open_url(&url))?;
16278                        Ok(Navigated::Yes)
16279                    }
16280                    Some(Either::Right(path)) => {
16281                        let Some(workspace) = workspace else {
16282                            return Ok(Navigated::No);
16283                        };
16284
16285                        workspace
16286                            .update_in(acx, |workspace, window, cx| {
16287                                workspace.open_resolved_path(path, window, cx)
16288                            })?
16289                            .await?;
16290                        Ok(Navigated::Yes)
16291                    }
16292                    None => Ok(Navigated::No),
16293                }
16294            } else {
16295                let Some(workspace) = workspace else {
16296                    return Ok(Navigated::No);
16297                };
16298
16299                let target = locations.pop().unwrap();
16300                editor.update_in(acx, |editor, window, cx| {
16301                    let pane = workspace.read(cx).active_pane().clone();
16302
16303                    let range = target.range.to_point(target.buffer.read(cx));
16304                    let range = editor.range_for_match(&range);
16305                    let range = collapse_multiline_range(range);
16306
16307                    if !split
16308                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16309                    {
16310                        editor.go_to_singleton_buffer_range(range, window, cx);
16311                    } else {
16312                        window.defer(cx, move |window, cx| {
16313                            let target_editor: Entity<Self> =
16314                                workspace.update(cx, |workspace, cx| {
16315                                    let pane = if split {
16316                                        workspace.adjacent_pane(window, cx)
16317                                    } else {
16318                                        workspace.active_pane().clone()
16319                                    };
16320
16321                                    workspace.open_project_item(
16322                                        pane,
16323                                        target.buffer.clone(),
16324                                        true,
16325                                        true,
16326                                        window,
16327                                        cx,
16328                                    )
16329                                });
16330                            target_editor.update(cx, |target_editor, cx| {
16331                                // When selecting a definition in a different buffer, disable the nav history
16332                                // to avoid creating a history entry at the previous cursor location.
16333                                pane.update(cx, |pane, _| pane.disable_history());
16334                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16335                                pane.update(cx, |pane, _| pane.enable_history());
16336                            });
16337                        });
16338                    }
16339                    Navigated::Yes
16340                })
16341            }
16342        })
16343    }
16344
16345    fn compute_target_location(
16346        &self,
16347        lsp_location: lsp::Location,
16348        server_id: LanguageServerId,
16349        window: &mut Window,
16350        cx: &mut Context<Self>,
16351    ) -> Task<anyhow::Result<Option<Location>>> {
16352        let Some(project) = self.project.clone() else {
16353            return Task::ready(Ok(None));
16354        };
16355
16356        cx.spawn_in(window, async move |editor, cx| {
16357            let location_task = editor.update(cx, |_, cx| {
16358                project.update(cx, |project, cx| {
16359                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16360                })
16361            })?;
16362            let location = Some({
16363                let target_buffer_handle = location_task.await.context("open local buffer")?;
16364                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16365                    let target_start = target_buffer
16366                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16367                    let target_end = target_buffer
16368                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16369                    target_buffer.anchor_after(target_start)
16370                        ..target_buffer.anchor_before(target_end)
16371                })?;
16372                Location {
16373                    buffer: target_buffer_handle,
16374                    range,
16375                }
16376            });
16377            Ok(location)
16378        })
16379    }
16380
16381    pub fn find_all_references(
16382        &mut self,
16383        _: &FindAllReferences,
16384        window: &mut Window,
16385        cx: &mut Context<Self>,
16386    ) -> Option<Task<Result<Navigated>>> {
16387        let selection = self.selections.newest::<usize>(cx);
16388        let multi_buffer = self.buffer.read(cx);
16389        let head = selection.head();
16390
16391        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16392        let head_anchor = multi_buffer_snapshot.anchor_at(
16393            head,
16394            if head < selection.tail() {
16395                Bias::Right
16396            } else {
16397                Bias::Left
16398            },
16399        );
16400
16401        match self
16402            .find_all_references_task_sources
16403            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16404        {
16405            Ok(_) => {
16406                log::info!(
16407                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16408                );
16409                return None;
16410            }
16411            Err(i) => {
16412                self.find_all_references_task_sources.insert(i, head_anchor);
16413            }
16414        }
16415
16416        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16417        let workspace = self.workspace()?;
16418        let project = workspace.read(cx).project().clone();
16419        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16420        Some(cx.spawn_in(window, async move |editor, cx| {
16421            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16422                if let Ok(i) = editor
16423                    .find_all_references_task_sources
16424                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16425                {
16426                    editor.find_all_references_task_sources.remove(i);
16427                }
16428            });
16429
16430            let Some(locations) = references.await? else {
16431                return anyhow::Ok(Navigated::No);
16432            };
16433            if locations.is_empty() {
16434                return anyhow::Ok(Navigated::No);
16435            }
16436
16437            workspace.update_in(cx, |workspace, window, cx| {
16438                let target = locations
16439                    .iter()
16440                    .map(|location| {
16441                        location
16442                            .buffer
16443                            .read(cx)
16444                            .text_for_range(location.range.clone())
16445                            .collect::<String>()
16446                    })
16447                    .filter(|text| !text.contains('\n'))
16448                    .unique()
16449                    .take(3)
16450                    .join(", ");
16451                let title = if target.is_empty() {
16452                    "References".to_owned()
16453                } else {
16454                    format!("References to {target}")
16455                };
16456                Self::open_locations_in_multibuffer(
16457                    workspace,
16458                    locations,
16459                    title,
16460                    false,
16461                    MultibufferSelectionMode::First,
16462                    window,
16463                    cx,
16464                );
16465                Navigated::Yes
16466            })
16467        }))
16468    }
16469
16470    /// Opens a multibuffer with the given project locations in it
16471    pub fn open_locations_in_multibuffer(
16472        workspace: &mut Workspace,
16473        mut locations: Vec<Location>,
16474        title: String,
16475        split: bool,
16476        multibuffer_selection_mode: MultibufferSelectionMode,
16477        window: &mut Window,
16478        cx: &mut Context<Workspace>,
16479    ) {
16480        if locations.is_empty() {
16481            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16482            return;
16483        }
16484
16485        // If there are multiple definitions, open them in a multibuffer
16486        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16487        let mut locations = locations.into_iter().peekable();
16488        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16489        let capability = workspace.project().read(cx).capability();
16490
16491        let excerpt_buffer = cx.new(|cx| {
16492            let mut multibuffer = MultiBuffer::new(capability);
16493            while let Some(location) = locations.next() {
16494                let buffer = location.buffer.read(cx);
16495                let mut ranges_for_buffer = Vec::new();
16496                let range = location.range.to_point(buffer);
16497                ranges_for_buffer.push(range.clone());
16498
16499                while let Some(next_location) = locations.peek() {
16500                    if next_location.buffer == location.buffer {
16501                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16502                        locations.next();
16503                    } else {
16504                        break;
16505                    }
16506                }
16507
16508                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16509                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16510                    PathKey::for_buffer(&location.buffer, cx),
16511                    location.buffer.clone(),
16512                    ranges_for_buffer,
16513                    multibuffer_context_lines(cx),
16514                    cx,
16515                );
16516                ranges.extend(new_ranges)
16517            }
16518
16519            multibuffer.with_title(title)
16520        });
16521
16522        let editor = cx.new(|cx| {
16523            Editor::for_multibuffer(
16524                excerpt_buffer,
16525                Some(workspace.project().clone()),
16526                window,
16527                cx,
16528            )
16529        });
16530        editor.update(cx, |editor, cx| {
16531            match multibuffer_selection_mode {
16532                MultibufferSelectionMode::First => {
16533                    if let Some(first_range) = ranges.first() {
16534                        editor.change_selections(
16535                            SelectionEffects::no_scroll(),
16536                            window,
16537                            cx,
16538                            |selections| {
16539                                selections.clear_disjoint();
16540                                selections
16541                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16542                            },
16543                        );
16544                    }
16545                    editor.highlight_background::<Self>(
16546                        &ranges,
16547                        |theme| theme.colors().editor_highlighted_line_background,
16548                        cx,
16549                    );
16550                }
16551                MultibufferSelectionMode::All => {
16552                    editor.change_selections(
16553                        SelectionEffects::no_scroll(),
16554                        window,
16555                        cx,
16556                        |selections| {
16557                            selections.clear_disjoint();
16558                            selections.select_anchor_ranges(ranges);
16559                        },
16560                    );
16561                }
16562            }
16563            editor.register_buffers_with_language_servers(cx);
16564        });
16565
16566        let item = Box::new(editor);
16567        let item_id = item.item_id();
16568
16569        if split {
16570            workspace.split_item(SplitDirection::Right, item, window, cx);
16571        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16572            let (preview_item_id, preview_item_idx) =
16573                workspace.active_pane().read_with(cx, |pane, _| {
16574                    (pane.preview_item_id(), pane.preview_item_idx())
16575                });
16576
16577            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16578
16579            if let Some(preview_item_id) = preview_item_id {
16580                workspace.active_pane().update(cx, |pane, cx| {
16581                    pane.remove_item(preview_item_id, false, false, window, cx);
16582                });
16583            }
16584        } else {
16585            workspace.add_item_to_active_pane(item, None, true, window, cx);
16586        }
16587        workspace.active_pane().update(cx, |pane, cx| {
16588            pane.set_preview_item_id(Some(item_id), cx);
16589        });
16590    }
16591
16592    pub fn rename(
16593        &mut self,
16594        _: &Rename,
16595        window: &mut Window,
16596        cx: &mut Context<Self>,
16597    ) -> Option<Task<Result<()>>> {
16598        use language::ToOffset as _;
16599
16600        let provider = self.semantics_provider.clone()?;
16601        let selection = self.selections.newest_anchor().clone();
16602        let (cursor_buffer, cursor_buffer_position) = self
16603            .buffer
16604            .read(cx)
16605            .text_anchor_for_position(selection.head(), cx)?;
16606        let (tail_buffer, cursor_buffer_position_end) = self
16607            .buffer
16608            .read(cx)
16609            .text_anchor_for_position(selection.tail(), cx)?;
16610        if tail_buffer != cursor_buffer {
16611            return None;
16612        }
16613
16614        let snapshot = cursor_buffer.read(cx).snapshot();
16615        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16616        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16617        let prepare_rename = provider
16618            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16619            .unwrap_or_else(|| Task::ready(Ok(None)));
16620        drop(snapshot);
16621
16622        Some(cx.spawn_in(window, async move |this, cx| {
16623            let rename_range = if let Some(range) = prepare_rename.await? {
16624                Some(range)
16625            } else {
16626                this.update(cx, |this, cx| {
16627                    let buffer = this.buffer.read(cx).snapshot(cx);
16628                    let mut buffer_highlights = this
16629                        .document_highlights_for_position(selection.head(), &buffer)
16630                        .filter(|highlight| {
16631                            highlight.start.excerpt_id == selection.head().excerpt_id
16632                                && highlight.end.excerpt_id == selection.head().excerpt_id
16633                        });
16634                    buffer_highlights
16635                        .next()
16636                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16637                })?
16638            };
16639            if let Some(rename_range) = rename_range {
16640                this.update_in(cx, |this, window, cx| {
16641                    let snapshot = cursor_buffer.read(cx).snapshot();
16642                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16643                    let cursor_offset_in_rename_range =
16644                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16645                    let cursor_offset_in_rename_range_end =
16646                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16647
16648                    this.take_rename(false, window, cx);
16649                    let buffer = this.buffer.read(cx).read(cx);
16650                    let cursor_offset = selection.head().to_offset(&buffer);
16651                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16652                    let rename_end = rename_start + rename_buffer_range.len();
16653                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16654                    let mut old_highlight_id = None;
16655                    let old_name: Arc<str> = buffer
16656                        .chunks(rename_start..rename_end, true)
16657                        .map(|chunk| {
16658                            if old_highlight_id.is_none() {
16659                                old_highlight_id = chunk.syntax_highlight_id;
16660                            }
16661                            chunk.text
16662                        })
16663                        .collect::<String>()
16664                        .into();
16665
16666                    drop(buffer);
16667
16668                    // Position the selection in the rename editor so that it matches the current selection.
16669                    this.show_local_selections = false;
16670                    let rename_editor = cx.new(|cx| {
16671                        let mut editor = Editor::single_line(window, cx);
16672                        editor.buffer.update(cx, |buffer, cx| {
16673                            buffer.edit([(0..0, old_name.clone())], None, cx)
16674                        });
16675                        let rename_selection_range = match cursor_offset_in_rename_range
16676                            .cmp(&cursor_offset_in_rename_range_end)
16677                        {
16678                            Ordering::Equal => {
16679                                editor.select_all(&SelectAll, window, cx);
16680                                return editor;
16681                            }
16682                            Ordering::Less => {
16683                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16684                            }
16685                            Ordering::Greater => {
16686                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16687                            }
16688                        };
16689                        if rename_selection_range.end > old_name.len() {
16690                            editor.select_all(&SelectAll, window, cx);
16691                        } else {
16692                            editor.change_selections(Default::default(), window, cx, |s| {
16693                                s.select_ranges([rename_selection_range]);
16694                            });
16695                        }
16696                        editor
16697                    });
16698                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16699                        if e == &EditorEvent::Focused {
16700                            cx.emit(EditorEvent::FocusedIn)
16701                        }
16702                    })
16703                    .detach();
16704
16705                    let write_highlights =
16706                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16707                    let read_highlights =
16708                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16709                    let ranges = write_highlights
16710                        .iter()
16711                        .flat_map(|(_, ranges)| ranges.iter())
16712                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16713                        .cloned()
16714                        .collect();
16715
16716                    this.highlight_text::<Rename>(
16717                        ranges,
16718                        HighlightStyle {
16719                            fade_out: Some(0.6),
16720                            ..Default::default()
16721                        },
16722                        cx,
16723                    );
16724                    let rename_focus_handle = rename_editor.focus_handle(cx);
16725                    window.focus(&rename_focus_handle);
16726                    let block_id = this.insert_blocks(
16727                        [BlockProperties {
16728                            style: BlockStyle::Flex,
16729                            placement: BlockPlacement::Below(range.start),
16730                            height: Some(1),
16731                            render: Arc::new({
16732                                let rename_editor = rename_editor.clone();
16733                                move |cx: &mut BlockContext| {
16734                                    let mut text_style = cx.editor_style.text.clone();
16735                                    if let Some(highlight_style) = old_highlight_id
16736                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16737                                    {
16738                                        text_style = text_style.highlight(highlight_style);
16739                                    }
16740                                    div()
16741                                        .block_mouse_except_scroll()
16742                                        .pl(cx.anchor_x)
16743                                        .child(EditorElement::new(
16744                                            &rename_editor,
16745                                            EditorStyle {
16746                                                background: cx.theme().system().transparent,
16747                                                local_player: cx.editor_style.local_player,
16748                                                text: text_style,
16749                                                scrollbar_width: cx.editor_style.scrollbar_width,
16750                                                syntax: cx.editor_style.syntax.clone(),
16751                                                status: cx.editor_style.status.clone(),
16752                                                inlay_hints_style: HighlightStyle {
16753                                                    font_weight: Some(FontWeight::BOLD),
16754                                                    ..make_inlay_hints_style(cx.app)
16755                                                },
16756                                                edit_prediction_styles: make_suggestion_styles(
16757                                                    cx.app,
16758                                                ),
16759                                                ..EditorStyle::default()
16760                                            },
16761                                        ))
16762                                        .into_any_element()
16763                                }
16764                            }),
16765                            priority: 0,
16766                        }],
16767                        Some(Autoscroll::fit()),
16768                        cx,
16769                    )[0];
16770                    this.pending_rename = Some(RenameState {
16771                        range,
16772                        old_name,
16773                        editor: rename_editor,
16774                        block_id,
16775                    });
16776                })?;
16777            }
16778
16779            Ok(())
16780        }))
16781    }
16782
16783    pub fn confirm_rename(
16784        &mut self,
16785        _: &ConfirmRename,
16786        window: &mut Window,
16787        cx: &mut Context<Self>,
16788    ) -> Option<Task<Result<()>>> {
16789        let rename = self.take_rename(false, window, cx)?;
16790        let workspace = self.workspace()?.downgrade();
16791        let (buffer, start) = self
16792            .buffer
16793            .read(cx)
16794            .text_anchor_for_position(rename.range.start, cx)?;
16795        let (end_buffer, _) = self
16796            .buffer
16797            .read(cx)
16798            .text_anchor_for_position(rename.range.end, cx)?;
16799        if buffer != end_buffer {
16800            return None;
16801        }
16802
16803        let old_name = rename.old_name;
16804        let new_name = rename.editor.read(cx).text(cx);
16805
16806        let rename = self.semantics_provider.as_ref()?.perform_rename(
16807            &buffer,
16808            start,
16809            new_name.clone(),
16810            cx,
16811        )?;
16812
16813        Some(cx.spawn_in(window, async move |editor, cx| {
16814            let project_transaction = rename.await?;
16815            Self::open_project_transaction(
16816                &editor,
16817                workspace,
16818                project_transaction,
16819                format!("Rename: {}{}", old_name, new_name),
16820                cx,
16821            )
16822            .await?;
16823
16824            editor.update(cx, |editor, cx| {
16825                editor.refresh_document_highlights(cx);
16826            })?;
16827            Ok(())
16828        }))
16829    }
16830
16831    fn take_rename(
16832        &mut self,
16833        moving_cursor: bool,
16834        window: &mut Window,
16835        cx: &mut Context<Self>,
16836    ) -> Option<RenameState> {
16837        let rename = self.pending_rename.take()?;
16838        if rename.editor.focus_handle(cx).is_focused(window) {
16839            window.focus(&self.focus_handle);
16840        }
16841
16842        self.remove_blocks(
16843            [rename.block_id].into_iter().collect(),
16844            Some(Autoscroll::fit()),
16845            cx,
16846        );
16847        self.clear_highlights::<Rename>(cx);
16848        self.show_local_selections = true;
16849
16850        if moving_cursor {
16851            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16852                editor.selections.newest::<usize>(cx).head()
16853            });
16854
16855            // Update the selection to match the position of the selection inside
16856            // the rename editor.
16857            let snapshot = self.buffer.read(cx).read(cx);
16858            let rename_range = rename.range.to_offset(&snapshot);
16859            let cursor_in_editor = snapshot
16860                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16861                .min(rename_range.end);
16862            drop(snapshot);
16863
16864            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16865                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16866            });
16867        } else {
16868            self.refresh_document_highlights(cx);
16869        }
16870
16871        Some(rename)
16872    }
16873
16874    pub fn pending_rename(&self) -> Option<&RenameState> {
16875        self.pending_rename.as_ref()
16876    }
16877
16878    fn format(
16879        &mut self,
16880        _: &Format,
16881        window: &mut Window,
16882        cx: &mut Context<Self>,
16883    ) -> Option<Task<Result<()>>> {
16884        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16885
16886        let project = match &self.project {
16887            Some(project) => project.clone(),
16888            None => return None,
16889        };
16890
16891        Some(self.perform_format(
16892            project,
16893            FormatTrigger::Manual,
16894            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16895            window,
16896            cx,
16897        ))
16898    }
16899
16900    fn format_selections(
16901        &mut self,
16902        _: &FormatSelections,
16903        window: &mut Window,
16904        cx: &mut Context<Self>,
16905    ) -> Option<Task<Result<()>>> {
16906        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16907
16908        let project = match &self.project {
16909            Some(project) => project.clone(),
16910            None => return None,
16911        };
16912
16913        let ranges = self
16914            .selections
16915            .all_adjusted(cx)
16916            .into_iter()
16917            .map(|selection| selection.range())
16918            .collect_vec();
16919
16920        Some(self.perform_format(
16921            project,
16922            FormatTrigger::Manual,
16923            FormatTarget::Ranges(ranges),
16924            window,
16925            cx,
16926        ))
16927    }
16928
16929    fn perform_format(
16930        &mut self,
16931        project: Entity<Project>,
16932        trigger: FormatTrigger,
16933        target: FormatTarget,
16934        window: &mut Window,
16935        cx: &mut Context<Self>,
16936    ) -> Task<Result<()>> {
16937        let buffer = self.buffer.clone();
16938        let (buffers, target) = match target {
16939            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16940            FormatTarget::Ranges(selection_ranges) => {
16941                let multi_buffer = buffer.read(cx);
16942                let snapshot = multi_buffer.read(cx);
16943                let mut buffers = HashSet::default();
16944                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16945                    BTreeMap::new();
16946                for selection_range in selection_ranges {
16947                    for (buffer, buffer_range, _) in
16948                        snapshot.range_to_buffer_ranges(selection_range)
16949                    {
16950                        let buffer_id = buffer.remote_id();
16951                        let start = buffer.anchor_before(buffer_range.start);
16952                        let end = buffer.anchor_after(buffer_range.end);
16953                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16954                        buffer_id_to_ranges
16955                            .entry(buffer_id)
16956                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16957                            .or_insert_with(|| vec![start..end]);
16958                    }
16959                }
16960                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16961            }
16962        };
16963
16964        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16965        let selections_prev = transaction_id_prev
16966            .and_then(|transaction_id_prev| {
16967                // default to selections as they were after the last edit, if we have them,
16968                // instead of how they are now.
16969                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16970                // will take you back to where you made the last edit, instead of staying where you scrolled
16971                self.selection_history
16972                    .transaction(transaction_id_prev)
16973                    .map(|t| t.0.clone())
16974            })
16975            .unwrap_or_else(|| self.selections.disjoint_anchors());
16976
16977        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16978        let format = project.update(cx, |project, cx| {
16979            project.format(buffers, target, true, trigger, cx)
16980        });
16981
16982        cx.spawn_in(window, async move |editor, cx| {
16983            let transaction = futures::select_biased! {
16984                transaction = format.log_err().fuse() => transaction,
16985                () = timeout => {
16986                    log::warn!("timed out waiting for formatting");
16987                    None
16988                }
16989            };
16990
16991            buffer
16992                .update(cx, |buffer, cx| {
16993                    if let Some(transaction) = transaction
16994                        && !buffer.is_singleton()
16995                    {
16996                        buffer.push_transaction(&transaction.0, cx);
16997                    }
16998                    cx.notify();
16999                })
17000                .ok();
17001
17002            if let Some(transaction_id_now) =
17003                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17004            {
17005                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17006                if has_new_transaction {
17007                    _ = editor.update(cx, |editor, _| {
17008                        editor
17009                            .selection_history
17010                            .insert_transaction(transaction_id_now, selections_prev);
17011                    });
17012                }
17013            }
17014
17015            Ok(())
17016        })
17017    }
17018
17019    fn organize_imports(
17020        &mut self,
17021        _: &OrganizeImports,
17022        window: &mut Window,
17023        cx: &mut Context<Self>,
17024    ) -> Option<Task<Result<()>>> {
17025        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17026        let project = match &self.project {
17027            Some(project) => project.clone(),
17028            None => return None,
17029        };
17030        Some(self.perform_code_action_kind(
17031            project,
17032            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17033            window,
17034            cx,
17035        ))
17036    }
17037
17038    fn perform_code_action_kind(
17039        &mut self,
17040        project: Entity<Project>,
17041        kind: CodeActionKind,
17042        window: &mut Window,
17043        cx: &mut Context<Self>,
17044    ) -> Task<Result<()>> {
17045        let buffer = self.buffer.clone();
17046        let buffers = buffer.read(cx).all_buffers();
17047        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17048        let apply_action = project.update(cx, |project, cx| {
17049            project.apply_code_action_kind(buffers, kind, true, cx)
17050        });
17051        cx.spawn_in(window, async move |_, cx| {
17052            let transaction = futures::select_biased! {
17053                () = timeout => {
17054                    log::warn!("timed out waiting for executing code action");
17055                    None
17056                }
17057                transaction = apply_action.log_err().fuse() => transaction,
17058            };
17059            buffer
17060                .update(cx, |buffer, cx| {
17061                    // check if we need this
17062                    if let Some(transaction) = transaction
17063                        && !buffer.is_singleton()
17064                    {
17065                        buffer.push_transaction(&transaction.0, cx);
17066                    }
17067                    cx.notify();
17068                })
17069                .ok();
17070            Ok(())
17071        })
17072    }
17073
17074    pub fn restart_language_server(
17075        &mut self,
17076        _: &RestartLanguageServer,
17077        _: &mut Window,
17078        cx: &mut Context<Self>,
17079    ) {
17080        if let Some(project) = self.project.clone() {
17081            self.buffer.update(cx, |multi_buffer, cx| {
17082                project.update(cx, |project, cx| {
17083                    project.restart_language_servers_for_buffers(
17084                        multi_buffer.all_buffers().into_iter().collect(),
17085                        HashSet::default(),
17086                        cx,
17087                    );
17088                });
17089            })
17090        }
17091    }
17092
17093    pub fn stop_language_server(
17094        &mut self,
17095        _: &StopLanguageServer,
17096        _: &mut Window,
17097        cx: &mut Context<Self>,
17098    ) {
17099        if let Some(project) = self.project.clone() {
17100            self.buffer.update(cx, |multi_buffer, cx| {
17101                project.update(cx, |project, cx| {
17102                    project.stop_language_servers_for_buffers(
17103                        multi_buffer.all_buffers().into_iter().collect(),
17104                        HashSet::default(),
17105                        cx,
17106                    );
17107                    cx.emit(project::Event::RefreshInlayHints);
17108                });
17109            });
17110        }
17111    }
17112
17113    fn cancel_language_server_work(
17114        workspace: &mut Workspace,
17115        _: &actions::CancelLanguageServerWork,
17116        _: &mut Window,
17117        cx: &mut Context<Workspace>,
17118    ) {
17119        let project = workspace.project();
17120        let buffers = workspace
17121            .active_item(cx)
17122            .and_then(|item| item.act_as::<Editor>(cx))
17123            .map_or(HashSet::default(), |editor| {
17124                editor.read(cx).buffer.read(cx).all_buffers()
17125            });
17126        project.update(cx, |project, cx| {
17127            project.cancel_language_server_work_for_buffers(buffers, cx);
17128        });
17129    }
17130
17131    fn show_character_palette(
17132        &mut self,
17133        _: &ShowCharacterPalette,
17134        window: &mut Window,
17135        _: &mut Context<Self>,
17136    ) {
17137        window.show_character_palette();
17138    }
17139
17140    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17141        if !self.diagnostics_enabled() {
17142            return;
17143        }
17144
17145        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17146            let buffer = self.buffer.read(cx).snapshot(cx);
17147            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17148            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17149            let is_valid = buffer
17150                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17151                .any(|entry| {
17152                    entry.diagnostic.is_primary
17153                        && !entry.range.is_empty()
17154                        && entry.range.start == primary_range_start
17155                        && entry.diagnostic.message == active_diagnostics.active_message
17156                });
17157
17158            if !is_valid {
17159                self.dismiss_diagnostics(cx);
17160            }
17161        }
17162    }
17163
17164    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17165        match &self.active_diagnostics {
17166            ActiveDiagnostic::Group(group) => Some(group),
17167            _ => None,
17168        }
17169    }
17170
17171    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17172        if !self.diagnostics_enabled() {
17173            return;
17174        }
17175        self.dismiss_diagnostics(cx);
17176        self.active_diagnostics = ActiveDiagnostic::All;
17177    }
17178
17179    fn activate_diagnostics(
17180        &mut self,
17181        buffer_id: BufferId,
17182        diagnostic: DiagnosticEntry<usize>,
17183        window: &mut Window,
17184        cx: &mut Context<Self>,
17185    ) {
17186        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17187            return;
17188        }
17189        self.dismiss_diagnostics(cx);
17190        let snapshot = self.snapshot(window, cx);
17191        let buffer = self.buffer.read(cx).snapshot(cx);
17192        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17193            return;
17194        };
17195
17196        let diagnostic_group = buffer
17197            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17198            .collect::<Vec<_>>();
17199
17200        let blocks =
17201            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17202
17203        let blocks = self.display_map.update(cx, |display_map, cx| {
17204            display_map.insert_blocks(blocks, cx).into_iter().collect()
17205        });
17206        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17207            active_range: buffer.anchor_before(diagnostic.range.start)
17208                ..buffer.anchor_after(diagnostic.range.end),
17209            active_message: diagnostic.diagnostic.message.clone(),
17210            group_id: diagnostic.diagnostic.group_id,
17211            blocks,
17212        });
17213        cx.notify();
17214    }
17215
17216    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17217        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17218            return;
17219        };
17220
17221        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17222        if let ActiveDiagnostic::Group(group) = prev {
17223            self.display_map.update(cx, |display_map, cx| {
17224                display_map.remove_blocks(group.blocks, cx);
17225            });
17226            cx.notify();
17227        }
17228    }
17229
17230    /// Disable inline diagnostics rendering for this editor.
17231    pub fn disable_inline_diagnostics(&mut self) {
17232        self.inline_diagnostics_enabled = false;
17233        self.inline_diagnostics_update = Task::ready(());
17234        self.inline_diagnostics.clear();
17235    }
17236
17237    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17238        self.diagnostics_enabled = false;
17239        self.dismiss_diagnostics(cx);
17240        self.inline_diagnostics_update = Task::ready(());
17241        self.inline_diagnostics.clear();
17242    }
17243
17244    pub fn disable_word_completions(&mut self) {
17245        self.word_completions_enabled = false;
17246    }
17247
17248    pub fn diagnostics_enabled(&self) -> bool {
17249        self.diagnostics_enabled && self.mode.is_full()
17250    }
17251
17252    pub fn inline_diagnostics_enabled(&self) -> bool {
17253        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17254    }
17255
17256    pub fn show_inline_diagnostics(&self) -> bool {
17257        self.show_inline_diagnostics
17258    }
17259
17260    pub fn toggle_inline_diagnostics(
17261        &mut self,
17262        _: &ToggleInlineDiagnostics,
17263        window: &mut Window,
17264        cx: &mut Context<Editor>,
17265    ) {
17266        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17267        self.refresh_inline_diagnostics(false, window, cx);
17268    }
17269
17270    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17271        self.diagnostics_max_severity = severity;
17272        self.display_map.update(cx, |display_map, _| {
17273            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17274        });
17275    }
17276
17277    pub fn toggle_diagnostics(
17278        &mut self,
17279        _: &ToggleDiagnostics,
17280        window: &mut Window,
17281        cx: &mut Context<Editor>,
17282    ) {
17283        if !self.diagnostics_enabled() {
17284            return;
17285        }
17286
17287        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17288            EditorSettings::get_global(cx)
17289                .diagnostics_max_severity
17290                .filter(|severity| severity != &DiagnosticSeverity::Off)
17291                .unwrap_or(DiagnosticSeverity::Hint)
17292        } else {
17293            DiagnosticSeverity::Off
17294        };
17295        self.set_max_diagnostics_severity(new_severity, cx);
17296        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17297            self.active_diagnostics = ActiveDiagnostic::None;
17298            self.inline_diagnostics_update = Task::ready(());
17299            self.inline_diagnostics.clear();
17300        } else {
17301            self.refresh_inline_diagnostics(false, window, cx);
17302        }
17303
17304        cx.notify();
17305    }
17306
17307    pub fn toggle_minimap(
17308        &mut self,
17309        _: &ToggleMinimap,
17310        window: &mut Window,
17311        cx: &mut Context<Editor>,
17312    ) {
17313        if self.supports_minimap(cx) {
17314            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17315        }
17316    }
17317
17318    fn refresh_inline_diagnostics(
17319        &mut self,
17320        debounce: bool,
17321        window: &mut Window,
17322        cx: &mut Context<Self>,
17323    ) {
17324        let max_severity = ProjectSettings::get_global(cx)
17325            .diagnostics
17326            .inline
17327            .max_severity
17328            .unwrap_or(self.diagnostics_max_severity);
17329
17330        if !self.inline_diagnostics_enabled()
17331            || !self.show_inline_diagnostics
17332            || max_severity == DiagnosticSeverity::Off
17333        {
17334            self.inline_diagnostics_update = Task::ready(());
17335            self.inline_diagnostics.clear();
17336            return;
17337        }
17338
17339        let debounce_ms = ProjectSettings::get_global(cx)
17340            .diagnostics
17341            .inline
17342            .update_debounce_ms;
17343        let debounce = if debounce && debounce_ms > 0 {
17344            Some(Duration::from_millis(debounce_ms))
17345        } else {
17346            None
17347        };
17348        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17349            if let Some(debounce) = debounce {
17350                cx.background_executor().timer(debounce).await;
17351            }
17352            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17353                editor
17354                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17355                    .ok()
17356            }) else {
17357                return;
17358            };
17359
17360            let new_inline_diagnostics = cx
17361                .background_spawn(async move {
17362                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17363                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17364                        let message = diagnostic_entry
17365                            .diagnostic
17366                            .message
17367                            .split_once('\n')
17368                            .map(|(line, _)| line)
17369                            .map(SharedString::new)
17370                            .unwrap_or_else(|| {
17371                                SharedString::from(diagnostic_entry.diagnostic.message)
17372                            });
17373                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17374                        let (Ok(i) | Err(i)) = inline_diagnostics
17375                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17376                        inline_diagnostics.insert(
17377                            i,
17378                            (
17379                                start_anchor,
17380                                InlineDiagnostic {
17381                                    message,
17382                                    group_id: diagnostic_entry.diagnostic.group_id,
17383                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17384                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17385                                    severity: diagnostic_entry.diagnostic.severity,
17386                                },
17387                            ),
17388                        );
17389                    }
17390                    inline_diagnostics
17391                })
17392                .await;
17393
17394            editor
17395                .update(cx, |editor, cx| {
17396                    editor.inline_diagnostics = new_inline_diagnostics;
17397                    cx.notify();
17398                })
17399                .ok();
17400        });
17401    }
17402
17403    fn pull_diagnostics(
17404        &mut self,
17405        buffer_id: Option<BufferId>,
17406        window: &Window,
17407        cx: &mut Context<Self>,
17408    ) -> Option<()> {
17409        if !self.mode().is_full() {
17410            return None;
17411        }
17412        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17413            .diagnostics
17414            .lsp_pull_diagnostics;
17415        if !pull_diagnostics_settings.enabled {
17416            return None;
17417        }
17418        let project = self.project()?.downgrade();
17419        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17420        let mut buffers = self.buffer.read(cx).all_buffers();
17421        if let Some(buffer_id) = buffer_id {
17422            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17423        }
17424
17425        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17426            cx.background_executor().timer(debounce).await;
17427
17428            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17429                buffers
17430                    .into_iter()
17431                    .filter_map(|buffer| {
17432                        project
17433                            .update(cx, |project, cx| {
17434                                project.lsp_store().update(cx, |lsp_store, cx| {
17435                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17436                                })
17437                            })
17438                            .ok()
17439                    })
17440                    .collect::<FuturesUnordered<_>>()
17441            }) else {
17442                return;
17443            };
17444
17445            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17446                match pull_task {
17447                    Ok(()) => {
17448                        if editor
17449                            .update_in(cx, |editor, window, cx| {
17450                                editor.update_diagnostics_state(window, cx);
17451                            })
17452                            .is_err()
17453                        {
17454                            return;
17455                        }
17456                    }
17457                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17458                }
17459            }
17460        });
17461
17462        Some(())
17463    }
17464
17465    pub fn set_selections_from_remote(
17466        &mut self,
17467        selections: Vec<Selection<Anchor>>,
17468        pending_selection: Option<Selection<Anchor>>,
17469        window: &mut Window,
17470        cx: &mut Context<Self>,
17471    ) {
17472        let old_cursor_position = self.selections.newest_anchor().head();
17473        self.selections.change_with(cx, |s| {
17474            s.select_anchors(selections);
17475            if let Some(pending_selection) = pending_selection {
17476                s.set_pending(pending_selection, SelectMode::Character);
17477            } else {
17478                s.clear_pending();
17479            }
17480        });
17481        self.selections_did_change(
17482            false,
17483            &old_cursor_position,
17484            SelectionEffects::default(),
17485            window,
17486            cx,
17487        );
17488    }
17489
17490    pub fn transact(
17491        &mut self,
17492        window: &mut Window,
17493        cx: &mut Context<Self>,
17494        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17495    ) -> Option<TransactionId> {
17496        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17497            this.start_transaction_at(Instant::now(), window, cx);
17498            update(this, window, cx);
17499            this.end_transaction_at(Instant::now(), cx)
17500        })
17501    }
17502
17503    pub fn start_transaction_at(
17504        &mut self,
17505        now: Instant,
17506        window: &mut Window,
17507        cx: &mut Context<Self>,
17508    ) -> Option<TransactionId> {
17509        self.end_selection(window, cx);
17510        if let Some(tx_id) = self
17511            .buffer
17512            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17513        {
17514            self.selection_history
17515                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17516            cx.emit(EditorEvent::TransactionBegun {
17517                transaction_id: tx_id,
17518            });
17519            Some(tx_id)
17520        } else {
17521            None
17522        }
17523    }
17524
17525    pub fn end_transaction_at(
17526        &mut self,
17527        now: Instant,
17528        cx: &mut Context<Self>,
17529    ) -> Option<TransactionId> {
17530        if let Some(transaction_id) = self
17531            .buffer
17532            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17533        {
17534            if let Some((_, end_selections)) =
17535                self.selection_history.transaction_mut(transaction_id)
17536            {
17537                *end_selections = Some(self.selections.disjoint_anchors());
17538            } else {
17539                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17540            }
17541
17542            cx.emit(EditorEvent::Edited { transaction_id });
17543            Some(transaction_id)
17544        } else {
17545            None
17546        }
17547    }
17548
17549    pub fn modify_transaction_selection_history(
17550        &mut self,
17551        transaction_id: TransactionId,
17552        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17553    ) -> bool {
17554        self.selection_history
17555            .transaction_mut(transaction_id)
17556            .map(modify)
17557            .is_some()
17558    }
17559
17560    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17561        if self.selection_mark_mode {
17562            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17563                s.move_with(|_, sel| {
17564                    sel.collapse_to(sel.head(), SelectionGoal::None);
17565                });
17566            })
17567        }
17568        self.selection_mark_mode = true;
17569        cx.notify();
17570    }
17571
17572    pub fn swap_selection_ends(
17573        &mut self,
17574        _: &actions::SwapSelectionEnds,
17575        window: &mut Window,
17576        cx: &mut Context<Self>,
17577    ) {
17578        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17579            s.move_with(|_, sel| {
17580                if sel.start != sel.end {
17581                    sel.reversed = !sel.reversed
17582                }
17583            });
17584        });
17585        self.request_autoscroll(Autoscroll::newest(), cx);
17586        cx.notify();
17587    }
17588
17589    pub fn toggle_focus(
17590        workspace: &mut Workspace,
17591        _: &actions::ToggleFocus,
17592        window: &mut Window,
17593        cx: &mut Context<Workspace>,
17594    ) {
17595        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17596            return;
17597        };
17598        workspace.activate_item(&item, true, true, window, cx);
17599    }
17600
17601    pub fn toggle_fold(
17602        &mut self,
17603        _: &actions::ToggleFold,
17604        window: &mut Window,
17605        cx: &mut Context<Self>,
17606    ) {
17607        if self.is_singleton(cx) {
17608            let selection = self.selections.newest::<Point>(cx);
17609
17610            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17611            let range = if selection.is_empty() {
17612                let point = selection.head().to_display_point(&display_map);
17613                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17614                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17615                    .to_point(&display_map);
17616                start..end
17617            } else {
17618                selection.range()
17619            };
17620            if display_map.folds_in_range(range).next().is_some() {
17621                self.unfold_lines(&Default::default(), window, cx)
17622            } else {
17623                self.fold(&Default::default(), window, cx)
17624            }
17625        } else {
17626            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17627            let buffer_ids: HashSet<_> = self
17628                .selections
17629                .disjoint_anchor_ranges()
17630                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17631                .collect();
17632
17633            let should_unfold = buffer_ids
17634                .iter()
17635                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17636
17637            for buffer_id in buffer_ids {
17638                if should_unfold {
17639                    self.unfold_buffer(buffer_id, cx);
17640                } else {
17641                    self.fold_buffer(buffer_id, cx);
17642                }
17643            }
17644        }
17645    }
17646
17647    pub fn toggle_fold_recursive(
17648        &mut self,
17649        _: &actions::ToggleFoldRecursive,
17650        window: &mut Window,
17651        cx: &mut Context<Self>,
17652    ) {
17653        let selection = self.selections.newest::<Point>(cx);
17654
17655        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17656        let range = if selection.is_empty() {
17657            let point = selection.head().to_display_point(&display_map);
17658            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17659            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17660                .to_point(&display_map);
17661            start..end
17662        } else {
17663            selection.range()
17664        };
17665        if display_map.folds_in_range(range).next().is_some() {
17666            self.unfold_recursive(&Default::default(), window, cx)
17667        } else {
17668            self.fold_recursive(&Default::default(), window, cx)
17669        }
17670    }
17671
17672    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17673        if self.is_singleton(cx) {
17674            let mut to_fold = Vec::new();
17675            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17676            let selections = self.selections.all_adjusted(cx);
17677
17678            for selection in selections {
17679                let range = selection.range().sorted();
17680                let buffer_start_row = range.start.row;
17681
17682                if range.start.row != range.end.row {
17683                    let mut found = false;
17684                    let mut row = range.start.row;
17685                    while row <= range.end.row {
17686                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17687                        {
17688                            found = true;
17689                            row = crease.range().end.row + 1;
17690                            to_fold.push(crease);
17691                        } else {
17692                            row += 1
17693                        }
17694                    }
17695                    if found {
17696                        continue;
17697                    }
17698                }
17699
17700                for row in (0..=range.start.row).rev() {
17701                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17702                        && crease.range().end.row >= buffer_start_row
17703                    {
17704                        to_fold.push(crease);
17705                        if row <= range.start.row {
17706                            break;
17707                        }
17708                    }
17709                }
17710            }
17711
17712            self.fold_creases(to_fold, true, window, cx);
17713        } else {
17714            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17715            let buffer_ids = self
17716                .selections
17717                .disjoint_anchor_ranges()
17718                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17719                .collect::<HashSet<_>>();
17720            for buffer_id in buffer_ids {
17721                self.fold_buffer(buffer_id, cx);
17722            }
17723        }
17724    }
17725
17726    pub fn toggle_fold_all(
17727        &mut self,
17728        _: &actions::ToggleFoldAll,
17729        window: &mut Window,
17730        cx: &mut Context<Self>,
17731    ) {
17732        if self.buffer.read(cx).is_singleton() {
17733            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17734            let has_folds = display_map
17735                .folds_in_range(0..display_map.buffer_snapshot.len())
17736                .next()
17737                .is_some();
17738
17739            if has_folds {
17740                self.unfold_all(&actions::UnfoldAll, window, cx);
17741            } else {
17742                self.fold_all(&actions::FoldAll, window, cx);
17743            }
17744        } else {
17745            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17746            let should_unfold = buffer_ids
17747                .iter()
17748                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17749
17750            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17751                editor
17752                    .update_in(cx, |editor, _, cx| {
17753                        for buffer_id in buffer_ids {
17754                            if should_unfold {
17755                                editor.unfold_buffer(buffer_id, cx);
17756                            } else {
17757                                editor.fold_buffer(buffer_id, cx);
17758                            }
17759                        }
17760                    })
17761                    .ok();
17762            });
17763        }
17764    }
17765
17766    fn fold_at_level(
17767        &mut self,
17768        fold_at: &FoldAtLevel,
17769        window: &mut Window,
17770        cx: &mut Context<Self>,
17771    ) {
17772        if !self.buffer.read(cx).is_singleton() {
17773            return;
17774        }
17775
17776        let fold_at_level = fold_at.0;
17777        let snapshot = self.buffer.read(cx).snapshot(cx);
17778        let mut to_fold = Vec::new();
17779        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17780
17781        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17782            while start_row < end_row {
17783                match self
17784                    .snapshot(window, cx)
17785                    .crease_for_buffer_row(MultiBufferRow(start_row))
17786                {
17787                    Some(crease) => {
17788                        let nested_start_row = crease.range().start.row + 1;
17789                        let nested_end_row = crease.range().end.row;
17790
17791                        if current_level < fold_at_level {
17792                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17793                        } else if current_level == fold_at_level {
17794                            to_fold.push(crease);
17795                        }
17796
17797                        start_row = nested_end_row + 1;
17798                    }
17799                    None => start_row += 1,
17800                }
17801            }
17802        }
17803
17804        self.fold_creases(to_fold, true, window, cx);
17805    }
17806
17807    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17808        if self.buffer.read(cx).is_singleton() {
17809            let mut fold_ranges = Vec::new();
17810            let snapshot = self.buffer.read(cx).snapshot(cx);
17811
17812            for row in 0..snapshot.max_row().0 {
17813                if let Some(foldable_range) = self
17814                    .snapshot(window, cx)
17815                    .crease_for_buffer_row(MultiBufferRow(row))
17816                {
17817                    fold_ranges.push(foldable_range);
17818                }
17819            }
17820
17821            self.fold_creases(fold_ranges, true, window, cx);
17822        } else {
17823            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17824                editor
17825                    .update_in(cx, |editor, _, cx| {
17826                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17827                            editor.fold_buffer(buffer_id, cx);
17828                        }
17829                    })
17830                    .ok();
17831            });
17832        }
17833    }
17834
17835    pub fn fold_function_bodies(
17836        &mut self,
17837        _: &actions::FoldFunctionBodies,
17838        window: &mut Window,
17839        cx: &mut Context<Self>,
17840    ) {
17841        let snapshot = self.buffer.read(cx).snapshot(cx);
17842
17843        let ranges = snapshot
17844            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17845            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17846            .collect::<Vec<_>>();
17847
17848        let creases = ranges
17849            .into_iter()
17850            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17851            .collect();
17852
17853        self.fold_creases(creases, true, window, cx);
17854    }
17855
17856    pub fn fold_recursive(
17857        &mut self,
17858        _: &actions::FoldRecursive,
17859        window: &mut Window,
17860        cx: &mut Context<Self>,
17861    ) {
17862        let mut to_fold = Vec::new();
17863        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17864        let selections = self.selections.all_adjusted(cx);
17865
17866        for selection in selections {
17867            let range = selection.range().sorted();
17868            let buffer_start_row = range.start.row;
17869
17870            if range.start.row != range.end.row {
17871                let mut found = false;
17872                for row in range.start.row..=range.end.row {
17873                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17874                        found = true;
17875                        to_fold.push(crease);
17876                    }
17877                }
17878                if found {
17879                    continue;
17880                }
17881            }
17882
17883            for row in (0..=range.start.row).rev() {
17884                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17885                    if crease.range().end.row >= buffer_start_row {
17886                        to_fold.push(crease);
17887                    } else {
17888                        break;
17889                    }
17890                }
17891            }
17892        }
17893
17894        self.fold_creases(to_fold, true, window, cx);
17895    }
17896
17897    pub fn fold_at(
17898        &mut self,
17899        buffer_row: MultiBufferRow,
17900        window: &mut Window,
17901        cx: &mut Context<Self>,
17902    ) {
17903        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17904
17905        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17906            let autoscroll = self
17907                .selections
17908                .all::<Point>(cx)
17909                .iter()
17910                .any(|selection| crease.range().overlaps(&selection.range()));
17911
17912            self.fold_creases(vec![crease], autoscroll, window, cx);
17913        }
17914    }
17915
17916    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17917        if self.is_singleton(cx) {
17918            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17919            let buffer = &display_map.buffer_snapshot;
17920            let selections = self.selections.all::<Point>(cx);
17921            let ranges = selections
17922                .iter()
17923                .map(|s| {
17924                    let range = s.display_range(&display_map).sorted();
17925                    let mut start = range.start.to_point(&display_map);
17926                    let mut end = range.end.to_point(&display_map);
17927                    start.column = 0;
17928                    end.column = buffer.line_len(MultiBufferRow(end.row));
17929                    start..end
17930                })
17931                .collect::<Vec<_>>();
17932
17933            self.unfold_ranges(&ranges, true, true, cx);
17934        } else {
17935            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17936            let buffer_ids = self
17937                .selections
17938                .disjoint_anchor_ranges()
17939                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17940                .collect::<HashSet<_>>();
17941            for buffer_id in buffer_ids {
17942                self.unfold_buffer(buffer_id, cx);
17943            }
17944        }
17945    }
17946
17947    pub fn unfold_recursive(
17948        &mut self,
17949        _: &UnfoldRecursive,
17950        _window: &mut Window,
17951        cx: &mut Context<Self>,
17952    ) {
17953        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17954        let selections = self.selections.all::<Point>(cx);
17955        let ranges = selections
17956            .iter()
17957            .map(|s| {
17958                let mut range = s.display_range(&display_map).sorted();
17959                *range.start.column_mut() = 0;
17960                *range.end.column_mut() = display_map.line_len(range.end.row());
17961                let start = range.start.to_point(&display_map);
17962                let end = range.end.to_point(&display_map);
17963                start..end
17964            })
17965            .collect::<Vec<_>>();
17966
17967        self.unfold_ranges(&ranges, true, true, cx);
17968    }
17969
17970    pub fn unfold_at(
17971        &mut self,
17972        buffer_row: MultiBufferRow,
17973        _window: &mut Window,
17974        cx: &mut Context<Self>,
17975    ) {
17976        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17977
17978        let intersection_range = Point::new(buffer_row.0, 0)
17979            ..Point::new(
17980                buffer_row.0,
17981                display_map.buffer_snapshot.line_len(buffer_row),
17982            );
17983
17984        let autoscroll = self
17985            .selections
17986            .all::<Point>(cx)
17987            .iter()
17988            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17989
17990        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17991    }
17992
17993    pub fn unfold_all(
17994        &mut self,
17995        _: &actions::UnfoldAll,
17996        _window: &mut Window,
17997        cx: &mut Context<Self>,
17998    ) {
17999        if self.buffer.read(cx).is_singleton() {
18000            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18001            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18002        } else {
18003            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18004                editor
18005                    .update(cx, |editor, cx| {
18006                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18007                            editor.unfold_buffer(buffer_id, cx);
18008                        }
18009                    })
18010                    .ok();
18011            });
18012        }
18013    }
18014
18015    pub fn fold_selected_ranges(
18016        &mut self,
18017        _: &FoldSelectedRanges,
18018        window: &mut Window,
18019        cx: &mut Context<Self>,
18020    ) {
18021        let selections = self.selections.all_adjusted(cx);
18022        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18023        let ranges = selections
18024            .into_iter()
18025            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18026            .collect::<Vec<_>>();
18027        self.fold_creases(ranges, true, window, cx);
18028    }
18029
18030    pub fn fold_ranges<T: ToOffset + Clone>(
18031        &mut self,
18032        ranges: Vec<Range<T>>,
18033        auto_scroll: bool,
18034        window: &mut Window,
18035        cx: &mut Context<Self>,
18036    ) {
18037        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18038        let ranges = ranges
18039            .into_iter()
18040            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18041            .collect::<Vec<_>>();
18042        self.fold_creases(ranges, auto_scroll, window, cx);
18043    }
18044
18045    pub fn fold_creases<T: ToOffset + Clone>(
18046        &mut self,
18047        creases: Vec<Crease<T>>,
18048        auto_scroll: bool,
18049        _window: &mut Window,
18050        cx: &mut Context<Self>,
18051    ) {
18052        if creases.is_empty() {
18053            return;
18054        }
18055
18056        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18057
18058        if auto_scroll {
18059            self.request_autoscroll(Autoscroll::fit(), cx);
18060        }
18061
18062        cx.notify();
18063
18064        self.scrollbar_marker_state.dirty = true;
18065        self.folds_did_change(cx);
18066    }
18067
18068    /// Removes any folds whose ranges intersect any of the given ranges.
18069    pub fn unfold_ranges<T: ToOffset + Clone>(
18070        &mut self,
18071        ranges: &[Range<T>],
18072        inclusive: bool,
18073        auto_scroll: bool,
18074        cx: &mut Context<Self>,
18075    ) {
18076        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18077            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18078        });
18079        self.folds_did_change(cx);
18080    }
18081
18082    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18083        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18084            return;
18085        }
18086        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18087        self.display_map.update(cx, |display_map, cx| {
18088            display_map.fold_buffers([buffer_id], cx)
18089        });
18090        cx.emit(EditorEvent::BufferFoldToggled {
18091            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18092            folded: true,
18093        });
18094        cx.notify();
18095    }
18096
18097    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18098        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18099            return;
18100        }
18101        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18102        self.display_map.update(cx, |display_map, cx| {
18103            display_map.unfold_buffers([buffer_id], cx);
18104        });
18105        cx.emit(EditorEvent::BufferFoldToggled {
18106            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18107            folded: false,
18108        });
18109        cx.notify();
18110    }
18111
18112    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18113        self.display_map.read(cx).is_buffer_folded(buffer)
18114    }
18115
18116    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18117        self.display_map.read(cx).folded_buffers()
18118    }
18119
18120    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18121        self.display_map.update(cx, |display_map, cx| {
18122            display_map.disable_header_for_buffer(buffer_id, cx);
18123        });
18124        cx.notify();
18125    }
18126
18127    /// Removes any folds with the given ranges.
18128    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18129        &mut self,
18130        ranges: &[Range<T>],
18131        type_id: TypeId,
18132        auto_scroll: bool,
18133        cx: &mut Context<Self>,
18134    ) {
18135        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18136            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18137        });
18138        self.folds_did_change(cx);
18139    }
18140
18141    fn remove_folds_with<T: ToOffset + Clone>(
18142        &mut self,
18143        ranges: &[Range<T>],
18144        auto_scroll: bool,
18145        cx: &mut Context<Self>,
18146        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18147    ) {
18148        if ranges.is_empty() {
18149            return;
18150        }
18151
18152        let mut buffers_affected = HashSet::default();
18153        let multi_buffer = self.buffer().read(cx);
18154        for range in ranges {
18155            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18156                buffers_affected.insert(buffer.read(cx).remote_id());
18157            };
18158        }
18159
18160        self.display_map.update(cx, update);
18161
18162        if auto_scroll {
18163            self.request_autoscroll(Autoscroll::fit(), cx);
18164        }
18165
18166        cx.notify();
18167        self.scrollbar_marker_state.dirty = true;
18168        self.active_indent_guides_state.dirty = true;
18169    }
18170
18171    pub fn update_renderer_widths(
18172        &mut self,
18173        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18174        cx: &mut Context<Self>,
18175    ) -> bool {
18176        self.display_map
18177            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18178    }
18179
18180    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18181        self.display_map.read(cx).fold_placeholder.clone()
18182    }
18183
18184    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18185        self.buffer.update(cx, |buffer, cx| {
18186            buffer.set_all_diff_hunks_expanded(cx);
18187        });
18188    }
18189
18190    pub fn expand_all_diff_hunks(
18191        &mut self,
18192        _: &ExpandAllDiffHunks,
18193        _window: &mut Window,
18194        cx: &mut Context<Self>,
18195    ) {
18196        self.buffer.update(cx, |buffer, cx| {
18197            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18198        });
18199    }
18200
18201    pub fn toggle_selected_diff_hunks(
18202        &mut self,
18203        _: &ToggleSelectedDiffHunks,
18204        _window: &mut Window,
18205        cx: &mut Context<Self>,
18206    ) {
18207        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18208        self.toggle_diff_hunks_in_ranges(ranges, cx);
18209    }
18210
18211    pub fn diff_hunks_in_ranges<'a>(
18212        &'a self,
18213        ranges: &'a [Range<Anchor>],
18214        buffer: &'a MultiBufferSnapshot,
18215    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18216        ranges.iter().flat_map(move |range| {
18217            let end_excerpt_id = range.end.excerpt_id;
18218            let range = range.to_point(buffer);
18219            let mut peek_end = range.end;
18220            if range.end.row < buffer.max_row().0 {
18221                peek_end = Point::new(range.end.row + 1, 0);
18222            }
18223            buffer
18224                .diff_hunks_in_range(range.start..peek_end)
18225                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18226        })
18227    }
18228
18229    pub fn has_stageable_diff_hunks_in_ranges(
18230        &self,
18231        ranges: &[Range<Anchor>],
18232        snapshot: &MultiBufferSnapshot,
18233    ) -> bool {
18234        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18235        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18236    }
18237
18238    pub fn toggle_staged_selected_diff_hunks(
18239        &mut self,
18240        _: &::git::ToggleStaged,
18241        _: &mut Window,
18242        cx: &mut Context<Self>,
18243    ) {
18244        let snapshot = self.buffer.read(cx).snapshot(cx);
18245        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18246        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18247        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18248    }
18249
18250    pub fn set_render_diff_hunk_controls(
18251        &mut self,
18252        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18253        cx: &mut Context<Self>,
18254    ) {
18255        self.render_diff_hunk_controls = render_diff_hunk_controls;
18256        cx.notify();
18257    }
18258
18259    pub fn stage_and_next(
18260        &mut self,
18261        _: &::git::StageAndNext,
18262        window: &mut Window,
18263        cx: &mut Context<Self>,
18264    ) {
18265        self.do_stage_or_unstage_and_next(true, window, cx);
18266    }
18267
18268    pub fn unstage_and_next(
18269        &mut self,
18270        _: &::git::UnstageAndNext,
18271        window: &mut Window,
18272        cx: &mut Context<Self>,
18273    ) {
18274        self.do_stage_or_unstage_and_next(false, window, cx);
18275    }
18276
18277    pub fn stage_or_unstage_diff_hunks(
18278        &mut self,
18279        stage: bool,
18280        ranges: Vec<Range<Anchor>>,
18281        cx: &mut Context<Self>,
18282    ) {
18283        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18284        cx.spawn(async move |this, cx| {
18285            task.await?;
18286            this.update(cx, |this, cx| {
18287                let snapshot = this.buffer.read(cx).snapshot(cx);
18288                let chunk_by = this
18289                    .diff_hunks_in_ranges(&ranges, &snapshot)
18290                    .chunk_by(|hunk| hunk.buffer_id);
18291                for (buffer_id, hunks) in &chunk_by {
18292                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18293                }
18294            })
18295        })
18296        .detach_and_log_err(cx);
18297    }
18298
18299    fn save_buffers_for_ranges_if_needed(
18300        &mut self,
18301        ranges: &[Range<Anchor>],
18302        cx: &mut Context<Editor>,
18303    ) -> Task<Result<()>> {
18304        let multibuffer = self.buffer.read(cx);
18305        let snapshot = multibuffer.read(cx);
18306        let buffer_ids: HashSet<_> = ranges
18307            .iter()
18308            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18309            .collect();
18310        drop(snapshot);
18311
18312        let mut buffers = HashSet::default();
18313        for buffer_id in buffer_ids {
18314            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18315                let buffer = buffer_entity.read(cx);
18316                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18317                {
18318                    buffers.insert(buffer_entity);
18319                }
18320            }
18321        }
18322
18323        if let Some(project) = &self.project {
18324            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18325        } else {
18326            Task::ready(Ok(()))
18327        }
18328    }
18329
18330    fn do_stage_or_unstage_and_next(
18331        &mut self,
18332        stage: bool,
18333        window: &mut Window,
18334        cx: &mut Context<Self>,
18335    ) {
18336        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18337
18338        if ranges.iter().any(|range| range.start != range.end) {
18339            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18340            return;
18341        }
18342
18343        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18344        let snapshot = self.snapshot(window, cx);
18345        let position = self.selections.newest::<Point>(cx).head();
18346        let mut row = snapshot
18347            .buffer_snapshot
18348            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18349            .find(|hunk| hunk.row_range.start.0 > position.row)
18350            .map(|hunk| hunk.row_range.start);
18351
18352        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18353        // Outside of the project diff editor, wrap around to the beginning.
18354        if !all_diff_hunks_expanded {
18355            row = row.or_else(|| {
18356                snapshot
18357                    .buffer_snapshot
18358                    .diff_hunks_in_range(Point::zero()..position)
18359                    .find(|hunk| hunk.row_range.end.0 < position.row)
18360                    .map(|hunk| hunk.row_range.start)
18361            });
18362        }
18363
18364        if let Some(row) = row {
18365            let destination = Point::new(row.0, 0);
18366            let autoscroll = Autoscroll::center();
18367
18368            self.unfold_ranges(&[destination..destination], false, false, cx);
18369            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18370                s.select_ranges([destination..destination]);
18371            });
18372        }
18373    }
18374
18375    fn do_stage_or_unstage(
18376        &self,
18377        stage: bool,
18378        buffer_id: BufferId,
18379        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18380        cx: &mut App,
18381    ) -> Option<()> {
18382        let project = self.project()?;
18383        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18384        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18385        let buffer_snapshot = buffer.read(cx).snapshot();
18386        let file_exists = buffer_snapshot
18387            .file()
18388            .is_some_and(|file| file.disk_state().exists());
18389        diff.update(cx, |diff, cx| {
18390            diff.stage_or_unstage_hunks(
18391                stage,
18392                &hunks
18393                    .map(|hunk| buffer_diff::DiffHunk {
18394                        buffer_range: hunk.buffer_range,
18395                        diff_base_byte_range: hunk.diff_base_byte_range,
18396                        secondary_status: hunk.secondary_status,
18397                        range: Point::zero()..Point::zero(), // unused
18398                    })
18399                    .collect::<Vec<_>>(),
18400                &buffer_snapshot,
18401                file_exists,
18402                cx,
18403            )
18404        });
18405        None
18406    }
18407
18408    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18409        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18410        self.buffer
18411            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18412    }
18413
18414    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18415        self.buffer.update(cx, |buffer, cx| {
18416            let ranges = vec![Anchor::min()..Anchor::max()];
18417            if !buffer.all_diff_hunks_expanded()
18418                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18419            {
18420                buffer.collapse_diff_hunks(ranges, cx);
18421                true
18422            } else {
18423                false
18424            }
18425        })
18426    }
18427
18428    fn toggle_diff_hunks_in_ranges(
18429        &mut self,
18430        ranges: Vec<Range<Anchor>>,
18431        cx: &mut Context<Editor>,
18432    ) {
18433        self.buffer.update(cx, |buffer, cx| {
18434            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18435            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18436        })
18437    }
18438
18439    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18440        self.buffer.update(cx, |buffer, cx| {
18441            let snapshot = buffer.snapshot(cx);
18442            let excerpt_id = range.end.excerpt_id;
18443            let point_range = range.to_point(&snapshot);
18444            let expand = !buffer.single_hunk_is_expanded(range, cx);
18445            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18446        })
18447    }
18448
18449    pub(crate) fn apply_all_diff_hunks(
18450        &mut self,
18451        _: &ApplyAllDiffHunks,
18452        window: &mut Window,
18453        cx: &mut Context<Self>,
18454    ) {
18455        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18456
18457        let buffers = self.buffer.read(cx).all_buffers();
18458        for branch_buffer in buffers {
18459            branch_buffer.update(cx, |branch_buffer, cx| {
18460                branch_buffer.merge_into_base(Vec::new(), cx);
18461            });
18462        }
18463
18464        if let Some(project) = self.project.clone() {
18465            self.save(
18466                SaveOptions {
18467                    format: true,
18468                    autosave: false,
18469                },
18470                project,
18471                window,
18472                cx,
18473            )
18474            .detach_and_log_err(cx);
18475        }
18476    }
18477
18478    pub(crate) fn apply_selected_diff_hunks(
18479        &mut self,
18480        _: &ApplyDiffHunk,
18481        window: &mut Window,
18482        cx: &mut Context<Self>,
18483    ) {
18484        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18485        let snapshot = self.snapshot(window, cx);
18486        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18487        let mut ranges_by_buffer = HashMap::default();
18488        self.transact(window, cx, |editor, _window, cx| {
18489            for hunk in hunks {
18490                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18491                    ranges_by_buffer
18492                        .entry(buffer.clone())
18493                        .or_insert_with(Vec::new)
18494                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18495                }
18496            }
18497
18498            for (buffer, ranges) in ranges_by_buffer {
18499                buffer.update(cx, |buffer, cx| {
18500                    buffer.merge_into_base(ranges, cx);
18501                });
18502            }
18503        });
18504
18505        if let Some(project) = self.project.clone() {
18506            self.save(
18507                SaveOptions {
18508                    format: true,
18509                    autosave: false,
18510                },
18511                project,
18512                window,
18513                cx,
18514            )
18515            .detach_and_log_err(cx);
18516        }
18517    }
18518
18519    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18520        if hovered != self.gutter_hovered {
18521            self.gutter_hovered = hovered;
18522            cx.notify();
18523        }
18524    }
18525
18526    pub fn insert_blocks(
18527        &mut self,
18528        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18529        autoscroll: Option<Autoscroll>,
18530        cx: &mut Context<Self>,
18531    ) -> Vec<CustomBlockId> {
18532        let blocks = self
18533            .display_map
18534            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18535        if let Some(autoscroll) = autoscroll {
18536            self.request_autoscroll(autoscroll, cx);
18537        }
18538        cx.notify();
18539        blocks
18540    }
18541
18542    pub fn resize_blocks(
18543        &mut self,
18544        heights: HashMap<CustomBlockId, u32>,
18545        autoscroll: Option<Autoscroll>,
18546        cx: &mut Context<Self>,
18547    ) {
18548        self.display_map
18549            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18550        if let Some(autoscroll) = autoscroll {
18551            self.request_autoscroll(autoscroll, cx);
18552        }
18553        cx.notify();
18554    }
18555
18556    pub fn replace_blocks(
18557        &mut self,
18558        renderers: HashMap<CustomBlockId, RenderBlock>,
18559        autoscroll: Option<Autoscroll>,
18560        cx: &mut Context<Self>,
18561    ) {
18562        self.display_map
18563            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18564        if let Some(autoscroll) = autoscroll {
18565            self.request_autoscroll(autoscroll, cx);
18566        }
18567        cx.notify();
18568    }
18569
18570    pub fn remove_blocks(
18571        &mut self,
18572        block_ids: HashSet<CustomBlockId>,
18573        autoscroll: Option<Autoscroll>,
18574        cx: &mut Context<Self>,
18575    ) {
18576        self.display_map.update(cx, |display_map, cx| {
18577            display_map.remove_blocks(block_ids, cx)
18578        });
18579        if let Some(autoscroll) = autoscroll {
18580            self.request_autoscroll(autoscroll, cx);
18581        }
18582        cx.notify();
18583    }
18584
18585    pub fn row_for_block(
18586        &self,
18587        block_id: CustomBlockId,
18588        cx: &mut Context<Self>,
18589    ) -> Option<DisplayRow> {
18590        self.display_map
18591            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18592    }
18593
18594    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18595        self.focused_block = Some(focused_block);
18596    }
18597
18598    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18599        self.focused_block.take()
18600    }
18601
18602    pub fn insert_creases(
18603        &mut self,
18604        creases: impl IntoIterator<Item = Crease<Anchor>>,
18605        cx: &mut Context<Self>,
18606    ) -> Vec<CreaseId> {
18607        self.display_map
18608            .update(cx, |map, cx| map.insert_creases(creases, cx))
18609    }
18610
18611    pub fn remove_creases(
18612        &mut self,
18613        ids: impl IntoIterator<Item = CreaseId>,
18614        cx: &mut Context<Self>,
18615    ) -> Vec<(CreaseId, Range<Anchor>)> {
18616        self.display_map
18617            .update(cx, |map, cx| map.remove_creases(ids, cx))
18618    }
18619
18620    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18621        self.display_map
18622            .update(cx, |map, cx| map.snapshot(cx))
18623            .longest_row()
18624    }
18625
18626    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18627        self.display_map
18628            .update(cx, |map, cx| map.snapshot(cx))
18629            .max_point()
18630    }
18631
18632    pub fn text(&self, cx: &App) -> String {
18633        self.buffer.read(cx).read(cx).text()
18634    }
18635
18636    pub fn is_empty(&self, cx: &App) -> bool {
18637        self.buffer.read(cx).read(cx).is_empty()
18638    }
18639
18640    pub fn text_option(&self, cx: &App) -> Option<String> {
18641        let text = self.text(cx);
18642        let text = text.trim();
18643
18644        if text.is_empty() {
18645            return None;
18646        }
18647
18648        Some(text.to_string())
18649    }
18650
18651    pub fn set_text(
18652        &mut self,
18653        text: impl Into<Arc<str>>,
18654        window: &mut Window,
18655        cx: &mut Context<Self>,
18656    ) {
18657        self.transact(window, cx, |this, _, cx| {
18658            this.buffer
18659                .read(cx)
18660                .as_singleton()
18661                .expect("you can only call set_text on editors for singleton buffers")
18662                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18663        });
18664    }
18665
18666    pub fn display_text(&self, cx: &mut App) -> String {
18667        self.display_map
18668            .update(cx, |map, cx| map.snapshot(cx))
18669            .text()
18670    }
18671
18672    fn create_minimap(
18673        &self,
18674        minimap_settings: MinimapSettings,
18675        window: &mut Window,
18676        cx: &mut Context<Self>,
18677    ) -> Option<Entity<Self>> {
18678        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18679            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18680    }
18681
18682    fn initialize_new_minimap(
18683        &self,
18684        minimap_settings: MinimapSettings,
18685        window: &mut Window,
18686        cx: &mut Context<Self>,
18687    ) -> Entity<Self> {
18688        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18689
18690        let mut minimap = Editor::new_internal(
18691            EditorMode::Minimap {
18692                parent: cx.weak_entity(),
18693            },
18694            self.buffer.clone(),
18695            None,
18696            Some(self.display_map.clone()),
18697            window,
18698            cx,
18699        );
18700        minimap.scroll_manager.clone_state(&self.scroll_manager);
18701        minimap.set_text_style_refinement(TextStyleRefinement {
18702            font_size: Some(MINIMAP_FONT_SIZE),
18703            font_weight: Some(MINIMAP_FONT_WEIGHT),
18704            ..Default::default()
18705        });
18706        minimap.update_minimap_configuration(minimap_settings, cx);
18707        cx.new(|_| minimap)
18708    }
18709
18710    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18711        let current_line_highlight = minimap_settings
18712            .current_line_highlight
18713            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18714        self.set_current_line_highlight(Some(current_line_highlight));
18715    }
18716
18717    pub fn minimap(&self) -> Option<&Entity<Self>> {
18718        self.minimap
18719            .as_ref()
18720            .filter(|_| self.minimap_visibility.visible())
18721    }
18722
18723    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18724        let mut wrap_guides = smallvec![];
18725
18726        if self.show_wrap_guides == Some(false) {
18727            return wrap_guides;
18728        }
18729
18730        let settings = self.buffer.read(cx).language_settings(cx);
18731        if settings.show_wrap_guides {
18732            match self.soft_wrap_mode(cx) {
18733                SoftWrap::Column(soft_wrap) => {
18734                    wrap_guides.push((soft_wrap as usize, true));
18735                }
18736                SoftWrap::Bounded(soft_wrap) => {
18737                    wrap_guides.push((soft_wrap as usize, true));
18738                }
18739                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18740            }
18741            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18742        }
18743
18744        wrap_guides
18745    }
18746
18747    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18748        let settings = self.buffer.read(cx).language_settings(cx);
18749        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18750        match mode {
18751            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18752                SoftWrap::None
18753            }
18754            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18755            language_settings::SoftWrap::PreferredLineLength => {
18756                SoftWrap::Column(settings.preferred_line_length)
18757            }
18758            language_settings::SoftWrap::Bounded => {
18759                SoftWrap::Bounded(settings.preferred_line_length)
18760            }
18761        }
18762    }
18763
18764    pub fn set_soft_wrap_mode(
18765        &mut self,
18766        mode: language_settings::SoftWrap,
18767
18768        cx: &mut Context<Self>,
18769    ) {
18770        self.soft_wrap_mode_override = Some(mode);
18771        cx.notify();
18772    }
18773
18774    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18775        self.hard_wrap = hard_wrap;
18776        cx.notify();
18777    }
18778
18779    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18780        self.text_style_refinement = Some(style);
18781    }
18782
18783    /// called by the Element so we know what style we were most recently rendered with.
18784    pub(crate) fn set_style(
18785        &mut self,
18786        style: EditorStyle,
18787        window: &mut Window,
18788        cx: &mut Context<Self>,
18789    ) {
18790        // We intentionally do not inform the display map about the minimap style
18791        // so that wrapping is not recalculated and stays consistent for the editor
18792        // and its linked minimap.
18793        if !self.mode.is_minimap() {
18794            let rem_size = window.rem_size();
18795            self.display_map.update(cx, |map, cx| {
18796                map.set_font(
18797                    style.text.font(),
18798                    style.text.font_size.to_pixels(rem_size),
18799                    cx,
18800                )
18801            });
18802        }
18803        self.style = Some(style);
18804    }
18805
18806    pub fn style(&self) -> Option<&EditorStyle> {
18807        self.style.as_ref()
18808    }
18809
18810    // Called by the element. This method is not designed to be called outside of the editor
18811    // element's layout code because it does not notify when rewrapping is computed synchronously.
18812    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18813        self.display_map
18814            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18815    }
18816
18817    pub fn set_soft_wrap(&mut self) {
18818        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18819    }
18820
18821    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18822        if self.soft_wrap_mode_override.is_some() {
18823            self.soft_wrap_mode_override.take();
18824        } else {
18825            let soft_wrap = match self.soft_wrap_mode(cx) {
18826                SoftWrap::GitDiff => return,
18827                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18828                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18829                    language_settings::SoftWrap::None
18830                }
18831            };
18832            self.soft_wrap_mode_override = Some(soft_wrap);
18833        }
18834        cx.notify();
18835    }
18836
18837    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18838        let Some(workspace) = self.workspace() else {
18839            return;
18840        };
18841        let fs = workspace.read(cx).app_state().fs.clone();
18842        let current_show = TabBarSettings::get_global(cx).show;
18843        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18844            setting.show = Some(!current_show);
18845        });
18846    }
18847
18848    pub fn toggle_indent_guides(
18849        &mut self,
18850        _: &ToggleIndentGuides,
18851        _: &mut Window,
18852        cx: &mut Context<Self>,
18853    ) {
18854        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18855            self.buffer
18856                .read(cx)
18857                .language_settings(cx)
18858                .indent_guides
18859                .enabled
18860        });
18861        self.show_indent_guides = Some(!currently_enabled);
18862        cx.notify();
18863    }
18864
18865    fn should_show_indent_guides(&self) -> Option<bool> {
18866        self.show_indent_guides
18867    }
18868
18869    pub fn toggle_line_numbers(
18870        &mut self,
18871        _: &ToggleLineNumbers,
18872        _: &mut Window,
18873        cx: &mut Context<Self>,
18874    ) {
18875        let mut editor_settings = EditorSettings::get_global(cx).clone();
18876        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18877        EditorSettings::override_global(editor_settings, cx);
18878    }
18879
18880    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18881        if let Some(show_line_numbers) = self.show_line_numbers {
18882            return show_line_numbers;
18883        }
18884        EditorSettings::get_global(cx).gutter.line_numbers
18885    }
18886
18887    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18888        self.use_relative_line_numbers
18889            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18890    }
18891
18892    pub fn toggle_relative_line_numbers(
18893        &mut self,
18894        _: &ToggleRelativeLineNumbers,
18895        _: &mut Window,
18896        cx: &mut Context<Self>,
18897    ) {
18898        let is_relative = self.should_use_relative_line_numbers(cx);
18899        self.set_relative_line_number(Some(!is_relative), cx)
18900    }
18901
18902    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18903        self.use_relative_line_numbers = is_relative;
18904        cx.notify();
18905    }
18906
18907    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18908        self.show_gutter = show_gutter;
18909        cx.notify();
18910    }
18911
18912    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18913        self.show_scrollbars = ScrollbarAxes {
18914            horizontal: show,
18915            vertical: show,
18916        };
18917        cx.notify();
18918    }
18919
18920    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18921        self.show_scrollbars.vertical = show;
18922        cx.notify();
18923    }
18924
18925    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18926        self.show_scrollbars.horizontal = show;
18927        cx.notify();
18928    }
18929
18930    pub fn set_minimap_visibility(
18931        &mut self,
18932        minimap_visibility: MinimapVisibility,
18933        window: &mut Window,
18934        cx: &mut Context<Self>,
18935    ) {
18936        if self.minimap_visibility != minimap_visibility {
18937            if minimap_visibility.visible() && self.minimap.is_none() {
18938                let minimap_settings = EditorSettings::get_global(cx).minimap;
18939                self.minimap =
18940                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18941            }
18942            self.minimap_visibility = minimap_visibility;
18943            cx.notify();
18944        }
18945    }
18946
18947    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18948        self.set_show_scrollbars(false, cx);
18949        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18950    }
18951
18952    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18953        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18954    }
18955
18956    /// Normally the text in full mode and auto height editors is padded on the
18957    /// left side by roughly half a character width for improved hit testing.
18958    ///
18959    /// Use this method to disable this for cases where this is not wanted (e.g.
18960    /// if you want to align the editor text with some other text above or below)
18961    /// or if you want to add this padding to single-line editors.
18962    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18963        self.offset_content = offset_content;
18964        cx.notify();
18965    }
18966
18967    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18968        self.show_line_numbers = Some(show_line_numbers);
18969        cx.notify();
18970    }
18971
18972    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18973        self.disable_expand_excerpt_buttons = true;
18974        cx.notify();
18975    }
18976
18977    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18978        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18979        cx.notify();
18980    }
18981
18982    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18983        self.show_code_actions = Some(show_code_actions);
18984        cx.notify();
18985    }
18986
18987    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18988        self.show_runnables = Some(show_runnables);
18989        cx.notify();
18990    }
18991
18992    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18993        self.show_breakpoints = Some(show_breakpoints);
18994        cx.notify();
18995    }
18996
18997    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18998        if self.display_map.read(cx).masked != masked {
18999            self.display_map.update(cx, |map, _| map.masked = masked);
19000        }
19001        cx.notify()
19002    }
19003
19004    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19005        self.show_wrap_guides = Some(show_wrap_guides);
19006        cx.notify();
19007    }
19008
19009    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19010        self.show_indent_guides = Some(show_indent_guides);
19011        cx.notify();
19012    }
19013
19014    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19015        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19016            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19017                && let Some(dir) = file.abs_path(cx).parent()
19018            {
19019                return Some(dir.to_owned());
19020            }
19021
19022            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19023                return Some(project_path.path.to_path_buf());
19024            }
19025        }
19026
19027        None
19028    }
19029
19030    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19031        self.active_excerpt(cx)?
19032            .1
19033            .read(cx)
19034            .file()
19035            .and_then(|f| f.as_local())
19036    }
19037
19038    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19039        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19040            let buffer = buffer.read(cx);
19041            if let Some(project_path) = buffer.project_path(cx) {
19042                let project = self.project()?.read(cx);
19043                project.absolute_path(&project_path, cx)
19044            } else {
19045                buffer
19046                    .file()
19047                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19048            }
19049        })
19050    }
19051
19052    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19053        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19054            let project_path = buffer.read(cx).project_path(cx)?;
19055            let project = self.project()?.read(cx);
19056            let entry = project.entry_for_path(&project_path, cx)?;
19057            let path = entry.path.to_path_buf();
19058            Some(path)
19059        })
19060    }
19061
19062    pub fn reveal_in_finder(
19063        &mut self,
19064        _: &RevealInFileManager,
19065        _window: &mut Window,
19066        cx: &mut Context<Self>,
19067    ) {
19068        if let Some(target) = self.target_file(cx) {
19069            cx.reveal_path(&target.abs_path(cx));
19070        }
19071    }
19072
19073    pub fn copy_path(
19074        &mut self,
19075        _: &zed_actions::workspace::CopyPath,
19076        _window: &mut Window,
19077        cx: &mut Context<Self>,
19078    ) {
19079        if let Some(path) = self.target_file_abs_path(cx)
19080            && let Some(path) = path.to_str()
19081        {
19082            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19083        }
19084    }
19085
19086    pub fn copy_relative_path(
19087        &mut self,
19088        _: &zed_actions::workspace::CopyRelativePath,
19089        _window: &mut Window,
19090        cx: &mut Context<Self>,
19091    ) {
19092        if let Some(path) = self.target_file_path(cx)
19093            && let Some(path) = path.to_str()
19094        {
19095            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19096        }
19097    }
19098
19099    /// Returns the project path for the editor's buffer, if any buffer is
19100    /// opened in the editor.
19101    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19102        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19103            buffer.read(cx).project_path(cx)
19104        } else {
19105            None
19106        }
19107    }
19108
19109    // Returns true if the editor handled a go-to-line request
19110    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19111        maybe!({
19112            let breakpoint_store = self.breakpoint_store.as_ref()?;
19113
19114            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19115            else {
19116                self.clear_row_highlights::<ActiveDebugLine>();
19117                return None;
19118            };
19119
19120            let position = active_stack_frame.position;
19121            let buffer_id = position.buffer_id?;
19122            let snapshot = self
19123                .project
19124                .as_ref()?
19125                .read(cx)
19126                .buffer_for_id(buffer_id, cx)?
19127                .read(cx)
19128                .snapshot();
19129
19130            let mut handled = false;
19131            for (id, ExcerptRange { context, .. }) in
19132                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19133            {
19134                if context.start.cmp(&position, &snapshot).is_ge()
19135                    || context.end.cmp(&position, &snapshot).is_lt()
19136                {
19137                    continue;
19138                }
19139                let snapshot = self.buffer.read(cx).snapshot(cx);
19140                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19141
19142                handled = true;
19143                self.clear_row_highlights::<ActiveDebugLine>();
19144
19145                self.go_to_line::<ActiveDebugLine>(
19146                    multibuffer_anchor,
19147                    Some(cx.theme().colors().editor_debugger_active_line_background),
19148                    window,
19149                    cx,
19150                );
19151
19152                cx.notify();
19153            }
19154
19155            handled.then_some(())
19156        })
19157        .is_some()
19158    }
19159
19160    pub fn copy_file_name_without_extension(
19161        &mut self,
19162        _: &CopyFileNameWithoutExtension,
19163        _: &mut Window,
19164        cx: &mut Context<Self>,
19165    ) {
19166        if let Some(file) = self.target_file(cx)
19167            && let Some(file_stem) = file.path().file_stem()
19168            && let Some(name) = file_stem.to_str()
19169        {
19170            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19171        }
19172    }
19173
19174    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19175        if let Some(file) = self.target_file(cx)
19176            && let Some(file_name) = file.path().file_name()
19177            && let Some(name) = file_name.to_str()
19178        {
19179            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19180        }
19181    }
19182
19183    pub fn toggle_git_blame(
19184        &mut self,
19185        _: &::git::Blame,
19186        window: &mut Window,
19187        cx: &mut Context<Self>,
19188    ) {
19189        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19190
19191        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19192            self.start_git_blame(true, window, cx);
19193        }
19194
19195        cx.notify();
19196    }
19197
19198    pub fn toggle_git_blame_inline(
19199        &mut self,
19200        _: &ToggleGitBlameInline,
19201        window: &mut Window,
19202        cx: &mut Context<Self>,
19203    ) {
19204        self.toggle_git_blame_inline_internal(true, window, cx);
19205        cx.notify();
19206    }
19207
19208    pub fn open_git_blame_commit(
19209        &mut self,
19210        _: &OpenGitBlameCommit,
19211        window: &mut Window,
19212        cx: &mut Context<Self>,
19213    ) {
19214        self.open_git_blame_commit_internal(window, cx);
19215    }
19216
19217    fn open_git_blame_commit_internal(
19218        &mut self,
19219        window: &mut Window,
19220        cx: &mut Context<Self>,
19221    ) -> Option<()> {
19222        let blame = self.blame.as_ref()?;
19223        let snapshot = self.snapshot(window, cx);
19224        let cursor = self.selections.newest::<Point>(cx).head();
19225        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19226        let (_, blame_entry) = blame
19227            .update(cx, |blame, cx| {
19228                blame
19229                    .blame_for_rows(
19230                        &[RowInfo {
19231                            buffer_id: Some(buffer.remote_id()),
19232                            buffer_row: Some(point.row),
19233                            ..Default::default()
19234                        }],
19235                        cx,
19236                    )
19237                    .next()
19238            })
19239            .flatten()?;
19240        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19241        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19242        let workspace = self.workspace()?.downgrade();
19243        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19244        None
19245    }
19246
19247    pub fn git_blame_inline_enabled(&self) -> bool {
19248        self.git_blame_inline_enabled
19249    }
19250
19251    pub fn toggle_selection_menu(
19252        &mut self,
19253        _: &ToggleSelectionMenu,
19254        _: &mut Window,
19255        cx: &mut Context<Self>,
19256    ) {
19257        self.show_selection_menu = self
19258            .show_selection_menu
19259            .map(|show_selections_menu| !show_selections_menu)
19260            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19261
19262        cx.notify();
19263    }
19264
19265    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19266        self.show_selection_menu
19267            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19268    }
19269
19270    fn start_git_blame(
19271        &mut self,
19272        user_triggered: bool,
19273        window: &mut Window,
19274        cx: &mut Context<Self>,
19275    ) {
19276        if let Some(project) = self.project() {
19277            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19278                && buffer.read(cx).file().is_none()
19279            {
19280                return;
19281            }
19282
19283            let focused = self.focus_handle(cx).contains_focused(window, cx);
19284
19285            let project = project.clone();
19286            let blame = cx
19287                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19288            self.blame_subscription =
19289                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19290            self.blame = Some(blame);
19291        }
19292    }
19293
19294    fn toggle_git_blame_inline_internal(
19295        &mut self,
19296        user_triggered: bool,
19297        window: &mut Window,
19298        cx: &mut Context<Self>,
19299    ) {
19300        if self.git_blame_inline_enabled {
19301            self.git_blame_inline_enabled = false;
19302            self.show_git_blame_inline = false;
19303            self.show_git_blame_inline_delay_task.take();
19304        } else {
19305            self.git_blame_inline_enabled = true;
19306            self.start_git_blame_inline(user_triggered, window, cx);
19307        }
19308
19309        cx.notify();
19310    }
19311
19312    fn start_git_blame_inline(
19313        &mut self,
19314        user_triggered: bool,
19315        window: &mut Window,
19316        cx: &mut Context<Self>,
19317    ) {
19318        self.start_git_blame(user_triggered, window, cx);
19319
19320        if ProjectSettings::get_global(cx)
19321            .git
19322            .inline_blame_delay()
19323            .is_some()
19324        {
19325            self.start_inline_blame_timer(window, cx);
19326        } else {
19327            self.show_git_blame_inline = true
19328        }
19329    }
19330
19331    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19332        self.blame.as_ref()
19333    }
19334
19335    pub fn show_git_blame_gutter(&self) -> bool {
19336        self.show_git_blame_gutter
19337    }
19338
19339    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19340        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19341    }
19342
19343    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19344        self.show_git_blame_inline
19345            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19346            && !self.newest_selection_head_on_empty_line(cx)
19347            && self.has_blame_entries(cx)
19348    }
19349
19350    fn has_blame_entries(&self, cx: &App) -> bool {
19351        self.blame()
19352            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19353    }
19354
19355    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19356        let cursor_anchor = self.selections.newest_anchor().head();
19357
19358        let snapshot = self.buffer.read(cx).snapshot(cx);
19359        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19360
19361        snapshot.line_len(buffer_row) == 0
19362    }
19363
19364    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19365        let buffer_and_selection = maybe!({
19366            let selection = self.selections.newest::<Point>(cx);
19367            let selection_range = selection.range();
19368
19369            let multi_buffer = self.buffer().read(cx);
19370            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19371            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19372
19373            let (buffer, range, _) = if selection.reversed {
19374                buffer_ranges.first()
19375            } else {
19376                buffer_ranges.last()
19377            }?;
19378
19379            let selection = text::ToPoint::to_point(&range.start, buffer).row
19380                ..text::ToPoint::to_point(&range.end, buffer).row;
19381            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19382        });
19383
19384        let Some((buffer, selection)) = buffer_and_selection else {
19385            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19386        };
19387
19388        let Some(project) = self.project() else {
19389            return Task::ready(Err(anyhow!("editor does not have project")));
19390        };
19391
19392        project.update(cx, |project, cx| {
19393            project.get_permalink_to_line(&buffer, selection, cx)
19394        })
19395    }
19396
19397    pub fn copy_permalink_to_line(
19398        &mut self,
19399        _: &CopyPermalinkToLine,
19400        window: &mut Window,
19401        cx: &mut Context<Self>,
19402    ) {
19403        let permalink_task = self.get_permalink_to_line(cx);
19404        let workspace = self.workspace();
19405
19406        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19407            Ok(permalink) => {
19408                cx.update(|_, cx| {
19409                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19410                })
19411                .ok();
19412            }
19413            Err(err) => {
19414                let message = format!("Failed to copy permalink: {err}");
19415
19416                anyhow::Result::<()>::Err(err).log_err();
19417
19418                if let Some(workspace) = workspace {
19419                    workspace
19420                        .update_in(cx, |workspace, _, cx| {
19421                            struct CopyPermalinkToLine;
19422
19423                            workspace.show_toast(
19424                                Toast::new(
19425                                    NotificationId::unique::<CopyPermalinkToLine>(),
19426                                    message,
19427                                ),
19428                                cx,
19429                            )
19430                        })
19431                        .ok();
19432                }
19433            }
19434        })
19435        .detach();
19436    }
19437
19438    pub fn copy_file_location(
19439        &mut self,
19440        _: &CopyFileLocation,
19441        _: &mut Window,
19442        cx: &mut Context<Self>,
19443    ) {
19444        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19445        if let Some(file) = self.target_file(cx)
19446            && let Some(path) = file.path().to_str()
19447        {
19448            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19449        }
19450    }
19451
19452    pub fn open_permalink_to_line(
19453        &mut self,
19454        _: &OpenPermalinkToLine,
19455        window: &mut Window,
19456        cx: &mut Context<Self>,
19457    ) {
19458        let permalink_task = self.get_permalink_to_line(cx);
19459        let workspace = self.workspace();
19460
19461        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19462            Ok(permalink) => {
19463                cx.update(|_, cx| {
19464                    cx.open_url(permalink.as_ref());
19465                })
19466                .ok();
19467            }
19468            Err(err) => {
19469                let message = format!("Failed to open permalink: {err}");
19470
19471                anyhow::Result::<()>::Err(err).log_err();
19472
19473                if let Some(workspace) = workspace {
19474                    workspace
19475                        .update(cx, |workspace, cx| {
19476                            struct OpenPermalinkToLine;
19477
19478                            workspace.show_toast(
19479                                Toast::new(
19480                                    NotificationId::unique::<OpenPermalinkToLine>(),
19481                                    message,
19482                                ),
19483                                cx,
19484                            )
19485                        })
19486                        .ok();
19487                }
19488            }
19489        })
19490        .detach();
19491    }
19492
19493    pub fn insert_uuid_v4(
19494        &mut self,
19495        _: &InsertUuidV4,
19496        window: &mut Window,
19497        cx: &mut Context<Self>,
19498    ) {
19499        self.insert_uuid(UuidVersion::V4, window, cx);
19500    }
19501
19502    pub fn insert_uuid_v7(
19503        &mut self,
19504        _: &InsertUuidV7,
19505        window: &mut Window,
19506        cx: &mut Context<Self>,
19507    ) {
19508        self.insert_uuid(UuidVersion::V7, window, cx);
19509    }
19510
19511    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19512        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19513        self.transact(window, cx, |this, window, cx| {
19514            let edits = this
19515                .selections
19516                .all::<Point>(cx)
19517                .into_iter()
19518                .map(|selection| {
19519                    let uuid = match version {
19520                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19521                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19522                    };
19523
19524                    (selection.range(), uuid.to_string())
19525                });
19526            this.edit(edits, cx);
19527            this.refresh_edit_prediction(true, false, window, cx);
19528        });
19529    }
19530
19531    pub fn open_selections_in_multibuffer(
19532        &mut self,
19533        _: &OpenSelectionsInMultibuffer,
19534        window: &mut Window,
19535        cx: &mut Context<Self>,
19536    ) {
19537        let multibuffer = self.buffer.read(cx);
19538
19539        let Some(buffer) = multibuffer.as_singleton() else {
19540            return;
19541        };
19542
19543        let Some(workspace) = self.workspace() else {
19544            return;
19545        };
19546
19547        let title = multibuffer.title(cx).to_string();
19548
19549        let locations = self
19550            .selections
19551            .all_anchors(cx)
19552            .iter()
19553            .map(|selection| Location {
19554                buffer: buffer.clone(),
19555                range: selection.start.text_anchor..selection.end.text_anchor,
19556            })
19557            .collect::<Vec<_>>();
19558
19559        cx.spawn_in(window, async move |_, cx| {
19560            workspace.update_in(cx, |workspace, window, cx| {
19561                Self::open_locations_in_multibuffer(
19562                    workspace,
19563                    locations,
19564                    format!("Selections for '{title}'"),
19565                    false,
19566                    MultibufferSelectionMode::All,
19567                    window,
19568                    cx,
19569                );
19570            })
19571        })
19572        .detach();
19573    }
19574
19575    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19576    /// last highlight added will be used.
19577    ///
19578    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19579    pub fn highlight_rows<T: 'static>(
19580        &mut self,
19581        range: Range<Anchor>,
19582        color: Hsla,
19583        options: RowHighlightOptions,
19584        cx: &mut Context<Self>,
19585    ) {
19586        let snapshot = self.buffer().read(cx).snapshot(cx);
19587        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19588        let ix = row_highlights.binary_search_by(|highlight| {
19589            Ordering::Equal
19590                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19591                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19592        });
19593
19594        if let Err(mut ix) = ix {
19595            let index = post_inc(&mut self.highlight_order);
19596
19597            // If this range intersects with the preceding highlight, then merge it with
19598            // the preceding highlight. Otherwise insert a new highlight.
19599            let mut merged = false;
19600            if ix > 0 {
19601                let prev_highlight = &mut row_highlights[ix - 1];
19602                if prev_highlight
19603                    .range
19604                    .end
19605                    .cmp(&range.start, &snapshot)
19606                    .is_ge()
19607                {
19608                    ix -= 1;
19609                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19610                        prev_highlight.range.end = range.end;
19611                    }
19612                    merged = true;
19613                    prev_highlight.index = index;
19614                    prev_highlight.color = color;
19615                    prev_highlight.options = options;
19616                }
19617            }
19618
19619            if !merged {
19620                row_highlights.insert(
19621                    ix,
19622                    RowHighlight {
19623                        range,
19624                        index,
19625                        color,
19626                        options,
19627                        type_id: TypeId::of::<T>(),
19628                    },
19629                );
19630            }
19631
19632            // If any of the following highlights intersect with this one, merge them.
19633            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19634                let highlight = &row_highlights[ix];
19635                if next_highlight
19636                    .range
19637                    .start
19638                    .cmp(&highlight.range.end, &snapshot)
19639                    .is_le()
19640                {
19641                    if next_highlight
19642                        .range
19643                        .end
19644                        .cmp(&highlight.range.end, &snapshot)
19645                        .is_gt()
19646                    {
19647                        row_highlights[ix].range.end = next_highlight.range.end;
19648                    }
19649                    row_highlights.remove(ix + 1);
19650                } else {
19651                    break;
19652                }
19653            }
19654        }
19655    }
19656
19657    /// Remove any highlighted row ranges of the given type that intersect the
19658    /// given ranges.
19659    pub fn remove_highlighted_rows<T: 'static>(
19660        &mut self,
19661        ranges_to_remove: Vec<Range<Anchor>>,
19662        cx: &mut Context<Self>,
19663    ) {
19664        let snapshot = self.buffer().read(cx).snapshot(cx);
19665        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19666        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19667        row_highlights.retain(|highlight| {
19668            while let Some(range_to_remove) = ranges_to_remove.peek() {
19669                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19670                    Ordering::Less | Ordering::Equal => {
19671                        ranges_to_remove.next();
19672                    }
19673                    Ordering::Greater => {
19674                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19675                            Ordering::Less | Ordering::Equal => {
19676                                return false;
19677                            }
19678                            Ordering::Greater => break,
19679                        }
19680                    }
19681                }
19682            }
19683
19684            true
19685        })
19686    }
19687
19688    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19689    pub fn clear_row_highlights<T: 'static>(&mut self) {
19690        self.highlighted_rows.remove(&TypeId::of::<T>());
19691    }
19692
19693    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19694    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19695        self.highlighted_rows
19696            .get(&TypeId::of::<T>())
19697            .map_or(&[] as &[_], |vec| vec.as_slice())
19698            .iter()
19699            .map(|highlight| (highlight.range.clone(), highlight.color))
19700    }
19701
19702    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19703    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19704    /// Allows to ignore certain kinds of highlights.
19705    pub fn highlighted_display_rows(
19706        &self,
19707        window: &mut Window,
19708        cx: &mut App,
19709    ) -> BTreeMap<DisplayRow, LineHighlight> {
19710        let snapshot = self.snapshot(window, cx);
19711        let mut used_highlight_orders = HashMap::default();
19712        self.highlighted_rows
19713            .iter()
19714            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19715            .fold(
19716                BTreeMap::<DisplayRow, LineHighlight>::new(),
19717                |mut unique_rows, highlight| {
19718                    let start = highlight.range.start.to_display_point(&snapshot);
19719                    let end = highlight.range.end.to_display_point(&snapshot);
19720                    let start_row = start.row().0;
19721                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19722                        && end.column() == 0
19723                    {
19724                        end.row().0.saturating_sub(1)
19725                    } else {
19726                        end.row().0
19727                    };
19728                    for row in start_row..=end_row {
19729                        let used_index =
19730                            used_highlight_orders.entry(row).or_insert(highlight.index);
19731                        if highlight.index >= *used_index {
19732                            *used_index = highlight.index;
19733                            unique_rows.insert(
19734                                DisplayRow(row),
19735                                LineHighlight {
19736                                    include_gutter: highlight.options.include_gutter,
19737                                    border: None,
19738                                    background: highlight.color.into(),
19739                                    type_id: Some(highlight.type_id),
19740                                },
19741                            );
19742                        }
19743                    }
19744                    unique_rows
19745                },
19746            )
19747    }
19748
19749    pub fn highlighted_display_row_for_autoscroll(
19750        &self,
19751        snapshot: &DisplaySnapshot,
19752    ) -> Option<DisplayRow> {
19753        self.highlighted_rows
19754            .values()
19755            .flat_map(|highlighted_rows| highlighted_rows.iter())
19756            .filter_map(|highlight| {
19757                if highlight.options.autoscroll {
19758                    Some(highlight.range.start.to_display_point(snapshot).row())
19759                } else {
19760                    None
19761                }
19762            })
19763            .min()
19764    }
19765
19766    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19767        self.highlight_background::<SearchWithinRange>(
19768            ranges,
19769            |colors| colors.colors().editor_document_highlight_read_background,
19770            cx,
19771        )
19772    }
19773
19774    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19775        self.breadcrumb_header = Some(new_header);
19776    }
19777
19778    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19779        self.clear_background_highlights::<SearchWithinRange>(cx);
19780    }
19781
19782    pub fn highlight_background<T: 'static>(
19783        &mut self,
19784        ranges: &[Range<Anchor>],
19785        color_fetcher: fn(&Theme) -> Hsla,
19786        cx: &mut Context<Self>,
19787    ) {
19788        self.background_highlights.insert(
19789            HighlightKey::Type(TypeId::of::<T>()),
19790            (color_fetcher, Arc::from(ranges)),
19791        );
19792        self.scrollbar_marker_state.dirty = true;
19793        cx.notify();
19794    }
19795
19796    pub fn highlight_background_key<T: 'static>(
19797        &mut self,
19798        key: usize,
19799        ranges: &[Range<Anchor>],
19800        color_fetcher: fn(&Theme) -> Hsla,
19801        cx: &mut Context<Self>,
19802    ) {
19803        self.background_highlights.insert(
19804            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19805            (color_fetcher, Arc::from(ranges)),
19806        );
19807        self.scrollbar_marker_state.dirty = true;
19808        cx.notify();
19809    }
19810
19811    pub fn clear_background_highlights<T: 'static>(
19812        &mut self,
19813        cx: &mut Context<Self>,
19814    ) -> Option<BackgroundHighlight> {
19815        let text_highlights = self
19816            .background_highlights
19817            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19818        if !text_highlights.1.is_empty() {
19819            self.scrollbar_marker_state.dirty = true;
19820            cx.notify();
19821        }
19822        Some(text_highlights)
19823    }
19824
19825    pub fn highlight_gutter<T: 'static>(
19826        &mut self,
19827        ranges: impl Into<Vec<Range<Anchor>>>,
19828        color_fetcher: fn(&App) -> Hsla,
19829        cx: &mut Context<Self>,
19830    ) {
19831        self.gutter_highlights
19832            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19833        cx.notify();
19834    }
19835
19836    pub fn clear_gutter_highlights<T: 'static>(
19837        &mut self,
19838        cx: &mut Context<Self>,
19839    ) -> Option<GutterHighlight> {
19840        cx.notify();
19841        self.gutter_highlights.remove(&TypeId::of::<T>())
19842    }
19843
19844    pub fn insert_gutter_highlight<T: 'static>(
19845        &mut self,
19846        range: Range<Anchor>,
19847        color_fetcher: fn(&App) -> Hsla,
19848        cx: &mut Context<Self>,
19849    ) {
19850        let snapshot = self.buffer().read(cx).snapshot(cx);
19851        let mut highlights = self
19852            .gutter_highlights
19853            .remove(&TypeId::of::<T>())
19854            .map(|(_, highlights)| highlights)
19855            .unwrap_or_default();
19856        let ix = highlights.binary_search_by(|highlight| {
19857            Ordering::Equal
19858                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19859                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19860        });
19861        if let Err(ix) = ix {
19862            highlights.insert(ix, range);
19863        }
19864        self.gutter_highlights
19865            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19866    }
19867
19868    pub fn remove_gutter_highlights<T: 'static>(
19869        &mut self,
19870        ranges_to_remove: Vec<Range<Anchor>>,
19871        cx: &mut Context<Self>,
19872    ) {
19873        let snapshot = self.buffer().read(cx).snapshot(cx);
19874        let Some((color_fetcher, mut gutter_highlights)) =
19875            self.gutter_highlights.remove(&TypeId::of::<T>())
19876        else {
19877            return;
19878        };
19879        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19880        gutter_highlights.retain(|highlight| {
19881            while let Some(range_to_remove) = ranges_to_remove.peek() {
19882                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19883                    Ordering::Less | Ordering::Equal => {
19884                        ranges_to_remove.next();
19885                    }
19886                    Ordering::Greater => {
19887                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19888                            Ordering::Less | Ordering::Equal => {
19889                                return false;
19890                            }
19891                            Ordering::Greater => break,
19892                        }
19893                    }
19894                }
19895            }
19896
19897            true
19898        });
19899        self.gutter_highlights
19900            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19901    }
19902
19903    #[cfg(feature = "test-support")]
19904    pub fn all_text_highlights(
19905        &self,
19906        window: &mut Window,
19907        cx: &mut Context<Self>,
19908    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19909        let snapshot = self.snapshot(window, cx);
19910        self.display_map.update(cx, |display_map, _| {
19911            display_map
19912                .all_text_highlights()
19913                .map(|highlight| {
19914                    let (style, ranges) = highlight.as_ref();
19915                    (
19916                        *style,
19917                        ranges
19918                            .iter()
19919                            .map(|range| range.clone().to_display_points(&snapshot))
19920                            .collect(),
19921                    )
19922                })
19923                .collect()
19924        })
19925    }
19926
19927    #[cfg(feature = "test-support")]
19928    pub fn all_text_background_highlights(
19929        &self,
19930        window: &mut Window,
19931        cx: &mut Context<Self>,
19932    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19933        let snapshot = self.snapshot(window, cx);
19934        let buffer = &snapshot.buffer_snapshot;
19935        let start = buffer.anchor_before(0);
19936        let end = buffer.anchor_after(buffer.len());
19937        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
19938    }
19939
19940    #[cfg(any(test, feature = "test-support"))]
19941    pub fn sorted_background_highlights_in_range(
19942        &self,
19943        search_range: Range<Anchor>,
19944        display_snapshot: &DisplaySnapshot,
19945        theme: &Theme,
19946    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19947        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
19948        res.sort_by(|a, b| {
19949            a.0.start
19950                .cmp(&b.0.start)
19951                .then_with(|| a.0.end.cmp(&b.0.end))
19952                .then_with(|| a.1.cmp(&b.1))
19953        });
19954        res
19955    }
19956
19957    #[cfg(feature = "test-support")]
19958    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19959        let snapshot = self.buffer().read(cx).snapshot(cx);
19960
19961        let highlights = self
19962            .background_highlights
19963            .get(&HighlightKey::Type(TypeId::of::<
19964                items::BufferSearchHighlights,
19965            >()));
19966
19967        if let Some((_color, ranges)) = highlights {
19968            ranges
19969                .iter()
19970                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19971                .collect_vec()
19972        } else {
19973            vec![]
19974        }
19975    }
19976
19977    fn document_highlights_for_position<'a>(
19978        &'a self,
19979        position: Anchor,
19980        buffer: &'a MultiBufferSnapshot,
19981    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19982        let read_highlights = self
19983            .background_highlights
19984            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19985            .map(|h| &h.1);
19986        let write_highlights = self
19987            .background_highlights
19988            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19989            .map(|h| &h.1);
19990        let left_position = position.bias_left(buffer);
19991        let right_position = position.bias_right(buffer);
19992        read_highlights
19993            .into_iter()
19994            .chain(write_highlights)
19995            .flat_map(move |ranges| {
19996                let start_ix = match ranges.binary_search_by(|probe| {
19997                    let cmp = probe.end.cmp(&left_position, buffer);
19998                    if cmp.is_ge() {
19999                        Ordering::Greater
20000                    } else {
20001                        Ordering::Less
20002                    }
20003                }) {
20004                    Ok(i) | Err(i) => i,
20005                };
20006
20007                ranges[start_ix..]
20008                    .iter()
20009                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20010            })
20011    }
20012
20013    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20014        self.background_highlights
20015            .get(&HighlightKey::Type(TypeId::of::<T>()))
20016            .is_some_and(|(_, highlights)| !highlights.is_empty())
20017    }
20018
20019    /// Returns all background highlights for a given range.
20020    ///
20021    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20022    pub fn background_highlights_in_range(
20023        &self,
20024        search_range: Range<Anchor>,
20025        display_snapshot: &DisplaySnapshot,
20026        theme: &Theme,
20027    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20028        let mut results = Vec::new();
20029        for (color_fetcher, ranges) in self.background_highlights.values() {
20030            let color = color_fetcher(theme);
20031            let start_ix = match ranges.binary_search_by(|probe| {
20032                let cmp = probe
20033                    .end
20034                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20035                if cmp.is_gt() {
20036                    Ordering::Greater
20037                } else {
20038                    Ordering::Less
20039                }
20040            }) {
20041                Ok(i) | Err(i) => i,
20042            };
20043            for range in &ranges[start_ix..] {
20044                if range
20045                    .start
20046                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20047                    .is_ge()
20048                {
20049                    break;
20050                }
20051
20052                let start = range.start.to_display_point(display_snapshot);
20053                let end = range.end.to_display_point(display_snapshot);
20054                results.push((start..end, color))
20055            }
20056        }
20057        results
20058    }
20059
20060    pub fn gutter_highlights_in_range(
20061        &self,
20062        search_range: Range<Anchor>,
20063        display_snapshot: &DisplaySnapshot,
20064        cx: &App,
20065    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20066        let mut results = Vec::new();
20067        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20068            let color = color_fetcher(cx);
20069            let start_ix = match ranges.binary_search_by(|probe| {
20070                let cmp = probe
20071                    .end
20072                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20073                if cmp.is_gt() {
20074                    Ordering::Greater
20075                } else {
20076                    Ordering::Less
20077                }
20078            }) {
20079                Ok(i) | Err(i) => i,
20080            };
20081            for range in &ranges[start_ix..] {
20082                if range
20083                    .start
20084                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20085                    .is_ge()
20086                {
20087                    break;
20088                }
20089
20090                let start = range.start.to_display_point(display_snapshot);
20091                let end = range.end.to_display_point(display_snapshot);
20092                results.push((start..end, color))
20093            }
20094        }
20095        results
20096    }
20097
20098    /// Get the text ranges corresponding to the redaction query
20099    pub fn redacted_ranges(
20100        &self,
20101        search_range: Range<Anchor>,
20102        display_snapshot: &DisplaySnapshot,
20103        cx: &App,
20104    ) -> Vec<Range<DisplayPoint>> {
20105        display_snapshot
20106            .buffer_snapshot
20107            .redacted_ranges(search_range, |file| {
20108                if let Some(file) = file {
20109                    file.is_private()
20110                        && EditorSettings::get(
20111                            Some(SettingsLocation {
20112                                worktree_id: file.worktree_id(cx),
20113                                path: file.path().as_ref(),
20114                            }),
20115                            cx,
20116                        )
20117                        .redact_private_values
20118                } else {
20119                    false
20120                }
20121            })
20122            .map(|range| {
20123                range.start.to_display_point(display_snapshot)
20124                    ..range.end.to_display_point(display_snapshot)
20125            })
20126            .collect()
20127    }
20128
20129    pub fn highlight_text_key<T: 'static>(
20130        &mut self,
20131        key: usize,
20132        ranges: Vec<Range<Anchor>>,
20133        style: HighlightStyle,
20134        cx: &mut Context<Self>,
20135    ) {
20136        self.display_map.update(cx, |map, _| {
20137            map.highlight_text(
20138                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20139                ranges,
20140                style,
20141            );
20142        });
20143        cx.notify();
20144    }
20145
20146    pub fn highlight_text<T: 'static>(
20147        &mut self,
20148        ranges: Vec<Range<Anchor>>,
20149        style: HighlightStyle,
20150        cx: &mut Context<Self>,
20151    ) {
20152        self.display_map.update(cx, |map, _| {
20153            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20154        });
20155        cx.notify();
20156    }
20157
20158    pub(crate) fn highlight_inlays<T: 'static>(
20159        &mut self,
20160        highlights: Vec<InlayHighlight>,
20161        style: HighlightStyle,
20162        cx: &mut Context<Self>,
20163    ) {
20164        self.display_map.update(cx, |map, _| {
20165            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20166        });
20167        cx.notify();
20168    }
20169
20170    pub fn text_highlights<'a, T: 'static>(
20171        &'a self,
20172        cx: &'a App,
20173    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20174        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20175    }
20176
20177    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20178        let cleared = self
20179            .display_map
20180            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20181        if cleared {
20182            cx.notify();
20183        }
20184    }
20185
20186    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20187        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20188            && self.focus_handle.is_focused(window)
20189    }
20190
20191    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20192        self.show_cursor_when_unfocused = is_enabled;
20193        cx.notify();
20194    }
20195
20196    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20197        cx.notify();
20198    }
20199
20200    fn on_debug_session_event(
20201        &mut self,
20202        _session: Entity<Session>,
20203        event: &SessionEvent,
20204        cx: &mut Context<Self>,
20205    ) {
20206        if let SessionEvent::InvalidateInlineValue = event {
20207            self.refresh_inline_values(cx);
20208        }
20209    }
20210
20211    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20212        let Some(project) = self.project.clone() else {
20213            return;
20214        };
20215
20216        if !self.inline_value_cache.enabled {
20217            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20218            self.splice_inlays(&inlays, Vec::new(), cx);
20219            return;
20220        }
20221
20222        let current_execution_position = self
20223            .highlighted_rows
20224            .get(&TypeId::of::<ActiveDebugLine>())
20225            .and_then(|lines| lines.last().map(|line| line.range.end));
20226
20227        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20228            let inline_values = editor
20229                .update(cx, |editor, cx| {
20230                    let Some(current_execution_position) = current_execution_position else {
20231                        return Some(Task::ready(Ok(Vec::new())));
20232                    };
20233
20234                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20235                        let snapshot = buffer.snapshot(cx);
20236
20237                        let excerpt = snapshot.excerpt_containing(
20238                            current_execution_position..current_execution_position,
20239                        )?;
20240
20241                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20242                    })?;
20243
20244                    let range =
20245                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20246
20247                    project.inline_values(buffer, range, cx)
20248                })
20249                .ok()
20250                .flatten()?
20251                .await
20252                .context("refreshing debugger inlays")
20253                .log_err()?;
20254
20255            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20256
20257            for (buffer_id, inline_value) in inline_values
20258                .into_iter()
20259                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20260            {
20261                buffer_inline_values
20262                    .entry(buffer_id)
20263                    .or_default()
20264                    .push(inline_value);
20265            }
20266
20267            editor
20268                .update(cx, |editor, cx| {
20269                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20270                    let mut new_inlays = Vec::default();
20271
20272                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20273                        let buffer_id = buffer_snapshot.remote_id();
20274                        buffer_inline_values
20275                            .get(&buffer_id)
20276                            .into_iter()
20277                            .flatten()
20278                            .for_each(|hint| {
20279                                let inlay = Inlay::debugger(
20280                                    post_inc(&mut editor.next_inlay_id),
20281                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20282                                    hint.text(),
20283                                );
20284                                if !inlay.text.chars().contains(&'\n') {
20285                                    new_inlays.push(inlay);
20286                                }
20287                            });
20288                    }
20289
20290                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20291                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20292
20293                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20294                })
20295                .ok()?;
20296            Some(())
20297        });
20298    }
20299
20300    fn on_buffer_event(
20301        &mut self,
20302        multibuffer: &Entity<MultiBuffer>,
20303        event: &multi_buffer::Event,
20304        window: &mut Window,
20305        cx: &mut Context<Self>,
20306    ) {
20307        match event {
20308            multi_buffer::Event::Edited {
20309                singleton_buffer_edited,
20310                edited_buffer,
20311            } => {
20312                self.scrollbar_marker_state.dirty = true;
20313                self.active_indent_guides_state.dirty = true;
20314                self.refresh_active_diagnostics(cx);
20315                self.refresh_code_actions(window, cx);
20316                self.refresh_selected_text_highlights(true, window, cx);
20317                self.refresh_single_line_folds(window, cx);
20318                refresh_matching_bracket_highlights(self, window, cx);
20319                if self.has_active_edit_prediction() {
20320                    self.update_visible_edit_prediction(window, cx);
20321                }
20322                if let Some(project) = self.project.as_ref()
20323                    && let Some(edited_buffer) = edited_buffer
20324                {
20325                    project.update(cx, |project, cx| {
20326                        self.registered_buffers
20327                            .entry(edited_buffer.read(cx).remote_id())
20328                            .or_insert_with(|| {
20329                                project.register_buffer_with_language_servers(edited_buffer, cx)
20330                            });
20331                    });
20332                }
20333                cx.emit(EditorEvent::BufferEdited);
20334                cx.emit(SearchEvent::MatchesInvalidated);
20335
20336                if let Some(buffer) = edited_buffer {
20337                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20338                }
20339
20340                if *singleton_buffer_edited {
20341                    if let Some(buffer) = edited_buffer
20342                        && buffer.read(cx).file().is_none()
20343                    {
20344                        cx.emit(EditorEvent::TitleChanged);
20345                    }
20346                    if let Some(project) = &self.project {
20347                        #[allow(clippy::mutable_key_type)]
20348                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20349                            multibuffer
20350                                .all_buffers()
20351                                .into_iter()
20352                                .filter_map(|buffer| {
20353                                    buffer.update(cx, |buffer, cx| {
20354                                        let language = buffer.language()?;
20355                                        let should_discard = project.update(cx, |project, cx| {
20356                                            project.is_local()
20357                                                && !project.has_language_servers_for(buffer, cx)
20358                                        });
20359                                        should_discard.not().then_some(language.clone())
20360                                    })
20361                                })
20362                                .collect::<HashSet<_>>()
20363                        });
20364                        if !languages_affected.is_empty() {
20365                            self.refresh_inlay_hints(
20366                                InlayHintRefreshReason::BufferEdited(languages_affected),
20367                                cx,
20368                            );
20369                        }
20370                    }
20371                }
20372
20373                let Some(project) = &self.project else { return };
20374                let (telemetry, is_via_ssh) = {
20375                    let project = project.read(cx);
20376                    let telemetry = project.client().telemetry().clone();
20377                    let is_via_ssh = project.is_via_remote_server();
20378                    (telemetry, is_via_ssh)
20379                };
20380                refresh_linked_ranges(self, window, cx);
20381                telemetry.log_edit_event("editor", is_via_ssh);
20382            }
20383            multi_buffer::Event::ExcerptsAdded {
20384                buffer,
20385                predecessor,
20386                excerpts,
20387            } => {
20388                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20389                let buffer_id = buffer.read(cx).remote_id();
20390                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20391                    && let Some(project) = &self.project
20392                {
20393                    update_uncommitted_diff_for_buffer(
20394                        cx.entity(),
20395                        project,
20396                        [buffer.clone()],
20397                        self.buffer.clone(),
20398                        cx,
20399                    )
20400                    .detach();
20401                }
20402                self.update_lsp_data(false, Some(buffer_id), window, cx);
20403                cx.emit(EditorEvent::ExcerptsAdded {
20404                    buffer: buffer.clone(),
20405                    predecessor: *predecessor,
20406                    excerpts: excerpts.clone(),
20407                });
20408                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20409            }
20410            multi_buffer::Event::ExcerptsRemoved {
20411                ids,
20412                removed_buffer_ids,
20413            } => {
20414                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20415                let buffer = self.buffer.read(cx);
20416                self.registered_buffers
20417                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20418                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20419                cx.emit(EditorEvent::ExcerptsRemoved {
20420                    ids: ids.clone(),
20421                    removed_buffer_ids: removed_buffer_ids.clone(),
20422                });
20423            }
20424            multi_buffer::Event::ExcerptsEdited {
20425                excerpt_ids,
20426                buffer_ids,
20427            } => {
20428                self.display_map.update(cx, |map, cx| {
20429                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20430                });
20431                cx.emit(EditorEvent::ExcerptsEdited {
20432                    ids: excerpt_ids.clone(),
20433                });
20434            }
20435            multi_buffer::Event::ExcerptsExpanded { ids } => {
20436                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20437                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20438            }
20439            multi_buffer::Event::Reparsed(buffer_id) => {
20440                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20441                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20442
20443                cx.emit(EditorEvent::Reparsed(*buffer_id));
20444            }
20445            multi_buffer::Event::DiffHunksToggled => {
20446                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20447            }
20448            multi_buffer::Event::LanguageChanged(buffer_id) => {
20449                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20450                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20451                cx.emit(EditorEvent::Reparsed(*buffer_id));
20452                cx.notify();
20453            }
20454            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20455            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20456            multi_buffer::Event::FileHandleChanged
20457            | multi_buffer::Event::Reloaded
20458            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20459            multi_buffer::Event::DiagnosticsUpdated => {
20460                self.update_diagnostics_state(window, cx);
20461            }
20462            _ => {}
20463        };
20464    }
20465
20466    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20467        if !self.diagnostics_enabled() {
20468            return;
20469        }
20470        self.refresh_active_diagnostics(cx);
20471        self.refresh_inline_diagnostics(true, window, cx);
20472        self.scrollbar_marker_state.dirty = true;
20473        cx.notify();
20474    }
20475
20476    pub fn start_temporary_diff_override(&mut self) {
20477        self.load_diff_task.take();
20478        self.temporary_diff_override = true;
20479    }
20480
20481    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20482        self.temporary_diff_override = false;
20483        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20484        self.buffer.update(cx, |buffer, cx| {
20485            buffer.set_all_diff_hunks_collapsed(cx);
20486        });
20487
20488        if let Some(project) = self.project.clone() {
20489            self.load_diff_task = Some(
20490                update_uncommitted_diff_for_buffer(
20491                    cx.entity(),
20492                    &project,
20493                    self.buffer.read(cx).all_buffers(),
20494                    self.buffer.clone(),
20495                    cx,
20496                )
20497                .shared(),
20498            );
20499        }
20500    }
20501
20502    fn on_display_map_changed(
20503        &mut self,
20504        _: Entity<DisplayMap>,
20505        _: &mut Window,
20506        cx: &mut Context<Self>,
20507    ) {
20508        cx.notify();
20509    }
20510
20511    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20512        if self.diagnostics_enabled() {
20513            let new_severity = EditorSettings::get_global(cx)
20514                .diagnostics_max_severity
20515                .unwrap_or(DiagnosticSeverity::Hint);
20516            self.set_max_diagnostics_severity(new_severity, cx);
20517        }
20518        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20519        self.update_edit_prediction_settings(cx);
20520        self.refresh_edit_prediction(true, false, window, cx);
20521        self.refresh_inline_values(cx);
20522        self.refresh_inlay_hints(
20523            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20524                self.selections.newest_anchor().head(),
20525                &self.buffer.read(cx).snapshot(cx),
20526                cx,
20527            )),
20528            cx,
20529        );
20530
20531        let old_cursor_shape = self.cursor_shape;
20532        let old_show_breadcrumbs = self.show_breadcrumbs;
20533
20534        {
20535            let editor_settings = EditorSettings::get_global(cx);
20536            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20537            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20538            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20539            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20540        }
20541
20542        if old_cursor_shape != self.cursor_shape {
20543            cx.emit(EditorEvent::CursorShapeChanged);
20544        }
20545
20546        if old_show_breadcrumbs != self.show_breadcrumbs {
20547            cx.emit(EditorEvent::BreadcrumbsChanged);
20548        }
20549
20550        let project_settings = ProjectSettings::get_global(cx);
20551        self.serialize_dirty_buffers =
20552            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20553
20554        if self.mode.is_full() {
20555            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20556            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20557            if self.show_inline_diagnostics != show_inline_diagnostics {
20558                self.show_inline_diagnostics = show_inline_diagnostics;
20559                self.refresh_inline_diagnostics(false, window, cx);
20560            }
20561
20562            if self.git_blame_inline_enabled != inline_blame_enabled {
20563                self.toggle_git_blame_inline_internal(false, window, cx);
20564            }
20565
20566            let minimap_settings = EditorSettings::get_global(cx).minimap;
20567            if self.minimap_visibility != MinimapVisibility::Disabled {
20568                if self.minimap_visibility.settings_visibility()
20569                    != minimap_settings.minimap_enabled()
20570                {
20571                    self.set_minimap_visibility(
20572                        MinimapVisibility::for_mode(self.mode(), cx),
20573                        window,
20574                        cx,
20575                    );
20576                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20577                    minimap_entity.update(cx, |minimap_editor, cx| {
20578                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20579                    })
20580                }
20581            }
20582        }
20583
20584        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20585            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20586        }) {
20587            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20588                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20589            }
20590            self.refresh_colors(false, None, window, cx);
20591        }
20592
20593        cx.notify();
20594    }
20595
20596    pub fn set_searchable(&mut self, searchable: bool) {
20597        self.searchable = searchable;
20598    }
20599
20600    pub fn searchable(&self) -> bool {
20601        self.searchable
20602    }
20603
20604    fn open_proposed_changes_editor(
20605        &mut self,
20606        _: &OpenProposedChangesEditor,
20607        window: &mut Window,
20608        cx: &mut Context<Self>,
20609    ) {
20610        let Some(workspace) = self.workspace() else {
20611            cx.propagate();
20612            return;
20613        };
20614
20615        let selections = self.selections.all::<usize>(cx);
20616        let multi_buffer = self.buffer.read(cx);
20617        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20618        let mut new_selections_by_buffer = HashMap::default();
20619        for selection in selections {
20620            for (buffer, range, _) in
20621                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20622            {
20623                let mut range = range.to_point(buffer);
20624                range.start.column = 0;
20625                range.end.column = buffer.line_len(range.end.row);
20626                new_selections_by_buffer
20627                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20628                    .or_insert(Vec::new())
20629                    .push(range)
20630            }
20631        }
20632
20633        let proposed_changes_buffers = new_selections_by_buffer
20634            .into_iter()
20635            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20636            .collect::<Vec<_>>();
20637        let proposed_changes_editor = cx.new(|cx| {
20638            ProposedChangesEditor::new(
20639                "Proposed changes",
20640                proposed_changes_buffers,
20641                self.project.clone(),
20642                window,
20643                cx,
20644            )
20645        });
20646
20647        window.defer(cx, move |window, cx| {
20648            workspace.update(cx, |workspace, cx| {
20649                workspace.active_pane().update(cx, |pane, cx| {
20650                    pane.add_item(
20651                        Box::new(proposed_changes_editor),
20652                        true,
20653                        true,
20654                        None,
20655                        window,
20656                        cx,
20657                    );
20658                });
20659            });
20660        });
20661    }
20662
20663    pub fn open_excerpts_in_split(
20664        &mut self,
20665        _: &OpenExcerptsSplit,
20666        window: &mut Window,
20667        cx: &mut Context<Self>,
20668    ) {
20669        self.open_excerpts_common(None, true, window, cx)
20670    }
20671
20672    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20673        self.open_excerpts_common(None, false, window, cx)
20674    }
20675
20676    fn open_excerpts_common(
20677        &mut self,
20678        jump_data: Option<JumpData>,
20679        split: bool,
20680        window: &mut Window,
20681        cx: &mut Context<Self>,
20682    ) {
20683        let Some(workspace) = self.workspace() else {
20684            cx.propagate();
20685            return;
20686        };
20687
20688        if self.buffer.read(cx).is_singleton() {
20689            cx.propagate();
20690            return;
20691        }
20692
20693        let mut new_selections_by_buffer = HashMap::default();
20694        match &jump_data {
20695            Some(JumpData::MultiBufferPoint {
20696                excerpt_id,
20697                position,
20698                anchor,
20699                line_offset_from_top,
20700            }) => {
20701                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20702                if let Some(buffer) = multi_buffer_snapshot
20703                    .buffer_id_for_excerpt(*excerpt_id)
20704                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20705                {
20706                    let buffer_snapshot = buffer.read(cx).snapshot();
20707                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20708                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20709                    } else {
20710                        buffer_snapshot.clip_point(*position, Bias::Left)
20711                    };
20712                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20713                    new_selections_by_buffer.insert(
20714                        buffer,
20715                        (
20716                            vec![jump_to_offset..jump_to_offset],
20717                            Some(*line_offset_from_top),
20718                        ),
20719                    );
20720                }
20721            }
20722            Some(JumpData::MultiBufferRow {
20723                row,
20724                line_offset_from_top,
20725            }) => {
20726                let point = MultiBufferPoint::new(row.0, 0);
20727                if let Some((buffer, buffer_point, _)) =
20728                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20729                {
20730                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20731                    new_selections_by_buffer
20732                        .entry(buffer)
20733                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20734                        .0
20735                        .push(buffer_offset..buffer_offset)
20736                }
20737            }
20738            None => {
20739                let selections = self.selections.all::<usize>(cx);
20740                let multi_buffer = self.buffer.read(cx);
20741                for selection in selections {
20742                    for (snapshot, range, _, anchor) in multi_buffer
20743                        .snapshot(cx)
20744                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20745                    {
20746                        if let Some(anchor) = anchor {
20747                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20748                            else {
20749                                continue;
20750                            };
20751                            let offset = text::ToOffset::to_offset(
20752                                &anchor.text_anchor,
20753                                &buffer_handle.read(cx).snapshot(),
20754                            );
20755                            let range = offset..offset;
20756                            new_selections_by_buffer
20757                                .entry(buffer_handle)
20758                                .or_insert((Vec::new(), None))
20759                                .0
20760                                .push(range)
20761                        } else {
20762                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20763                            else {
20764                                continue;
20765                            };
20766                            new_selections_by_buffer
20767                                .entry(buffer_handle)
20768                                .or_insert((Vec::new(), None))
20769                                .0
20770                                .push(range)
20771                        }
20772                    }
20773                }
20774            }
20775        }
20776
20777        new_selections_by_buffer
20778            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20779
20780        if new_selections_by_buffer.is_empty() {
20781            return;
20782        }
20783
20784        // We defer the pane interaction because we ourselves are a workspace item
20785        // and activating a new item causes the pane to call a method on us reentrantly,
20786        // which panics if we're on the stack.
20787        window.defer(cx, move |window, cx| {
20788            workspace.update(cx, |workspace, cx| {
20789                let pane = if split {
20790                    workspace.adjacent_pane(window, cx)
20791                } else {
20792                    workspace.active_pane().clone()
20793                };
20794
20795                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20796                    let editor = buffer
20797                        .read(cx)
20798                        .file()
20799                        .is_none()
20800                        .then(|| {
20801                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20802                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20803                            // Instead, we try to activate the existing editor in the pane first.
20804                            let (editor, pane_item_index) =
20805                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20806                                    let editor = item.downcast::<Editor>()?;
20807                                    let singleton_buffer =
20808                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20809                                    if singleton_buffer == buffer {
20810                                        Some((editor, i))
20811                                    } else {
20812                                        None
20813                                    }
20814                                })?;
20815                            pane.update(cx, |pane, cx| {
20816                                pane.activate_item(pane_item_index, true, true, window, cx)
20817                            });
20818                            Some(editor)
20819                        })
20820                        .flatten()
20821                        .unwrap_or_else(|| {
20822                            workspace.open_project_item::<Self>(
20823                                pane.clone(),
20824                                buffer,
20825                                true,
20826                                true,
20827                                window,
20828                                cx,
20829                            )
20830                        });
20831
20832                    editor.update(cx, |editor, cx| {
20833                        let autoscroll = match scroll_offset {
20834                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20835                            None => Autoscroll::newest(),
20836                        };
20837                        let nav_history = editor.nav_history.take();
20838                        editor.change_selections(
20839                            SelectionEffects::scroll(autoscroll),
20840                            window,
20841                            cx,
20842                            |s| {
20843                                s.select_ranges(ranges);
20844                            },
20845                        );
20846                        editor.nav_history = nav_history;
20847                    });
20848                }
20849            })
20850        });
20851    }
20852
20853    // For now, don't allow opening excerpts in buffers that aren't backed by
20854    // regular project files.
20855    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20856        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20857    }
20858
20859    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20860        let snapshot = self.buffer.read(cx).read(cx);
20861        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20862        Some(
20863            ranges
20864                .iter()
20865                .map(move |range| {
20866                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20867                })
20868                .collect(),
20869        )
20870    }
20871
20872    fn selection_replacement_ranges(
20873        &self,
20874        range: Range<OffsetUtf16>,
20875        cx: &mut App,
20876    ) -> Vec<Range<OffsetUtf16>> {
20877        let selections = self.selections.all::<OffsetUtf16>(cx);
20878        let newest_selection = selections
20879            .iter()
20880            .max_by_key(|selection| selection.id)
20881            .unwrap();
20882        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20883        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20884        let snapshot = self.buffer.read(cx).read(cx);
20885        selections
20886            .into_iter()
20887            .map(|mut selection| {
20888                selection.start.0 =
20889                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20890                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20891                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20892                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20893            })
20894            .collect()
20895    }
20896
20897    fn report_editor_event(
20898        &self,
20899        reported_event: ReportEditorEvent,
20900        file_extension: Option<String>,
20901        cx: &App,
20902    ) {
20903        if cfg!(any(test, feature = "test-support")) {
20904            return;
20905        }
20906
20907        let Some(project) = &self.project else { return };
20908
20909        // If None, we are in a file without an extension
20910        let file = self
20911            .buffer
20912            .read(cx)
20913            .as_singleton()
20914            .and_then(|b| b.read(cx).file());
20915        let file_extension = file_extension.or(file
20916            .as_ref()
20917            .and_then(|file| Path::new(file.file_name(cx)).extension())
20918            .and_then(|e| e.to_str())
20919            .map(|a| a.to_string()));
20920
20921        let vim_mode = vim_enabled(cx);
20922
20923        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20924        let copilot_enabled = edit_predictions_provider
20925            == language::language_settings::EditPredictionProvider::Copilot;
20926        let copilot_enabled_for_language = self
20927            .buffer
20928            .read(cx)
20929            .language_settings(cx)
20930            .show_edit_predictions;
20931
20932        let project = project.read(cx);
20933        let event_type = reported_event.event_type();
20934
20935        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20936            telemetry::event!(
20937                event_type,
20938                type = if auto_saved {"autosave"} else {"manual"},
20939                file_extension,
20940                vim_mode,
20941                copilot_enabled,
20942                copilot_enabled_for_language,
20943                edit_predictions_provider,
20944                is_via_ssh = project.is_via_remote_server(),
20945            );
20946        } else {
20947            telemetry::event!(
20948                event_type,
20949                file_extension,
20950                vim_mode,
20951                copilot_enabled,
20952                copilot_enabled_for_language,
20953                edit_predictions_provider,
20954                is_via_ssh = project.is_via_remote_server(),
20955            );
20956        };
20957    }
20958
20959    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20960    /// with each line being an array of {text, highlight} objects.
20961    fn copy_highlight_json(
20962        &mut self,
20963        _: &CopyHighlightJson,
20964        window: &mut Window,
20965        cx: &mut Context<Self>,
20966    ) {
20967        #[derive(Serialize)]
20968        struct Chunk<'a> {
20969            text: String,
20970            highlight: Option<&'a str>,
20971        }
20972
20973        let snapshot = self.buffer.read(cx).snapshot(cx);
20974        let range = self
20975            .selected_text_range(false, window, cx)
20976            .and_then(|selection| {
20977                if selection.range.is_empty() {
20978                    None
20979                } else {
20980                    Some(selection.range)
20981                }
20982            })
20983            .unwrap_or_else(|| 0..snapshot.len());
20984
20985        let chunks = snapshot.chunks(range, true);
20986        let mut lines = Vec::new();
20987        let mut line: VecDeque<Chunk> = VecDeque::new();
20988
20989        let Some(style) = self.style.as_ref() else {
20990            return;
20991        };
20992
20993        for chunk in chunks {
20994            let highlight = chunk
20995                .syntax_highlight_id
20996                .and_then(|id| id.name(&style.syntax));
20997            let mut chunk_lines = chunk.text.split('\n').peekable();
20998            while let Some(text) = chunk_lines.next() {
20999                let mut merged_with_last_token = false;
21000                if let Some(last_token) = line.back_mut()
21001                    && last_token.highlight == highlight
21002                {
21003                    last_token.text.push_str(text);
21004                    merged_with_last_token = true;
21005                }
21006
21007                if !merged_with_last_token {
21008                    line.push_back(Chunk {
21009                        text: text.into(),
21010                        highlight,
21011                    });
21012                }
21013
21014                if chunk_lines.peek().is_some() {
21015                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21016                        line.pop_front();
21017                    }
21018                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21019                        line.pop_back();
21020                    }
21021
21022                    lines.push(mem::take(&mut line));
21023                }
21024            }
21025        }
21026
21027        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21028            return;
21029        };
21030        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21031    }
21032
21033    pub fn open_context_menu(
21034        &mut self,
21035        _: &OpenContextMenu,
21036        window: &mut Window,
21037        cx: &mut Context<Self>,
21038    ) {
21039        self.request_autoscroll(Autoscroll::newest(), cx);
21040        let position = self.selections.newest_display(cx).start;
21041        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21042    }
21043
21044    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21045        &self.inlay_hint_cache
21046    }
21047
21048    pub fn replay_insert_event(
21049        &mut self,
21050        text: &str,
21051        relative_utf16_range: Option<Range<isize>>,
21052        window: &mut Window,
21053        cx: &mut Context<Self>,
21054    ) {
21055        if !self.input_enabled {
21056            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21057            return;
21058        }
21059        if let Some(relative_utf16_range) = relative_utf16_range {
21060            let selections = self.selections.all::<OffsetUtf16>(cx);
21061            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21062                let new_ranges = selections.into_iter().map(|range| {
21063                    let start = OffsetUtf16(
21064                        range
21065                            .head()
21066                            .0
21067                            .saturating_add_signed(relative_utf16_range.start),
21068                    );
21069                    let end = OffsetUtf16(
21070                        range
21071                            .head()
21072                            .0
21073                            .saturating_add_signed(relative_utf16_range.end),
21074                    );
21075                    start..end
21076                });
21077                s.select_ranges(new_ranges);
21078            });
21079        }
21080
21081        self.handle_input(text, window, cx);
21082    }
21083
21084    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21085        let Some(provider) = self.semantics_provider.as_ref() else {
21086            return false;
21087        };
21088
21089        let mut supports = false;
21090        self.buffer().update(cx, |this, cx| {
21091            this.for_each_buffer(|buffer| {
21092                supports |= provider.supports_inlay_hints(buffer, cx);
21093            });
21094        });
21095
21096        supports
21097    }
21098
21099    pub fn is_focused(&self, window: &Window) -> bool {
21100        self.focus_handle.is_focused(window)
21101    }
21102
21103    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21104        cx.emit(EditorEvent::Focused);
21105
21106        if let Some(descendant) = self
21107            .last_focused_descendant
21108            .take()
21109            .and_then(|descendant| descendant.upgrade())
21110        {
21111            window.focus(&descendant);
21112        } else {
21113            if let Some(blame) = self.blame.as_ref() {
21114                blame.update(cx, GitBlame::focus)
21115            }
21116
21117            self.blink_manager.update(cx, BlinkManager::enable);
21118            self.show_cursor_names(window, cx);
21119            self.buffer.update(cx, |buffer, cx| {
21120                buffer.finalize_last_transaction(cx);
21121                if self.leader_id.is_none() {
21122                    buffer.set_active_selections(
21123                        &self.selections.disjoint_anchors(),
21124                        self.selections.line_mode,
21125                        self.cursor_shape,
21126                        cx,
21127                    );
21128                }
21129            });
21130        }
21131    }
21132
21133    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21134        cx.emit(EditorEvent::FocusedIn)
21135    }
21136
21137    fn handle_focus_out(
21138        &mut self,
21139        event: FocusOutEvent,
21140        _window: &mut Window,
21141        cx: &mut Context<Self>,
21142    ) {
21143        if event.blurred != self.focus_handle {
21144            self.last_focused_descendant = Some(event.blurred);
21145        }
21146        self.selection_drag_state = SelectionDragState::None;
21147        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21148    }
21149
21150    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21151        self.blink_manager.update(cx, BlinkManager::disable);
21152        self.buffer
21153            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21154
21155        if let Some(blame) = self.blame.as_ref() {
21156            blame.update(cx, GitBlame::blur)
21157        }
21158        if !self.hover_state.focused(window, cx) {
21159            hide_hover(self, cx);
21160        }
21161        if !self
21162            .context_menu
21163            .borrow()
21164            .as_ref()
21165            .is_some_and(|context_menu| context_menu.focused(window, cx))
21166        {
21167            self.hide_context_menu(window, cx);
21168        }
21169        self.discard_edit_prediction(false, cx);
21170        cx.emit(EditorEvent::Blurred);
21171        cx.notify();
21172    }
21173
21174    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21175        let mut pending: String = window
21176            .pending_input_keystrokes()
21177            .into_iter()
21178            .flatten()
21179            .filter_map(|keystroke| {
21180                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21181                    keystroke.key_char.clone()
21182                } else {
21183                    None
21184                }
21185            })
21186            .collect();
21187
21188        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21189            pending = "".to_string();
21190        }
21191
21192        let existing_pending = self
21193            .text_highlights::<PendingInput>(cx)
21194            .map(|(_, ranges)| ranges.to_vec());
21195        if existing_pending.is_none() && pending.is_empty() {
21196            return;
21197        }
21198        let transaction =
21199            self.transact(window, cx, |this, window, cx| {
21200                let selections = this.selections.all::<usize>(cx);
21201                let edits = selections
21202                    .iter()
21203                    .map(|selection| (selection.end..selection.end, pending.clone()));
21204                this.edit(edits, cx);
21205                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21206                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21207                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21208                    }));
21209                });
21210                if let Some(existing_ranges) = existing_pending {
21211                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21212                    this.edit(edits, cx);
21213                }
21214            });
21215
21216        let snapshot = self.snapshot(window, cx);
21217        let ranges = self
21218            .selections
21219            .all::<usize>(cx)
21220            .into_iter()
21221            .map(|selection| {
21222                snapshot.buffer_snapshot.anchor_after(selection.end)
21223                    ..snapshot
21224                        .buffer_snapshot
21225                        .anchor_before(selection.end + pending.len())
21226            })
21227            .collect();
21228
21229        if pending.is_empty() {
21230            self.clear_highlights::<PendingInput>(cx);
21231        } else {
21232            self.highlight_text::<PendingInput>(
21233                ranges,
21234                HighlightStyle {
21235                    underline: Some(UnderlineStyle {
21236                        thickness: px(1.),
21237                        color: None,
21238                        wavy: false,
21239                    }),
21240                    ..Default::default()
21241                },
21242                cx,
21243            );
21244        }
21245
21246        self.ime_transaction = self.ime_transaction.or(transaction);
21247        if let Some(transaction) = self.ime_transaction {
21248            self.buffer.update(cx, |buffer, cx| {
21249                buffer.group_until_transaction(transaction, cx);
21250            });
21251        }
21252
21253        if self.text_highlights::<PendingInput>(cx).is_none() {
21254            self.ime_transaction.take();
21255        }
21256    }
21257
21258    pub fn register_action_renderer(
21259        &mut self,
21260        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21261    ) -> Subscription {
21262        let id = self.next_editor_action_id.post_inc();
21263        self.editor_actions
21264            .borrow_mut()
21265            .insert(id, Box::new(listener));
21266
21267        let editor_actions = self.editor_actions.clone();
21268        Subscription::new(move || {
21269            editor_actions.borrow_mut().remove(&id);
21270        })
21271    }
21272
21273    pub fn register_action<A: Action>(
21274        &mut self,
21275        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21276    ) -> Subscription {
21277        let id = self.next_editor_action_id.post_inc();
21278        let listener = Arc::new(listener);
21279        self.editor_actions.borrow_mut().insert(
21280            id,
21281            Box::new(move |_, window, _| {
21282                let listener = listener.clone();
21283                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21284                    let action = action.downcast_ref().unwrap();
21285                    if phase == DispatchPhase::Bubble {
21286                        listener(action, window, cx)
21287                    }
21288                })
21289            }),
21290        );
21291
21292        let editor_actions = self.editor_actions.clone();
21293        Subscription::new(move || {
21294            editor_actions.borrow_mut().remove(&id);
21295        })
21296    }
21297
21298    pub fn file_header_size(&self) -> u32 {
21299        FILE_HEADER_HEIGHT
21300    }
21301
21302    pub fn restore(
21303        &mut self,
21304        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21305        window: &mut Window,
21306        cx: &mut Context<Self>,
21307    ) {
21308        let workspace = self.workspace();
21309        let project = self.project();
21310        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21311            let mut tasks = Vec::new();
21312            for (buffer_id, changes) in revert_changes {
21313                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21314                    buffer.update(cx, |buffer, cx| {
21315                        buffer.edit(
21316                            changes
21317                                .into_iter()
21318                                .map(|(range, text)| (range, text.to_string())),
21319                            None,
21320                            cx,
21321                        );
21322                    });
21323
21324                    if let Some(project) =
21325                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21326                    {
21327                        project.update(cx, |project, cx| {
21328                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21329                        })
21330                    }
21331                }
21332            }
21333            tasks
21334        });
21335        cx.spawn_in(window, async move |_, cx| {
21336            for (buffer, task) in save_tasks {
21337                let result = task.await;
21338                if result.is_err() {
21339                    let Some(path) = buffer
21340                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21341                        .ok()
21342                    else {
21343                        continue;
21344                    };
21345                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21346                        let Some(task) = cx
21347                            .update_window_entity(workspace, |workspace, window, cx| {
21348                                workspace
21349                                    .open_path_preview(path, None, false, false, false, window, cx)
21350                            })
21351                            .ok()
21352                        else {
21353                            continue;
21354                        };
21355                        task.await.log_err();
21356                    }
21357                }
21358            }
21359        })
21360        .detach();
21361        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21362            selections.refresh()
21363        });
21364    }
21365
21366    pub fn to_pixel_point(
21367        &self,
21368        source: multi_buffer::Anchor,
21369        editor_snapshot: &EditorSnapshot,
21370        window: &mut Window,
21371    ) -> Option<gpui::Point<Pixels>> {
21372        let source_point = source.to_display_point(editor_snapshot);
21373        self.display_to_pixel_point(source_point, editor_snapshot, window)
21374    }
21375
21376    pub fn display_to_pixel_point(
21377        &self,
21378        source: DisplayPoint,
21379        editor_snapshot: &EditorSnapshot,
21380        window: &mut Window,
21381    ) -> Option<gpui::Point<Pixels>> {
21382        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21383        let text_layout_details = self.text_layout_details(window);
21384        let scroll_top = text_layout_details
21385            .scroll_anchor
21386            .scroll_position(editor_snapshot)
21387            .y;
21388
21389        if source.row().as_f32() < scroll_top.floor() {
21390            return None;
21391        }
21392        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21393        let source_y = line_height * (source.row().as_f32() - scroll_top);
21394        Some(gpui::Point::new(source_x, source_y))
21395    }
21396
21397    pub fn has_visible_completions_menu(&self) -> bool {
21398        !self.edit_prediction_preview_is_active()
21399            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21400                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21401            })
21402    }
21403
21404    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21405        if self.mode.is_minimap() {
21406            return;
21407        }
21408        self.addons
21409            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21410    }
21411
21412    pub fn unregister_addon<T: Addon>(&mut self) {
21413        self.addons.remove(&std::any::TypeId::of::<T>());
21414    }
21415
21416    pub fn addon<T: Addon>(&self) -> Option<&T> {
21417        let type_id = std::any::TypeId::of::<T>();
21418        self.addons
21419            .get(&type_id)
21420            .and_then(|item| item.to_any().downcast_ref::<T>())
21421    }
21422
21423    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21424        let type_id = std::any::TypeId::of::<T>();
21425        self.addons
21426            .get_mut(&type_id)
21427            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21428    }
21429
21430    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21431        let text_layout_details = self.text_layout_details(window);
21432        let style = &text_layout_details.editor_style;
21433        let font_id = window.text_system().resolve_font(&style.text.font());
21434        let font_size = style.text.font_size.to_pixels(window.rem_size());
21435        let line_height = style.text.line_height_in_pixels(window.rem_size());
21436        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21437        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21438
21439        CharacterDimensions {
21440            em_width,
21441            em_advance,
21442            line_height,
21443        }
21444    }
21445
21446    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21447        self.load_diff_task.clone()
21448    }
21449
21450    fn read_metadata_from_db(
21451        &mut self,
21452        item_id: u64,
21453        workspace_id: WorkspaceId,
21454        window: &mut Window,
21455        cx: &mut Context<Editor>,
21456    ) {
21457        if self.is_singleton(cx)
21458            && !self.mode.is_minimap()
21459            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21460        {
21461            let buffer_snapshot = OnceCell::new();
21462
21463            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21464                && !folds.is_empty()
21465            {
21466                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21467                self.fold_ranges(
21468                    folds
21469                        .into_iter()
21470                        .map(|(start, end)| {
21471                            snapshot.clip_offset(start, Bias::Left)
21472                                ..snapshot.clip_offset(end, Bias::Right)
21473                        })
21474                        .collect(),
21475                    false,
21476                    window,
21477                    cx,
21478                );
21479            }
21480
21481            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21482                && !selections.is_empty()
21483            {
21484                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21485                // skip adding the initial selection to selection history
21486                self.selection_history.mode = SelectionHistoryMode::Skipping;
21487                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21488                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21489                        snapshot.clip_offset(start, Bias::Left)
21490                            ..snapshot.clip_offset(end, Bias::Right)
21491                    }));
21492                });
21493                self.selection_history.mode = SelectionHistoryMode::Normal;
21494            };
21495        }
21496
21497        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21498    }
21499
21500    fn update_lsp_data(
21501        &mut self,
21502        ignore_cache: bool,
21503        for_buffer: Option<BufferId>,
21504        window: &mut Window,
21505        cx: &mut Context<'_, Self>,
21506    ) {
21507        self.pull_diagnostics(for_buffer, window, cx);
21508        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21509    }
21510}
21511
21512fn vim_enabled(cx: &App) -> bool {
21513    cx.global::<SettingsStore>()
21514        .raw_user_settings()
21515        .get("vim_mode")
21516        == Some(&serde_json::Value::Bool(true))
21517}
21518
21519fn process_completion_for_edit(
21520    completion: &Completion,
21521    intent: CompletionIntent,
21522    buffer: &Entity<Buffer>,
21523    cursor_position: &text::Anchor,
21524    cx: &mut Context<Editor>,
21525) -> CompletionEdit {
21526    let buffer = buffer.read(cx);
21527    let buffer_snapshot = buffer.snapshot();
21528    let (snippet, new_text) = if completion.is_snippet() {
21529        // Workaround for typescript language server issues so that methods don't expand within
21530        // strings and functions with type expressions. The previous point is used because the query
21531        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21532        let mut snippet_source = completion.new_text.clone();
21533        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21534        previous_point.column = previous_point.column.saturating_sub(1);
21535        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21536            && scope.prefers_label_for_snippet_in_completion()
21537            && let Some(label) = completion.label()
21538            && matches!(
21539                completion.kind(),
21540                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21541            )
21542        {
21543            snippet_source = label;
21544        }
21545        match Snippet::parse(&snippet_source).log_err() {
21546            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21547            None => (None, completion.new_text.clone()),
21548        }
21549    } else {
21550        (None, completion.new_text.clone())
21551    };
21552
21553    let mut range_to_replace = {
21554        let replace_range = &completion.replace_range;
21555        if let CompletionSource::Lsp {
21556            insert_range: Some(insert_range),
21557            ..
21558        } = &completion.source
21559        {
21560            debug_assert_eq!(
21561                insert_range.start, replace_range.start,
21562                "insert_range and replace_range should start at the same position"
21563            );
21564            debug_assert!(
21565                insert_range
21566                    .start
21567                    .cmp(cursor_position, &buffer_snapshot)
21568                    .is_le(),
21569                "insert_range should start before or at cursor position"
21570            );
21571            debug_assert!(
21572                replace_range
21573                    .start
21574                    .cmp(cursor_position, &buffer_snapshot)
21575                    .is_le(),
21576                "replace_range should start before or at cursor position"
21577            );
21578
21579            let should_replace = match intent {
21580                CompletionIntent::CompleteWithInsert => false,
21581                CompletionIntent::CompleteWithReplace => true,
21582                CompletionIntent::Complete | CompletionIntent::Compose => {
21583                    let insert_mode =
21584                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21585                            .completions
21586                            .lsp_insert_mode;
21587                    match insert_mode {
21588                        LspInsertMode::Insert => false,
21589                        LspInsertMode::Replace => true,
21590                        LspInsertMode::ReplaceSubsequence => {
21591                            let mut text_to_replace = buffer.chars_for_range(
21592                                buffer.anchor_before(replace_range.start)
21593                                    ..buffer.anchor_after(replace_range.end),
21594                            );
21595                            let mut current_needle = text_to_replace.next();
21596                            for haystack_ch in completion.label.text.chars() {
21597                                if let Some(needle_ch) = current_needle
21598                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21599                                {
21600                                    current_needle = text_to_replace.next();
21601                                }
21602                            }
21603                            current_needle.is_none()
21604                        }
21605                        LspInsertMode::ReplaceSuffix => {
21606                            if replace_range
21607                                .end
21608                                .cmp(cursor_position, &buffer_snapshot)
21609                                .is_gt()
21610                            {
21611                                let range_after_cursor = *cursor_position..replace_range.end;
21612                                let text_after_cursor = buffer
21613                                    .text_for_range(
21614                                        buffer.anchor_before(range_after_cursor.start)
21615                                            ..buffer.anchor_after(range_after_cursor.end),
21616                                    )
21617                                    .collect::<String>()
21618                                    .to_ascii_lowercase();
21619                                completion
21620                                    .label
21621                                    .text
21622                                    .to_ascii_lowercase()
21623                                    .ends_with(&text_after_cursor)
21624                            } else {
21625                                true
21626                            }
21627                        }
21628                    }
21629                }
21630            };
21631
21632            if should_replace {
21633                replace_range.clone()
21634            } else {
21635                insert_range.clone()
21636            }
21637        } else {
21638            replace_range.clone()
21639        }
21640    };
21641
21642    if range_to_replace
21643        .end
21644        .cmp(cursor_position, &buffer_snapshot)
21645        .is_lt()
21646    {
21647        range_to_replace.end = *cursor_position;
21648    }
21649
21650    CompletionEdit {
21651        new_text,
21652        replace_range: range_to_replace.to_offset(buffer),
21653        snippet,
21654    }
21655}
21656
21657struct CompletionEdit {
21658    new_text: String,
21659    replace_range: Range<usize>,
21660    snippet: Option<Snippet>,
21661}
21662
21663fn insert_extra_newline_brackets(
21664    buffer: &MultiBufferSnapshot,
21665    range: Range<usize>,
21666    language: &language::LanguageScope,
21667) -> bool {
21668    let leading_whitespace_len = buffer
21669        .reversed_chars_at(range.start)
21670        .take_while(|c| c.is_whitespace() && *c != '\n')
21671        .map(|c| c.len_utf8())
21672        .sum::<usize>();
21673    let trailing_whitespace_len = buffer
21674        .chars_at(range.end)
21675        .take_while(|c| c.is_whitespace() && *c != '\n')
21676        .map(|c| c.len_utf8())
21677        .sum::<usize>();
21678    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21679
21680    language.brackets().any(|(pair, enabled)| {
21681        let pair_start = pair.start.trim_end();
21682        let pair_end = pair.end.trim_start();
21683
21684        enabled
21685            && pair.newline
21686            && buffer.contains_str_at(range.end, pair_end)
21687            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21688    })
21689}
21690
21691fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21692    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21693        [(buffer, range, _)] => (*buffer, range.clone()),
21694        _ => return false,
21695    };
21696    let pair = {
21697        let mut result: Option<BracketMatch> = None;
21698
21699        for pair in buffer
21700            .all_bracket_ranges(range.clone())
21701            .filter(move |pair| {
21702                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21703            })
21704        {
21705            let len = pair.close_range.end - pair.open_range.start;
21706
21707            if let Some(existing) = &result {
21708                let existing_len = existing.close_range.end - existing.open_range.start;
21709                if len > existing_len {
21710                    continue;
21711                }
21712            }
21713
21714            result = Some(pair);
21715        }
21716
21717        result
21718    };
21719    let Some(pair) = pair else {
21720        return false;
21721    };
21722    pair.newline_only
21723        && buffer
21724            .chars_for_range(pair.open_range.end..range.start)
21725            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21726            .all(|c| c.is_whitespace() && c != '\n')
21727}
21728
21729fn update_uncommitted_diff_for_buffer(
21730    editor: Entity<Editor>,
21731    project: &Entity<Project>,
21732    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21733    buffer: Entity<MultiBuffer>,
21734    cx: &mut App,
21735) -> Task<()> {
21736    let mut tasks = Vec::new();
21737    project.update(cx, |project, cx| {
21738        for buffer in buffers {
21739            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21740                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21741            }
21742        }
21743    });
21744    cx.spawn(async move |cx| {
21745        let diffs = future::join_all(tasks).await;
21746        if editor
21747            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21748            .unwrap_or(false)
21749        {
21750            return;
21751        }
21752
21753        buffer
21754            .update(cx, |buffer, cx| {
21755                for diff in diffs.into_iter().flatten() {
21756                    buffer.add_diff(diff, cx);
21757                }
21758            })
21759            .ok();
21760    })
21761}
21762
21763fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21764    let tab_size = tab_size.get() as usize;
21765    let mut width = offset;
21766
21767    for ch in text.chars() {
21768        width += if ch == '\t' {
21769            tab_size - (width % tab_size)
21770        } else {
21771            1
21772        };
21773    }
21774
21775    width - offset
21776}
21777
21778#[cfg(test)]
21779mod tests {
21780    use super::*;
21781
21782    #[test]
21783    fn test_string_size_with_expanded_tabs() {
21784        let nz = |val| NonZeroU32::new(val).unwrap();
21785        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21786        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21787        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21788        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21789        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21790        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21791        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21792        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21793    }
21794}
21795
21796/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21797struct WordBreakingTokenizer<'a> {
21798    input: &'a str,
21799}
21800
21801impl<'a> WordBreakingTokenizer<'a> {
21802    fn new(input: &'a str) -> Self {
21803        Self { input }
21804    }
21805}
21806
21807fn is_char_ideographic(ch: char) -> bool {
21808    use unicode_script::Script::*;
21809    use unicode_script::UnicodeScript;
21810    matches!(ch.script(), Han | Tangut | Yi)
21811}
21812
21813fn is_grapheme_ideographic(text: &str) -> bool {
21814    text.chars().any(is_char_ideographic)
21815}
21816
21817fn is_grapheme_whitespace(text: &str) -> bool {
21818    text.chars().any(|x| x.is_whitespace())
21819}
21820
21821fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21822    text.chars()
21823        .next()
21824        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21825}
21826
21827#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21828enum WordBreakToken<'a> {
21829    Word { token: &'a str, grapheme_len: usize },
21830    InlineWhitespace { token: &'a str, grapheme_len: usize },
21831    Newline,
21832}
21833
21834impl<'a> Iterator for WordBreakingTokenizer<'a> {
21835    /// Yields a span, the count of graphemes in the token, and whether it was
21836    /// whitespace. Note that it also breaks at word boundaries.
21837    type Item = WordBreakToken<'a>;
21838
21839    fn next(&mut self) -> Option<Self::Item> {
21840        use unicode_segmentation::UnicodeSegmentation;
21841        if self.input.is_empty() {
21842            return None;
21843        }
21844
21845        let mut iter = self.input.graphemes(true).peekable();
21846        let mut offset = 0;
21847        let mut grapheme_len = 0;
21848        if let Some(first_grapheme) = iter.next() {
21849            let is_newline = first_grapheme == "\n";
21850            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21851            offset += first_grapheme.len();
21852            grapheme_len += 1;
21853            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21854                if let Some(grapheme) = iter.peek().copied()
21855                    && should_stay_with_preceding_ideograph(grapheme)
21856                {
21857                    offset += grapheme.len();
21858                    grapheme_len += 1;
21859                }
21860            } else {
21861                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21862                let mut next_word_bound = words.peek().copied();
21863                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21864                    next_word_bound = words.next();
21865                }
21866                while let Some(grapheme) = iter.peek().copied() {
21867                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21868                        break;
21869                    };
21870                    if is_grapheme_whitespace(grapheme) != is_whitespace
21871                        || (grapheme == "\n") != is_newline
21872                    {
21873                        break;
21874                    };
21875                    offset += grapheme.len();
21876                    grapheme_len += 1;
21877                    iter.next();
21878                }
21879            }
21880            let token = &self.input[..offset];
21881            self.input = &self.input[offset..];
21882            if token == "\n" {
21883                Some(WordBreakToken::Newline)
21884            } else if is_whitespace {
21885                Some(WordBreakToken::InlineWhitespace {
21886                    token,
21887                    grapheme_len,
21888                })
21889            } else {
21890                Some(WordBreakToken::Word {
21891                    token,
21892                    grapheme_len,
21893                })
21894            }
21895        } else {
21896            None
21897        }
21898    }
21899}
21900
21901#[test]
21902fn test_word_breaking_tokenizer() {
21903    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21904        ("", &[]),
21905        ("  ", &[whitespace("  ", 2)]),
21906        ("Ʒ", &[word("Ʒ", 1)]),
21907        ("Ǽ", &[word("Ǽ", 1)]),
21908        ("", &[word("", 1)]),
21909        ("⋑⋑", &[word("⋑⋑", 2)]),
21910        (
21911            "原理,进而",
21912            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21913        ),
21914        (
21915            "hello world",
21916            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21917        ),
21918        (
21919            "hello, world",
21920            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21921        ),
21922        (
21923            "  hello world",
21924            &[
21925                whitespace("  ", 2),
21926                word("hello", 5),
21927                whitespace(" ", 1),
21928                word("world", 5),
21929            ],
21930        ),
21931        (
21932            "这是什么 \n 钢笔",
21933            &[
21934                word("", 1),
21935                word("", 1),
21936                word("", 1),
21937                word("", 1),
21938                whitespace(" ", 1),
21939                newline(),
21940                whitespace(" ", 1),
21941                word("", 1),
21942                word("", 1),
21943            ],
21944        ),
21945        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21946    ];
21947
21948    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21949        WordBreakToken::Word {
21950            token,
21951            grapheme_len,
21952        }
21953    }
21954
21955    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21956        WordBreakToken::InlineWhitespace {
21957            token,
21958            grapheme_len,
21959        }
21960    }
21961
21962    fn newline() -> WordBreakToken<'static> {
21963        WordBreakToken::Newline
21964    }
21965
21966    for (input, result) in tests {
21967        assert_eq!(
21968            WordBreakingTokenizer::new(input)
21969                .collect::<Vec<_>>()
21970                .as_slice(),
21971            *result,
21972        );
21973    }
21974}
21975
21976fn wrap_with_prefix(
21977    first_line_prefix: String,
21978    subsequent_lines_prefix: String,
21979    unwrapped_text: String,
21980    wrap_column: usize,
21981    tab_size: NonZeroU32,
21982    preserve_existing_whitespace: bool,
21983) -> String {
21984    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21985    let subsequent_lines_prefix_len =
21986        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21987    let mut wrapped_text = String::new();
21988    let mut current_line = first_line_prefix;
21989    let mut is_first_line = true;
21990
21991    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21992    let mut current_line_len = first_line_prefix_len;
21993    let mut in_whitespace = false;
21994    for token in tokenizer {
21995        let have_preceding_whitespace = in_whitespace;
21996        match token {
21997            WordBreakToken::Word {
21998                token,
21999                grapheme_len,
22000            } => {
22001                in_whitespace = false;
22002                let current_prefix_len = if is_first_line {
22003                    first_line_prefix_len
22004                } else {
22005                    subsequent_lines_prefix_len
22006                };
22007                if current_line_len + grapheme_len > wrap_column
22008                    && current_line_len != current_prefix_len
22009                {
22010                    wrapped_text.push_str(current_line.trim_end());
22011                    wrapped_text.push('\n');
22012                    is_first_line = false;
22013                    current_line = subsequent_lines_prefix.clone();
22014                    current_line_len = subsequent_lines_prefix_len;
22015                }
22016                current_line.push_str(token);
22017                current_line_len += grapheme_len;
22018            }
22019            WordBreakToken::InlineWhitespace {
22020                mut token,
22021                mut grapheme_len,
22022            } => {
22023                in_whitespace = true;
22024                if have_preceding_whitespace && !preserve_existing_whitespace {
22025                    continue;
22026                }
22027                if !preserve_existing_whitespace {
22028                    token = " ";
22029                    grapheme_len = 1;
22030                }
22031                let current_prefix_len = if is_first_line {
22032                    first_line_prefix_len
22033                } else {
22034                    subsequent_lines_prefix_len
22035                };
22036                if current_line_len + grapheme_len > wrap_column {
22037                    wrapped_text.push_str(current_line.trim_end());
22038                    wrapped_text.push('\n');
22039                    is_first_line = false;
22040                    current_line = subsequent_lines_prefix.clone();
22041                    current_line_len = subsequent_lines_prefix_len;
22042                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22043                    current_line.push_str(token);
22044                    current_line_len += grapheme_len;
22045                }
22046            }
22047            WordBreakToken::Newline => {
22048                in_whitespace = true;
22049                let current_prefix_len = if is_first_line {
22050                    first_line_prefix_len
22051                } else {
22052                    subsequent_lines_prefix_len
22053                };
22054                if preserve_existing_whitespace {
22055                    wrapped_text.push_str(current_line.trim_end());
22056                    wrapped_text.push('\n');
22057                    is_first_line = false;
22058                    current_line = subsequent_lines_prefix.clone();
22059                    current_line_len = subsequent_lines_prefix_len;
22060                } else if have_preceding_whitespace {
22061                    continue;
22062                } else if current_line_len + 1 > wrap_column
22063                    && current_line_len != current_prefix_len
22064                {
22065                    wrapped_text.push_str(current_line.trim_end());
22066                    wrapped_text.push('\n');
22067                    is_first_line = false;
22068                    current_line = subsequent_lines_prefix.clone();
22069                    current_line_len = subsequent_lines_prefix_len;
22070                } else if current_line_len != current_prefix_len {
22071                    current_line.push(' ');
22072                    current_line_len += 1;
22073                }
22074            }
22075        }
22076    }
22077
22078    if !current_line.is_empty() {
22079        wrapped_text.push_str(&current_line);
22080    }
22081    wrapped_text
22082}
22083
22084#[test]
22085fn test_wrap_with_prefix() {
22086    assert_eq!(
22087        wrap_with_prefix(
22088            "# ".to_string(),
22089            "# ".to_string(),
22090            "abcdefg".to_string(),
22091            4,
22092            NonZeroU32::new(4).unwrap(),
22093            false,
22094        ),
22095        "# abcdefg"
22096    );
22097    assert_eq!(
22098        wrap_with_prefix(
22099            "".to_string(),
22100            "".to_string(),
22101            "\thello world".to_string(),
22102            8,
22103            NonZeroU32::new(4).unwrap(),
22104            false,
22105        ),
22106        "hello\nworld"
22107    );
22108    assert_eq!(
22109        wrap_with_prefix(
22110            "// ".to_string(),
22111            "// ".to_string(),
22112            "xx \nyy zz aa bb cc".to_string(),
22113            12,
22114            NonZeroU32::new(4).unwrap(),
22115            false,
22116        ),
22117        "// xx yy zz\n// aa bb cc"
22118    );
22119    assert_eq!(
22120        wrap_with_prefix(
22121            String::new(),
22122            String::new(),
22123            "这是什么 \n 钢笔".to_string(),
22124            3,
22125            NonZeroU32::new(4).unwrap(),
22126            false,
22127        ),
22128        "这是什\n么 钢\n"
22129    );
22130}
22131
22132pub trait CollaborationHub {
22133    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22134    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22135    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22136}
22137
22138impl CollaborationHub for Entity<Project> {
22139    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22140        self.read(cx).collaborators()
22141    }
22142
22143    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22144        self.read(cx).user_store().read(cx).participant_indices()
22145    }
22146
22147    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22148        let this = self.read(cx);
22149        let user_ids = this.collaborators().values().map(|c| c.user_id);
22150        this.user_store().read(cx).participant_names(user_ids, cx)
22151    }
22152}
22153
22154pub trait SemanticsProvider {
22155    fn hover(
22156        &self,
22157        buffer: &Entity<Buffer>,
22158        position: text::Anchor,
22159        cx: &mut App,
22160    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22161
22162    fn inline_values(
22163        &self,
22164        buffer_handle: Entity<Buffer>,
22165        range: Range<text::Anchor>,
22166        cx: &mut App,
22167    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22168
22169    fn inlay_hints(
22170        &self,
22171        buffer_handle: Entity<Buffer>,
22172        range: Range<text::Anchor>,
22173        cx: &mut App,
22174    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22175
22176    fn resolve_inlay_hint(
22177        &self,
22178        hint: InlayHint,
22179        buffer_handle: Entity<Buffer>,
22180        server_id: LanguageServerId,
22181        cx: &mut App,
22182    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22183
22184    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22185
22186    fn document_highlights(
22187        &self,
22188        buffer: &Entity<Buffer>,
22189        position: text::Anchor,
22190        cx: &mut App,
22191    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22192
22193    fn definitions(
22194        &self,
22195        buffer: &Entity<Buffer>,
22196        position: text::Anchor,
22197        kind: GotoDefinitionKind,
22198        cx: &mut App,
22199    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22200
22201    fn range_for_rename(
22202        &self,
22203        buffer: &Entity<Buffer>,
22204        position: text::Anchor,
22205        cx: &mut App,
22206    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22207
22208    fn perform_rename(
22209        &self,
22210        buffer: &Entity<Buffer>,
22211        position: text::Anchor,
22212        new_name: String,
22213        cx: &mut App,
22214    ) -> Option<Task<Result<ProjectTransaction>>>;
22215}
22216
22217pub trait CompletionProvider {
22218    fn completions(
22219        &self,
22220        excerpt_id: ExcerptId,
22221        buffer: &Entity<Buffer>,
22222        buffer_position: text::Anchor,
22223        trigger: CompletionContext,
22224        window: &mut Window,
22225        cx: &mut Context<Editor>,
22226    ) -> Task<Result<Vec<CompletionResponse>>>;
22227
22228    fn resolve_completions(
22229        &self,
22230        _buffer: Entity<Buffer>,
22231        _completion_indices: Vec<usize>,
22232        _completions: Rc<RefCell<Box<[Completion]>>>,
22233        _cx: &mut Context<Editor>,
22234    ) -> Task<Result<bool>> {
22235        Task::ready(Ok(false))
22236    }
22237
22238    fn apply_additional_edits_for_completion(
22239        &self,
22240        _buffer: Entity<Buffer>,
22241        _completions: Rc<RefCell<Box<[Completion]>>>,
22242        _completion_index: usize,
22243        _push_to_history: bool,
22244        _cx: &mut Context<Editor>,
22245    ) -> Task<Result<Option<language::Transaction>>> {
22246        Task::ready(Ok(None))
22247    }
22248
22249    fn is_completion_trigger(
22250        &self,
22251        buffer: &Entity<Buffer>,
22252        position: language::Anchor,
22253        text: &str,
22254        trigger_in_words: bool,
22255        menu_is_open: bool,
22256        cx: &mut Context<Editor>,
22257    ) -> bool;
22258
22259    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22260
22261    fn sort_completions(&self) -> bool {
22262        true
22263    }
22264
22265    fn filter_completions(&self) -> bool {
22266        true
22267    }
22268}
22269
22270pub trait CodeActionProvider {
22271    fn id(&self) -> Arc<str>;
22272
22273    fn code_actions(
22274        &self,
22275        buffer: &Entity<Buffer>,
22276        range: Range<text::Anchor>,
22277        window: &mut Window,
22278        cx: &mut App,
22279    ) -> Task<Result<Vec<CodeAction>>>;
22280
22281    fn apply_code_action(
22282        &self,
22283        buffer_handle: Entity<Buffer>,
22284        action: CodeAction,
22285        excerpt_id: ExcerptId,
22286        push_to_history: bool,
22287        window: &mut Window,
22288        cx: &mut App,
22289    ) -> Task<Result<ProjectTransaction>>;
22290}
22291
22292impl CodeActionProvider for Entity<Project> {
22293    fn id(&self) -> Arc<str> {
22294        "project".into()
22295    }
22296
22297    fn code_actions(
22298        &self,
22299        buffer: &Entity<Buffer>,
22300        range: Range<text::Anchor>,
22301        _window: &mut Window,
22302        cx: &mut App,
22303    ) -> Task<Result<Vec<CodeAction>>> {
22304        self.update(cx, |project, cx| {
22305            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22306            let code_actions = project.code_actions(buffer, range, None, cx);
22307            cx.background_spawn(async move {
22308                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22309                Ok(code_lens_actions
22310                    .context("code lens fetch")?
22311                    .into_iter()
22312                    .flatten()
22313                    .chain(
22314                        code_actions
22315                            .context("code action fetch")?
22316                            .into_iter()
22317                            .flatten(),
22318                    )
22319                    .collect())
22320            })
22321        })
22322    }
22323
22324    fn apply_code_action(
22325        &self,
22326        buffer_handle: Entity<Buffer>,
22327        action: CodeAction,
22328        _excerpt_id: ExcerptId,
22329        push_to_history: bool,
22330        _window: &mut Window,
22331        cx: &mut App,
22332    ) -> Task<Result<ProjectTransaction>> {
22333        self.update(cx, |project, cx| {
22334            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22335        })
22336    }
22337}
22338
22339fn snippet_completions(
22340    project: &Project,
22341    buffer: &Entity<Buffer>,
22342    buffer_position: text::Anchor,
22343    cx: &mut App,
22344) -> Task<Result<CompletionResponse>> {
22345    let languages = buffer.read(cx).languages_at(buffer_position);
22346    let snippet_store = project.snippets().read(cx);
22347
22348    let scopes: Vec<_> = languages
22349        .iter()
22350        .filter_map(|language| {
22351            let language_name = language.lsp_id();
22352            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22353
22354            if snippets.is_empty() {
22355                None
22356            } else {
22357                Some((language.default_scope(), snippets))
22358            }
22359        })
22360        .collect();
22361
22362    if scopes.is_empty() {
22363        return Task::ready(Ok(CompletionResponse {
22364            completions: vec![],
22365            display_options: CompletionDisplayOptions::default(),
22366            is_incomplete: false,
22367        }));
22368    }
22369
22370    let snapshot = buffer.read(cx).text_snapshot();
22371    let chars: String = snapshot
22372        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22373        .collect();
22374    let executor = cx.background_executor().clone();
22375
22376    cx.background_spawn(async move {
22377        let mut is_incomplete = false;
22378        let mut completions: Vec<Completion> = Vec::new();
22379        for (scope, snippets) in scopes.into_iter() {
22380            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22381            let mut last_word = chars
22382                .chars()
22383                .take_while(|c| classifier.is_word(*c))
22384                .collect::<String>();
22385            last_word = last_word.chars().rev().collect();
22386
22387            if last_word.is_empty() {
22388                return Ok(CompletionResponse {
22389                    completions: vec![],
22390                    display_options: CompletionDisplayOptions::default(),
22391                    is_incomplete: true,
22392                });
22393            }
22394
22395            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22396            let to_lsp = |point: &text::Anchor| {
22397                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22398                point_to_lsp(end)
22399            };
22400            let lsp_end = to_lsp(&buffer_position);
22401
22402            let candidates = snippets
22403                .iter()
22404                .enumerate()
22405                .flat_map(|(ix, snippet)| {
22406                    snippet
22407                        .prefix
22408                        .iter()
22409                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22410                })
22411                .collect::<Vec<StringMatchCandidate>>();
22412
22413            const MAX_RESULTS: usize = 100;
22414            let mut matches = fuzzy::match_strings(
22415                &candidates,
22416                &last_word,
22417                last_word.chars().any(|c| c.is_uppercase()),
22418                true,
22419                MAX_RESULTS,
22420                &Default::default(),
22421                executor.clone(),
22422            )
22423            .await;
22424
22425            if matches.len() >= MAX_RESULTS {
22426                is_incomplete = true;
22427            }
22428
22429            // Remove all candidates where the query's start does not match the start of any word in the candidate
22430            if let Some(query_start) = last_word.chars().next() {
22431                matches.retain(|string_match| {
22432                    split_words(&string_match.string).any(|word| {
22433                        // Check that the first codepoint of the word as lowercase matches the first
22434                        // codepoint of the query as lowercase
22435                        word.chars()
22436                            .flat_map(|codepoint| codepoint.to_lowercase())
22437                            .zip(query_start.to_lowercase())
22438                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22439                    })
22440                });
22441            }
22442
22443            let matched_strings = matches
22444                .into_iter()
22445                .map(|m| m.string)
22446                .collect::<HashSet<_>>();
22447
22448            completions.extend(snippets.iter().filter_map(|snippet| {
22449                let matching_prefix = snippet
22450                    .prefix
22451                    .iter()
22452                    .find(|prefix| matched_strings.contains(*prefix))?;
22453                let start = as_offset - last_word.len();
22454                let start = snapshot.anchor_before(start);
22455                let range = start..buffer_position;
22456                let lsp_start = to_lsp(&start);
22457                let lsp_range = lsp::Range {
22458                    start: lsp_start,
22459                    end: lsp_end,
22460                };
22461                Some(Completion {
22462                    replace_range: range,
22463                    new_text: snippet.body.clone(),
22464                    source: CompletionSource::Lsp {
22465                        insert_range: None,
22466                        server_id: LanguageServerId(usize::MAX),
22467                        resolved: true,
22468                        lsp_completion: Box::new(lsp::CompletionItem {
22469                            label: snippet.prefix.first().unwrap().clone(),
22470                            kind: Some(CompletionItemKind::SNIPPET),
22471                            label_details: snippet.description.as_ref().map(|description| {
22472                                lsp::CompletionItemLabelDetails {
22473                                    detail: Some(description.clone()),
22474                                    description: None,
22475                                }
22476                            }),
22477                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22478                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22479                                lsp::InsertReplaceEdit {
22480                                    new_text: snippet.body.clone(),
22481                                    insert: lsp_range,
22482                                    replace: lsp_range,
22483                                },
22484                            )),
22485                            filter_text: Some(snippet.body.clone()),
22486                            sort_text: Some(char::MAX.to_string()),
22487                            ..lsp::CompletionItem::default()
22488                        }),
22489                        lsp_defaults: None,
22490                    },
22491                    label: CodeLabel {
22492                        text: matching_prefix.clone(),
22493                        runs: Vec::new(),
22494                        filter_range: 0..matching_prefix.len(),
22495                    },
22496                    icon_path: None,
22497                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22498                        single_line: snippet.name.clone().into(),
22499                        plain_text: snippet
22500                            .description
22501                            .clone()
22502                            .map(|description| description.into()),
22503                    }),
22504                    insert_text_mode: None,
22505                    confirm: None,
22506                })
22507            }))
22508        }
22509
22510        Ok(CompletionResponse {
22511            completions,
22512            display_options: CompletionDisplayOptions::default(),
22513            is_incomplete,
22514        })
22515    })
22516}
22517
22518impl CompletionProvider for Entity<Project> {
22519    fn completions(
22520        &self,
22521        _excerpt_id: ExcerptId,
22522        buffer: &Entity<Buffer>,
22523        buffer_position: text::Anchor,
22524        options: CompletionContext,
22525        _window: &mut Window,
22526        cx: &mut Context<Editor>,
22527    ) -> Task<Result<Vec<CompletionResponse>>> {
22528        self.update(cx, |project, cx| {
22529            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22530            let project_completions = project.completions(buffer, buffer_position, options, cx);
22531            cx.background_spawn(async move {
22532                let mut responses = project_completions.await?;
22533                let snippets = snippets.await?;
22534                if !snippets.completions.is_empty() {
22535                    responses.push(snippets);
22536                }
22537                Ok(responses)
22538            })
22539        })
22540    }
22541
22542    fn resolve_completions(
22543        &self,
22544        buffer: Entity<Buffer>,
22545        completion_indices: Vec<usize>,
22546        completions: Rc<RefCell<Box<[Completion]>>>,
22547        cx: &mut Context<Editor>,
22548    ) -> Task<Result<bool>> {
22549        self.update(cx, |project, cx| {
22550            project.lsp_store().update(cx, |lsp_store, cx| {
22551                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22552            })
22553        })
22554    }
22555
22556    fn apply_additional_edits_for_completion(
22557        &self,
22558        buffer: Entity<Buffer>,
22559        completions: Rc<RefCell<Box<[Completion]>>>,
22560        completion_index: usize,
22561        push_to_history: bool,
22562        cx: &mut Context<Editor>,
22563    ) -> Task<Result<Option<language::Transaction>>> {
22564        self.update(cx, |project, cx| {
22565            project.lsp_store().update(cx, |lsp_store, cx| {
22566                lsp_store.apply_additional_edits_for_completion(
22567                    buffer,
22568                    completions,
22569                    completion_index,
22570                    push_to_history,
22571                    cx,
22572                )
22573            })
22574        })
22575    }
22576
22577    fn is_completion_trigger(
22578        &self,
22579        buffer: &Entity<Buffer>,
22580        position: language::Anchor,
22581        text: &str,
22582        trigger_in_words: bool,
22583        menu_is_open: bool,
22584        cx: &mut Context<Editor>,
22585    ) -> bool {
22586        let mut chars = text.chars();
22587        let char = if let Some(char) = chars.next() {
22588            char
22589        } else {
22590            return false;
22591        };
22592        if chars.next().is_some() {
22593            return false;
22594        }
22595
22596        let buffer = buffer.read(cx);
22597        let snapshot = buffer.snapshot();
22598        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22599            return false;
22600        }
22601        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22602        if trigger_in_words && classifier.is_word(char) {
22603            return true;
22604        }
22605
22606        buffer.completion_triggers().contains(text)
22607    }
22608}
22609
22610impl SemanticsProvider for Entity<Project> {
22611    fn hover(
22612        &self,
22613        buffer: &Entity<Buffer>,
22614        position: text::Anchor,
22615        cx: &mut App,
22616    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22617        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22618    }
22619
22620    fn document_highlights(
22621        &self,
22622        buffer: &Entity<Buffer>,
22623        position: text::Anchor,
22624        cx: &mut App,
22625    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22626        Some(self.update(cx, |project, cx| {
22627            project.document_highlights(buffer, position, cx)
22628        }))
22629    }
22630
22631    fn definitions(
22632        &self,
22633        buffer: &Entity<Buffer>,
22634        position: text::Anchor,
22635        kind: GotoDefinitionKind,
22636        cx: &mut App,
22637    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22638        Some(self.update(cx, |project, cx| match kind {
22639            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22640            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22641            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22642            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22643        }))
22644    }
22645
22646    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22647        self.update(cx, |project, cx| {
22648            if project
22649                .active_debug_session(cx)
22650                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22651            {
22652                return true;
22653            }
22654
22655            buffer.update(cx, |buffer, cx| {
22656                project.any_language_server_supports_inlay_hints(buffer, cx)
22657            })
22658        })
22659    }
22660
22661    fn inline_values(
22662        &self,
22663        buffer_handle: Entity<Buffer>,
22664        range: Range<text::Anchor>,
22665        cx: &mut App,
22666    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22667        self.update(cx, |project, cx| {
22668            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22669
22670            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22671        })
22672    }
22673
22674    fn inlay_hints(
22675        &self,
22676        buffer_handle: Entity<Buffer>,
22677        range: Range<text::Anchor>,
22678        cx: &mut App,
22679    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22680        Some(self.update(cx, |project, cx| {
22681            project.inlay_hints(buffer_handle, range, cx)
22682        }))
22683    }
22684
22685    fn resolve_inlay_hint(
22686        &self,
22687        hint: InlayHint,
22688        buffer_handle: Entity<Buffer>,
22689        server_id: LanguageServerId,
22690        cx: &mut App,
22691    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22692        Some(self.update(cx, |project, cx| {
22693            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22694        }))
22695    }
22696
22697    fn range_for_rename(
22698        &self,
22699        buffer: &Entity<Buffer>,
22700        position: text::Anchor,
22701        cx: &mut App,
22702    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22703        Some(self.update(cx, |project, cx| {
22704            let buffer = buffer.clone();
22705            let task = project.prepare_rename(buffer.clone(), position, cx);
22706            cx.spawn(async move |_, cx| {
22707                Ok(match task.await? {
22708                    PrepareRenameResponse::Success(range) => Some(range),
22709                    PrepareRenameResponse::InvalidPosition => None,
22710                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22711                        // Fallback on using TreeSitter info to determine identifier range
22712                        buffer.read_with(cx, |buffer, _| {
22713                            let snapshot = buffer.snapshot();
22714                            let (range, kind) = snapshot.surrounding_word(position, false);
22715                            if kind != Some(CharKind::Word) {
22716                                return None;
22717                            }
22718                            Some(
22719                                snapshot.anchor_before(range.start)
22720                                    ..snapshot.anchor_after(range.end),
22721                            )
22722                        })?
22723                    }
22724                })
22725            })
22726        }))
22727    }
22728
22729    fn perform_rename(
22730        &self,
22731        buffer: &Entity<Buffer>,
22732        position: text::Anchor,
22733        new_name: String,
22734        cx: &mut App,
22735    ) -> Option<Task<Result<ProjectTransaction>>> {
22736        Some(self.update(cx, |project, cx| {
22737            project.perform_rename(buffer.clone(), position, new_name, cx)
22738        }))
22739    }
22740}
22741
22742fn inlay_hint_settings(
22743    location: Anchor,
22744    snapshot: &MultiBufferSnapshot,
22745    cx: &mut Context<Editor>,
22746) -> InlayHintSettings {
22747    let file = snapshot.file_at(location);
22748    let language = snapshot.language_at(location).map(|l| l.name());
22749    language_settings(language, file, cx).inlay_hints
22750}
22751
22752fn consume_contiguous_rows(
22753    contiguous_row_selections: &mut Vec<Selection<Point>>,
22754    selection: &Selection<Point>,
22755    display_map: &DisplaySnapshot,
22756    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22757) -> (MultiBufferRow, MultiBufferRow) {
22758    contiguous_row_selections.push(selection.clone());
22759    let start_row = starting_row(selection, display_map);
22760    let mut end_row = ending_row(selection, display_map);
22761
22762    while let Some(next_selection) = selections.peek() {
22763        if next_selection.start.row <= end_row.0 {
22764            end_row = ending_row(next_selection, display_map);
22765            contiguous_row_selections.push(selections.next().unwrap().clone());
22766        } else {
22767            break;
22768        }
22769    }
22770    (start_row, end_row)
22771}
22772
22773fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22774    if selection.start.column > 0 {
22775        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22776    } else {
22777        MultiBufferRow(selection.start.row)
22778    }
22779}
22780
22781fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22782    if next_selection.end.column > 0 || next_selection.is_empty() {
22783        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22784    } else {
22785        MultiBufferRow(next_selection.end.row)
22786    }
22787}
22788
22789impl EditorSnapshot {
22790    pub fn remote_selections_in_range<'a>(
22791        &'a self,
22792        range: &'a Range<Anchor>,
22793        collaboration_hub: &dyn CollaborationHub,
22794        cx: &'a App,
22795    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22796        let participant_names = collaboration_hub.user_names(cx);
22797        let participant_indices = collaboration_hub.user_participant_indices(cx);
22798        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22799        let collaborators_by_replica_id = collaborators_by_peer_id
22800            .values()
22801            .map(|collaborator| (collaborator.replica_id, collaborator))
22802            .collect::<HashMap<_, _>>();
22803        self.buffer_snapshot
22804            .selections_in_range(range, false)
22805            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22806                if replica_id == AGENT_REPLICA_ID {
22807                    Some(RemoteSelection {
22808                        replica_id,
22809                        selection,
22810                        cursor_shape,
22811                        line_mode,
22812                        collaborator_id: CollaboratorId::Agent,
22813                        user_name: Some("Agent".into()),
22814                        color: cx.theme().players().agent(),
22815                    })
22816                } else {
22817                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22818                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22819                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22820                    Some(RemoteSelection {
22821                        replica_id,
22822                        selection,
22823                        cursor_shape,
22824                        line_mode,
22825                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22826                        user_name,
22827                        color: if let Some(index) = participant_index {
22828                            cx.theme().players().color_for_participant(index.0)
22829                        } else {
22830                            cx.theme().players().absent()
22831                        },
22832                    })
22833                }
22834            })
22835    }
22836
22837    pub fn hunks_for_ranges(
22838        &self,
22839        ranges: impl IntoIterator<Item = Range<Point>>,
22840    ) -> Vec<MultiBufferDiffHunk> {
22841        let mut hunks = Vec::new();
22842        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22843            HashMap::default();
22844        for query_range in ranges {
22845            let query_rows =
22846                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22847            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22848                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22849            ) {
22850                // Include deleted hunks that are adjacent to the query range, because
22851                // otherwise they would be missed.
22852                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22853                if hunk.status().is_deleted() {
22854                    intersects_range |= hunk.row_range.start == query_rows.end;
22855                    intersects_range |= hunk.row_range.end == query_rows.start;
22856                }
22857                if intersects_range {
22858                    if !processed_buffer_rows
22859                        .entry(hunk.buffer_id)
22860                        .or_default()
22861                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22862                    {
22863                        continue;
22864                    }
22865                    hunks.push(hunk);
22866                }
22867            }
22868        }
22869
22870        hunks
22871    }
22872
22873    fn display_diff_hunks_for_rows<'a>(
22874        &'a self,
22875        display_rows: Range<DisplayRow>,
22876        folded_buffers: &'a HashSet<BufferId>,
22877    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22878        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22879        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22880
22881        self.buffer_snapshot
22882            .diff_hunks_in_range(buffer_start..buffer_end)
22883            .filter_map(|hunk| {
22884                if folded_buffers.contains(&hunk.buffer_id) {
22885                    return None;
22886                }
22887
22888                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22889                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22890
22891                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22892                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22893
22894                let display_hunk = if hunk_display_start.column() != 0 {
22895                    DisplayDiffHunk::Folded {
22896                        display_row: hunk_display_start.row(),
22897                    }
22898                } else {
22899                    let mut end_row = hunk_display_end.row();
22900                    if hunk_display_end.column() > 0 {
22901                        end_row.0 += 1;
22902                    }
22903                    let is_created_file = hunk.is_created_file();
22904                    DisplayDiffHunk::Unfolded {
22905                        status: hunk.status(),
22906                        diff_base_byte_range: hunk.diff_base_byte_range,
22907                        display_row_range: hunk_display_start.row()..end_row,
22908                        multi_buffer_range: Anchor::range_in_buffer(
22909                            hunk.excerpt_id,
22910                            hunk.buffer_id,
22911                            hunk.buffer_range,
22912                        ),
22913                        is_created_file,
22914                    }
22915                };
22916
22917                Some(display_hunk)
22918            })
22919    }
22920
22921    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22922        self.display_snapshot.buffer_snapshot.language_at(position)
22923    }
22924
22925    pub fn is_focused(&self) -> bool {
22926        self.is_focused
22927    }
22928
22929    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22930        self.placeholder_text.as_ref()
22931    }
22932
22933    pub fn scroll_position(&self) -> gpui::Point<f32> {
22934        self.scroll_anchor.scroll_position(&self.display_snapshot)
22935    }
22936
22937    fn gutter_dimensions(
22938        &self,
22939        font_id: FontId,
22940        font_size: Pixels,
22941        max_line_number_width: Pixels,
22942        cx: &App,
22943    ) -> Option<GutterDimensions> {
22944        if !self.show_gutter {
22945            return None;
22946        }
22947
22948        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22949        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22950
22951        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22952            matches!(
22953                ProjectSettings::get_global(cx).git.git_gutter,
22954                Some(GitGutterSetting::TrackedFiles)
22955            )
22956        });
22957        let gutter_settings = EditorSettings::get_global(cx).gutter;
22958        let show_line_numbers = self
22959            .show_line_numbers
22960            .unwrap_or(gutter_settings.line_numbers);
22961        let line_gutter_width = if show_line_numbers {
22962            // Avoid flicker-like gutter resizes when the line number gains another digit by
22963            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22964            let min_width_for_number_on_gutter =
22965                ch_advance * gutter_settings.min_line_number_digits as f32;
22966            max_line_number_width.max(min_width_for_number_on_gutter)
22967        } else {
22968            0.0.into()
22969        };
22970
22971        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22972        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22973
22974        let git_blame_entries_width =
22975            self.git_blame_gutter_max_author_length
22976                .map(|max_author_length| {
22977                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22978                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22979
22980                    /// The number of characters to dedicate to gaps and margins.
22981                    const SPACING_WIDTH: usize = 4;
22982
22983                    let max_char_count = max_author_length.min(renderer.max_author_length())
22984                        + ::git::SHORT_SHA_LENGTH
22985                        + MAX_RELATIVE_TIMESTAMP.len()
22986                        + SPACING_WIDTH;
22987
22988                    ch_advance * max_char_count
22989                });
22990
22991        let is_singleton = self.buffer_snapshot.is_singleton();
22992
22993        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22994        left_padding += if !is_singleton {
22995            ch_width * 4.0
22996        } else if show_runnables || show_breakpoints {
22997            ch_width * 3.0
22998        } else if show_git_gutter && show_line_numbers {
22999            ch_width * 2.0
23000        } else if show_git_gutter || show_line_numbers {
23001            ch_width
23002        } else {
23003            px(0.)
23004        };
23005
23006        let shows_folds = is_singleton && gutter_settings.folds;
23007
23008        let right_padding = if shows_folds && show_line_numbers {
23009            ch_width * 4.0
23010        } else if shows_folds || (!is_singleton && show_line_numbers) {
23011            ch_width * 3.0
23012        } else if show_line_numbers {
23013            ch_width
23014        } else {
23015            px(0.)
23016        };
23017
23018        Some(GutterDimensions {
23019            left_padding,
23020            right_padding,
23021            width: line_gutter_width + left_padding + right_padding,
23022            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23023            git_blame_entries_width,
23024        })
23025    }
23026
23027    pub fn render_crease_toggle(
23028        &self,
23029        buffer_row: MultiBufferRow,
23030        row_contains_cursor: bool,
23031        editor: Entity<Editor>,
23032        window: &mut Window,
23033        cx: &mut App,
23034    ) -> Option<AnyElement> {
23035        let folded = self.is_line_folded(buffer_row);
23036        let mut is_foldable = false;
23037
23038        if let Some(crease) = self
23039            .crease_snapshot
23040            .query_row(buffer_row, &self.buffer_snapshot)
23041        {
23042            is_foldable = true;
23043            match crease {
23044                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23045                    if let Some(render_toggle) = render_toggle {
23046                        let toggle_callback =
23047                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23048                                if folded {
23049                                    editor.update(cx, |editor, cx| {
23050                                        editor.fold_at(buffer_row, window, cx)
23051                                    });
23052                                } else {
23053                                    editor.update(cx, |editor, cx| {
23054                                        editor.unfold_at(buffer_row, window, cx)
23055                                    });
23056                                }
23057                            });
23058                        return Some((render_toggle)(
23059                            buffer_row,
23060                            folded,
23061                            toggle_callback,
23062                            window,
23063                            cx,
23064                        ));
23065                    }
23066                }
23067            }
23068        }
23069
23070        is_foldable |= self.starts_indent(buffer_row);
23071
23072        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23073            Some(
23074                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23075                    .toggle_state(folded)
23076                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23077                        if folded {
23078                            this.unfold_at(buffer_row, window, cx);
23079                        } else {
23080                            this.fold_at(buffer_row, window, cx);
23081                        }
23082                    }))
23083                    .into_any_element(),
23084            )
23085        } else {
23086            None
23087        }
23088    }
23089
23090    pub fn render_crease_trailer(
23091        &self,
23092        buffer_row: MultiBufferRow,
23093        window: &mut Window,
23094        cx: &mut App,
23095    ) -> Option<AnyElement> {
23096        let folded = self.is_line_folded(buffer_row);
23097        if let Crease::Inline { render_trailer, .. } = self
23098            .crease_snapshot
23099            .query_row(buffer_row, &self.buffer_snapshot)?
23100        {
23101            let render_trailer = render_trailer.as_ref()?;
23102            Some(render_trailer(buffer_row, folded, window, cx))
23103        } else {
23104            None
23105        }
23106    }
23107}
23108
23109impl Deref for EditorSnapshot {
23110    type Target = DisplaySnapshot;
23111
23112    fn deref(&self) -> &Self::Target {
23113        &self.display_snapshot
23114    }
23115}
23116
23117#[derive(Clone, Debug, PartialEq, Eq)]
23118pub enum EditorEvent {
23119    InputIgnored {
23120        text: Arc<str>,
23121    },
23122    InputHandled {
23123        utf16_range_to_replace: Option<Range<isize>>,
23124        text: Arc<str>,
23125    },
23126    ExcerptsAdded {
23127        buffer: Entity<Buffer>,
23128        predecessor: ExcerptId,
23129        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23130    },
23131    ExcerptsRemoved {
23132        ids: Vec<ExcerptId>,
23133        removed_buffer_ids: Vec<BufferId>,
23134    },
23135    BufferFoldToggled {
23136        ids: Vec<ExcerptId>,
23137        folded: bool,
23138    },
23139    ExcerptsEdited {
23140        ids: Vec<ExcerptId>,
23141    },
23142    ExcerptsExpanded {
23143        ids: Vec<ExcerptId>,
23144    },
23145    BufferEdited,
23146    Edited {
23147        transaction_id: clock::Lamport,
23148    },
23149    Reparsed(BufferId),
23150    Focused,
23151    FocusedIn,
23152    Blurred,
23153    DirtyChanged,
23154    Saved,
23155    TitleChanged,
23156    SelectionsChanged {
23157        local: bool,
23158    },
23159    ScrollPositionChanged {
23160        local: bool,
23161        autoscroll: bool,
23162    },
23163    TransactionUndone {
23164        transaction_id: clock::Lamport,
23165    },
23166    TransactionBegun {
23167        transaction_id: clock::Lamport,
23168    },
23169    CursorShapeChanged,
23170    BreadcrumbsChanged,
23171    PushedToNavHistory {
23172        anchor: Anchor,
23173        is_deactivate: bool,
23174    },
23175}
23176
23177impl EventEmitter<EditorEvent> for Editor {}
23178
23179impl Focusable for Editor {
23180    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23181        self.focus_handle.clone()
23182    }
23183}
23184
23185impl Render for Editor {
23186    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23187        let settings = ThemeSettings::get_global(cx);
23188
23189        let mut text_style = match self.mode {
23190            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23191                color: cx.theme().colors().editor_foreground,
23192                font_family: settings.ui_font.family.clone(),
23193                font_features: settings.ui_font.features.clone(),
23194                font_fallbacks: settings.ui_font.fallbacks.clone(),
23195                font_size: rems(0.875).into(),
23196                font_weight: settings.ui_font.weight,
23197                line_height: relative(settings.buffer_line_height.value()),
23198                ..Default::default()
23199            },
23200            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23201                color: cx.theme().colors().editor_foreground,
23202                font_family: settings.buffer_font.family.clone(),
23203                font_features: settings.buffer_font.features.clone(),
23204                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23205                font_size: settings.buffer_font_size(cx).into(),
23206                font_weight: settings.buffer_font.weight,
23207                line_height: relative(settings.buffer_line_height.value()),
23208                ..Default::default()
23209            },
23210        };
23211        if let Some(text_style_refinement) = &self.text_style_refinement {
23212            text_style.refine(text_style_refinement)
23213        }
23214
23215        let background = match self.mode {
23216            EditorMode::SingleLine => cx.theme().system().transparent,
23217            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23218            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23219            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23220        };
23221
23222        EditorElement::new(
23223            &cx.entity(),
23224            EditorStyle {
23225                background,
23226                border: cx.theme().colors().border,
23227                local_player: cx.theme().players().local(),
23228                text: text_style,
23229                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23230                syntax: cx.theme().syntax().clone(),
23231                status: cx.theme().status().clone(),
23232                inlay_hints_style: make_inlay_hints_style(cx),
23233                edit_prediction_styles: make_suggestion_styles(cx),
23234                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23235                show_underlines: self.diagnostics_enabled(),
23236            },
23237        )
23238    }
23239}
23240
23241impl EntityInputHandler for Editor {
23242    fn text_for_range(
23243        &mut self,
23244        range_utf16: Range<usize>,
23245        adjusted_range: &mut Option<Range<usize>>,
23246        _: &mut Window,
23247        cx: &mut Context<Self>,
23248    ) -> Option<String> {
23249        let snapshot = self.buffer.read(cx).read(cx);
23250        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23251        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23252        if (start.0..end.0) != range_utf16 {
23253            adjusted_range.replace(start.0..end.0);
23254        }
23255        Some(snapshot.text_for_range(start..end).collect())
23256    }
23257
23258    fn selected_text_range(
23259        &mut self,
23260        ignore_disabled_input: bool,
23261        _: &mut Window,
23262        cx: &mut Context<Self>,
23263    ) -> Option<UTF16Selection> {
23264        // Prevent the IME menu from appearing when holding down an alphabetic key
23265        // while input is disabled.
23266        if !ignore_disabled_input && !self.input_enabled {
23267            return None;
23268        }
23269
23270        let selection = self.selections.newest::<OffsetUtf16>(cx);
23271        let range = selection.range();
23272
23273        Some(UTF16Selection {
23274            range: range.start.0..range.end.0,
23275            reversed: selection.reversed,
23276        })
23277    }
23278
23279    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23280        let snapshot = self.buffer.read(cx).read(cx);
23281        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23282        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23283    }
23284
23285    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23286        self.clear_highlights::<InputComposition>(cx);
23287        self.ime_transaction.take();
23288    }
23289
23290    fn replace_text_in_range(
23291        &mut self,
23292        range_utf16: Option<Range<usize>>,
23293        text: &str,
23294        window: &mut Window,
23295        cx: &mut Context<Self>,
23296    ) {
23297        if !self.input_enabled {
23298            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23299            return;
23300        }
23301
23302        self.transact(window, cx, |this, window, cx| {
23303            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23304                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23305                Some(this.selection_replacement_ranges(range_utf16, cx))
23306            } else {
23307                this.marked_text_ranges(cx)
23308            };
23309
23310            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23311                let newest_selection_id = this.selections.newest_anchor().id;
23312                this.selections
23313                    .all::<OffsetUtf16>(cx)
23314                    .iter()
23315                    .zip(ranges_to_replace.iter())
23316                    .find_map(|(selection, range)| {
23317                        if selection.id == newest_selection_id {
23318                            Some(
23319                                (range.start.0 as isize - selection.head().0 as isize)
23320                                    ..(range.end.0 as isize - selection.head().0 as isize),
23321                            )
23322                        } else {
23323                            None
23324                        }
23325                    })
23326            });
23327
23328            cx.emit(EditorEvent::InputHandled {
23329                utf16_range_to_replace: range_to_replace,
23330                text: text.into(),
23331            });
23332
23333            if let Some(new_selected_ranges) = new_selected_ranges {
23334                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23335                    selections.select_ranges(new_selected_ranges)
23336                });
23337                this.backspace(&Default::default(), window, cx);
23338            }
23339
23340            this.handle_input(text, window, cx);
23341        });
23342
23343        if let Some(transaction) = self.ime_transaction {
23344            self.buffer.update(cx, |buffer, cx| {
23345                buffer.group_until_transaction(transaction, cx);
23346            });
23347        }
23348
23349        self.unmark_text(window, cx);
23350    }
23351
23352    fn replace_and_mark_text_in_range(
23353        &mut self,
23354        range_utf16: Option<Range<usize>>,
23355        text: &str,
23356        new_selected_range_utf16: Option<Range<usize>>,
23357        window: &mut Window,
23358        cx: &mut Context<Self>,
23359    ) {
23360        if !self.input_enabled {
23361            return;
23362        }
23363
23364        let transaction = self.transact(window, cx, |this, window, cx| {
23365            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23366                let snapshot = this.buffer.read(cx).read(cx);
23367                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23368                    for marked_range in &mut marked_ranges {
23369                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23370                        marked_range.start.0 += relative_range_utf16.start;
23371                        marked_range.start =
23372                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23373                        marked_range.end =
23374                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23375                    }
23376                }
23377                Some(marked_ranges)
23378            } else if let Some(range_utf16) = range_utf16 {
23379                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23380                Some(this.selection_replacement_ranges(range_utf16, cx))
23381            } else {
23382                None
23383            };
23384
23385            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23386                let newest_selection_id = this.selections.newest_anchor().id;
23387                this.selections
23388                    .all::<OffsetUtf16>(cx)
23389                    .iter()
23390                    .zip(ranges_to_replace.iter())
23391                    .find_map(|(selection, range)| {
23392                        if selection.id == newest_selection_id {
23393                            Some(
23394                                (range.start.0 as isize - selection.head().0 as isize)
23395                                    ..(range.end.0 as isize - selection.head().0 as isize),
23396                            )
23397                        } else {
23398                            None
23399                        }
23400                    })
23401            });
23402
23403            cx.emit(EditorEvent::InputHandled {
23404                utf16_range_to_replace: range_to_replace,
23405                text: text.into(),
23406            });
23407
23408            if let Some(ranges) = ranges_to_replace {
23409                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23410                    s.select_ranges(ranges)
23411                });
23412            }
23413
23414            let marked_ranges = {
23415                let snapshot = this.buffer.read(cx).read(cx);
23416                this.selections
23417                    .disjoint_anchors()
23418                    .iter()
23419                    .map(|selection| {
23420                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23421                    })
23422                    .collect::<Vec<_>>()
23423            };
23424
23425            if text.is_empty() {
23426                this.unmark_text(window, cx);
23427            } else {
23428                this.highlight_text::<InputComposition>(
23429                    marked_ranges.clone(),
23430                    HighlightStyle {
23431                        underline: Some(UnderlineStyle {
23432                            thickness: px(1.),
23433                            color: None,
23434                            wavy: false,
23435                        }),
23436                        ..Default::default()
23437                    },
23438                    cx,
23439                );
23440            }
23441
23442            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23443            let use_autoclose = this.use_autoclose;
23444            let use_auto_surround = this.use_auto_surround;
23445            this.set_use_autoclose(false);
23446            this.set_use_auto_surround(false);
23447            this.handle_input(text, window, cx);
23448            this.set_use_autoclose(use_autoclose);
23449            this.set_use_auto_surround(use_auto_surround);
23450
23451            if let Some(new_selected_range) = new_selected_range_utf16 {
23452                let snapshot = this.buffer.read(cx).read(cx);
23453                let new_selected_ranges = marked_ranges
23454                    .into_iter()
23455                    .map(|marked_range| {
23456                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23457                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23458                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23459                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23460                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23461                    })
23462                    .collect::<Vec<_>>();
23463
23464                drop(snapshot);
23465                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23466                    selections.select_ranges(new_selected_ranges)
23467                });
23468            }
23469        });
23470
23471        self.ime_transaction = self.ime_transaction.or(transaction);
23472        if let Some(transaction) = self.ime_transaction {
23473            self.buffer.update(cx, |buffer, cx| {
23474                buffer.group_until_transaction(transaction, cx);
23475            });
23476        }
23477
23478        if self.text_highlights::<InputComposition>(cx).is_none() {
23479            self.ime_transaction.take();
23480        }
23481    }
23482
23483    fn bounds_for_range(
23484        &mut self,
23485        range_utf16: Range<usize>,
23486        element_bounds: gpui::Bounds<Pixels>,
23487        window: &mut Window,
23488        cx: &mut Context<Self>,
23489    ) -> Option<gpui::Bounds<Pixels>> {
23490        let text_layout_details = self.text_layout_details(window);
23491        let CharacterDimensions {
23492            em_width,
23493            em_advance,
23494            line_height,
23495        } = self.character_dimensions(window);
23496
23497        let snapshot = self.snapshot(window, cx);
23498        let scroll_position = snapshot.scroll_position();
23499        let scroll_left = scroll_position.x * em_advance;
23500
23501        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23502        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23503            + self.gutter_dimensions.full_width();
23504        let y = line_height * (start.row().as_f32() - scroll_position.y);
23505
23506        Some(Bounds {
23507            origin: element_bounds.origin + point(x, y),
23508            size: size(em_width, line_height),
23509        })
23510    }
23511
23512    fn character_index_for_point(
23513        &mut self,
23514        point: gpui::Point<Pixels>,
23515        _window: &mut Window,
23516        _cx: &mut Context<Self>,
23517    ) -> Option<usize> {
23518        let position_map = self.last_position_map.as_ref()?;
23519        if !position_map.text_hitbox.contains(&point) {
23520            return None;
23521        }
23522        let display_point = position_map.point_for_position(point).previous_valid;
23523        let anchor = position_map
23524            .snapshot
23525            .display_point_to_anchor(display_point, Bias::Left);
23526        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23527        Some(utf16_offset.0)
23528    }
23529}
23530
23531trait SelectionExt {
23532    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23533    fn spanned_rows(
23534        &self,
23535        include_end_if_at_line_start: bool,
23536        map: &DisplaySnapshot,
23537    ) -> Range<MultiBufferRow>;
23538}
23539
23540impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23541    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23542        let start = self
23543            .start
23544            .to_point(&map.buffer_snapshot)
23545            .to_display_point(map);
23546        let end = self
23547            .end
23548            .to_point(&map.buffer_snapshot)
23549            .to_display_point(map);
23550        if self.reversed {
23551            end..start
23552        } else {
23553            start..end
23554        }
23555    }
23556
23557    fn spanned_rows(
23558        &self,
23559        include_end_if_at_line_start: bool,
23560        map: &DisplaySnapshot,
23561    ) -> Range<MultiBufferRow> {
23562        let start = self.start.to_point(&map.buffer_snapshot);
23563        let mut end = self.end.to_point(&map.buffer_snapshot);
23564        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23565            end.row -= 1;
23566        }
23567
23568        let buffer_start = map.prev_line_boundary(start).0;
23569        let buffer_end = map.next_line_boundary(end).0;
23570        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23571    }
23572}
23573
23574impl<T: InvalidationRegion> InvalidationStack<T> {
23575    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23576    where
23577        S: Clone + ToOffset,
23578    {
23579        while let Some(region) = self.last() {
23580            let all_selections_inside_invalidation_ranges =
23581                if selections.len() == region.ranges().len() {
23582                    selections
23583                        .iter()
23584                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23585                        .all(|(selection, invalidation_range)| {
23586                            let head = selection.head().to_offset(buffer);
23587                            invalidation_range.start <= head && invalidation_range.end >= head
23588                        })
23589                } else {
23590                    false
23591                };
23592
23593            if all_selections_inside_invalidation_ranges {
23594                break;
23595            } else {
23596                self.pop();
23597            }
23598        }
23599    }
23600}
23601
23602impl<T> Default for InvalidationStack<T> {
23603    fn default() -> Self {
23604        Self(Default::default())
23605    }
23606}
23607
23608impl<T> Deref for InvalidationStack<T> {
23609    type Target = Vec<T>;
23610
23611    fn deref(&self) -> &Self::Target {
23612        &self.0
23613    }
23614}
23615
23616impl<T> DerefMut for InvalidationStack<T> {
23617    fn deref_mut(&mut self) -> &mut Self::Target {
23618        &mut self.0
23619    }
23620}
23621
23622impl InvalidationRegion for SnippetState {
23623    fn ranges(&self) -> &[Range<Anchor>] {
23624        &self.ranges[self.active_index]
23625    }
23626}
23627
23628fn edit_prediction_edit_text(
23629    current_snapshot: &BufferSnapshot,
23630    edits: &[(Range<Anchor>, String)],
23631    edit_preview: &EditPreview,
23632    include_deletions: bool,
23633    cx: &App,
23634) -> HighlightedText {
23635    let edits = edits
23636        .iter()
23637        .map(|(anchor, text)| {
23638            (
23639                anchor.start.text_anchor..anchor.end.text_anchor,
23640                text.clone(),
23641            )
23642        })
23643        .collect::<Vec<_>>();
23644
23645    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23646}
23647
23648fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23649    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23650    // Just show the raw edit text with basic styling
23651    let mut text = String::new();
23652    let mut highlights = Vec::new();
23653
23654    let insertion_highlight_style = HighlightStyle {
23655        color: Some(cx.theme().colors().text),
23656        ..Default::default()
23657    };
23658
23659    for (_, edit_text) in edits {
23660        let start_offset = text.len();
23661        text.push_str(edit_text);
23662        let end_offset = text.len();
23663
23664        if start_offset < end_offset {
23665            highlights.push((start_offset..end_offset, insertion_highlight_style));
23666        }
23667    }
23668
23669    HighlightedText {
23670        text: text.into(),
23671        highlights,
23672    }
23673}
23674
23675pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23676    match severity {
23677        lsp::DiagnosticSeverity::ERROR => colors.error,
23678        lsp::DiagnosticSeverity::WARNING => colors.warning,
23679        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23680        lsp::DiagnosticSeverity::HINT => colors.info,
23681        _ => colors.ignored,
23682    }
23683}
23684
23685pub fn styled_runs_for_code_label<'a>(
23686    label: &'a CodeLabel,
23687    syntax_theme: &'a theme::SyntaxTheme,
23688) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23689    let fade_out = HighlightStyle {
23690        fade_out: Some(0.35),
23691        ..Default::default()
23692    };
23693
23694    let mut prev_end = label.filter_range.end;
23695    label
23696        .runs
23697        .iter()
23698        .enumerate()
23699        .flat_map(move |(ix, (range, highlight_id))| {
23700            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23701                style
23702            } else {
23703                return Default::default();
23704            };
23705            let mut muted_style = style;
23706            muted_style.highlight(fade_out);
23707
23708            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23709            if range.start >= label.filter_range.end {
23710                if range.start > prev_end {
23711                    runs.push((prev_end..range.start, fade_out));
23712                }
23713                runs.push((range.clone(), muted_style));
23714            } else if range.end <= label.filter_range.end {
23715                runs.push((range.clone(), style));
23716            } else {
23717                runs.push((range.start..label.filter_range.end, style));
23718                runs.push((label.filter_range.end..range.end, muted_style));
23719            }
23720            prev_end = cmp::max(prev_end, range.end);
23721
23722            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23723                runs.push((prev_end..label.text.len(), fade_out));
23724            }
23725
23726            runs
23727        })
23728}
23729
23730pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23731    let mut prev_index = 0;
23732    let mut prev_codepoint: Option<char> = None;
23733    text.char_indices()
23734        .chain([(text.len(), '\0')])
23735        .filter_map(move |(index, codepoint)| {
23736            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23737            let is_boundary = index == text.len()
23738                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23739                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23740            if is_boundary {
23741                let chunk = &text[prev_index..index];
23742                prev_index = index;
23743                Some(chunk)
23744            } else {
23745                None
23746            }
23747        })
23748}
23749
23750pub trait RangeToAnchorExt: Sized {
23751    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23752
23753    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23754        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23755        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23756    }
23757}
23758
23759impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23760    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23761        let start_offset = self.start.to_offset(snapshot);
23762        let end_offset = self.end.to_offset(snapshot);
23763        if start_offset == end_offset {
23764            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23765        } else {
23766            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23767        }
23768    }
23769}
23770
23771pub trait RowExt {
23772    fn as_f32(&self) -> f32;
23773
23774    fn next_row(&self) -> Self;
23775
23776    fn previous_row(&self) -> Self;
23777
23778    fn minus(&self, other: Self) -> u32;
23779}
23780
23781impl RowExt for DisplayRow {
23782    fn as_f32(&self) -> f32 {
23783        self.0 as f32
23784    }
23785
23786    fn next_row(&self) -> Self {
23787        Self(self.0 + 1)
23788    }
23789
23790    fn previous_row(&self) -> Self {
23791        Self(self.0.saturating_sub(1))
23792    }
23793
23794    fn minus(&self, other: Self) -> u32 {
23795        self.0 - other.0
23796    }
23797}
23798
23799impl RowExt for MultiBufferRow {
23800    fn as_f32(&self) -> f32 {
23801        self.0 as f32
23802    }
23803
23804    fn next_row(&self) -> Self {
23805        Self(self.0 + 1)
23806    }
23807
23808    fn previous_row(&self) -> Self {
23809        Self(self.0.saturating_sub(1))
23810    }
23811
23812    fn minus(&self, other: Self) -> u32 {
23813        self.0 - other.0
23814    }
23815}
23816
23817trait RowRangeExt {
23818    type Row;
23819
23820    fn len(&self) -> usize;
23821
23822    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23823}
23824
23825impl RowRangeExt for Range<MultiBufferRow> {
23826    type Row = MultiBufferRow;
23827
23828    fn len(&self) -> usize {
23829        (self.end.0 - self.start.0) as usize
23830    }
23831
23832    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23833        (self.start.0..self.end.0).map(MultiBufferRow)
23834    }
23835}
23836
23837impl RowRangeExt for Range<DisplayRow> {
23838    type Row = DisplayRow;
23839
23840    fn len(&self) -> usize {
23841        (self.end.0 - self.start.0) as usize
23842    }
23843
23844    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23845        (self.start.0..self.end.0).map(DisplayRow)
23846    }
23847}
23848
23849/// If select range has more than one line, we
23850/// just point the cursor to range.start.
23851fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23852    if range.start.row == range.end.row {
23853        range
23854    } else {
23855        range.start..range.start
23856    }
23857}
23858pub struct KillRing(ClipboardItem);
23859impl Global for KillRing {}
23860
23861const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23862
23863enum BreakpointPromptEditAction {
23864    Log,
23865    Condition,
23866    HitCondition,
23867}
23868
23869struct BreakpointPromptEditor {
23870    pub(crate) prompt: Entity<Editor>,
23871    editor: WeakEntity<Editor>,
23872    breakpoint_anchor: Anchor,
23873    breakpoint: Breakpoint,
23874    edit_action: BreakpointPromptEditAction,
23875    block_ids: HashSet<CustomBlockId>,
23876    editor_margins: Arc<Mutex<EditorMargins>>,
23877    _subscriptions: Vec<Subscription>,
23878}
23879
23880impl BreakpointPromptEditor {
23881    const MAX_LINES: u8 = 4;
23882
23883    fn new(
23884        editor: WeakEntity<Editor>,
23885        breakpoint_anchor: Anchor,
23886        breakpoint: Breakpoint,
23887        edit_action: BreakpointPromptEditAction,
23888        window: &mut Window,
23889        cx: &mut Context<Self>,
23890    ) -> Self {
23891        let base_text = match edit_action {
23892            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23893            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23894            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23895        }
23896        .map(|msg| msg.to_string())
23897        .unwrap_or_default();
23898
23899        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23900        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23901
23902        let prompt = cx.new(|cx| {
23903            let mut prompt = Editor::new(
23904                EditorMode::AutoHeight {
23905                    min_lines: 1,
23906                    max_lines: Some(Self::MAX_LINES as usize),
23907                },
23908                buffer,
23909                None,
23910                window,
23911                cx,
23912            );
23913            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23914            prompt.set_show_cursor_when_unfocused(false, cx);
23915            prompt.set_placeholder_text(
23916                match edit_action {
23917                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23918                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23919                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23920                },
23921                cx,
23922            );
23923
23924            prompt
23925        });
23926
23927        Self {
23928            prompt,
23929            editor,
23930            breakpoint_anchor,
23931            breakpoint,
23932            edit_action,
23933            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23934            block_ids: Default::default(),
23935            _subscriptions: vec![],
23936        }
23937    }
23938
23939    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23940        self.block_ids.extend(block_ids)
23941    }
23942
23943    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23944        if let Some(editor) = self.editor.upgrade() {
23945            let message = self
23946                .prompt
23947                .read(cx)
23948                .buffer
23949                .read(cx)
23950                .as_singleton()
23951                .expect("A multi buffer in breakpoint prompt isn't possible")
23952                .read(cx)
23953                .as_rope()
23954                .to_string();
23955
23956            editor.update(cx, |editor, cx| {
23957                editor.edit_breakpoint_at_anchor(
23958                    self.breakpoint_anchor,
23959                    self.breakpoint.clone(),
23960                    match self.edit_action {
23961                        BreakpointPromptEditAction::Log => {
23962                            BreakpointEditAction::EditLogMessage(message.into())
23963                        }
23964                        BreakpointPromptEditAction::Condition => {
23965                            BreakpointEditAction::EditCondition(message.into())
23966                        }
23967                        BreakpointPromptEditAction::HitCondition => {
23968                            BreakpointEditAction::EditHitCondition(message.into())
23969                        }
23970                    },
23971                    cx,
23972                );
23973
23974                editor.remove_blocks(self.block_ids.clone(), None, cx);
23975                cx.focus_self(window);
23976            });
23977        }
23978    }
23979
23980    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23981        self.editor
23982            .update(cx, |editor, cx| {
23983                editor.remove_blocks(self.block_ids.clone(), None, cx);
23984                window.focus(&editor.focus_handle);
23985            })
23986            .log_err();
23987    }
23988
23989    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23990        let settings = ThemeSettings::get_global(cx);
23991        let text_style = TextStyle {
23992            color: if self.prompt.read(cx).read_only(cx) {
23993                cx.theme().colors().text_disabled
23994            } else {
23995                cx.theme().colors().text
23996            },
23997            font_family: settings.buffer_font.family.clone(),
23998            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23999            font_size: settings.buffer_font_size(cx).into(),
24000            font_weight: settings.buffer_font.weight,
24001            line_height: relative(settings.buffer_line_height.value()),
24002            ..Default::default()
24003        };
24004        EditorElement::new(
24005            &self.prompt,
24006            EditorStyle {
24007                background: cx.theme().colors().editor_background,
24008                local_player: cx.theme().players().local(),
24009                text: text_style,
24010                ..Default::default()
24011            },
24012        )
24013    }
24014}
24015
24016impl Render for BreakpointPromptEditor {
24017    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24018        let editor_margins = *self.editor_margins.lock();
24019        let gutter_dimensions = editor_margins.gutter;
24020        h_flex()
24021            .key_context("Editor")
24022            .bg(cx.theme().colors().editor_background)
24023            .border_y_1()
24024            .border_color(cx.theme().status().info_border)
24025            .size_full()
24026            .py(window.line_height() / 2.5)
24027            .on_action(cx.listener(Self::confirm))
24028            .on_action(cx.listener(Self::cancel))
24029            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24030            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24031    }
24032}
24033
24034impl Focusable for BreakpointPromptEditor {
24035    fn focus_handle(&self, cx: &App) -> FocusHandle {
24036        self.prompt.focus_handle(cx)
24037    }
24038}
24039
24040fn all_edits_insertions_or_deletions(
24041    edits: &Vec<(Range<Anchor>, String)>,
24042    snapshot: &MultiBufferSnapshot,
24043) -> bool {
24044    let mut all_insertions = true;
24045    let mut all_deletions = true;
24046
24047    for (range, new_text) in edits.iter() {
24048        let range_is_empty = range.to_offset(snapshot).is_empty();
24049        let text_is_empty = new_text.is_empty();
24050
24051        if range_is_empty != text_is_empty {
24052            if range_is_empty {
24053                all_deletions = false;
24054            } else {
24055                all_insertions = false;
24056            }
24057        } else {
24058            return false;
24059        }
24060
24061        if !all_insertions && !all_deletions {
24062            return false;
24063        }
24064    }
24065    all_insertions || all_deletions
24066}
24067
24068struct MissingEditPredictionKeybindingTooltip;
24069
24070impl Render for MissingEditPredictionKeybindingTooltip {
24071    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24072        ui::tooltip_container(window, cx, |container, _, cx| {
24073            container
24074                .flex_shrink_0()
24075                .max_w_80()
24076                .min_h(rems_from_px(124.))
24077                .justify_between()
24078                .child(
24079                    v_flex()
24080                        .flex_1()
24081                        .text_ui_sm(cx)
24082                        .child(Label::new("Conflict with Accept Keybinding"))
24083                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24084                )
24085                .child(
24086                    h_flex()
24087                        .pb_1()
24088                        .gap_1()
24089                        .items_end()
24090                        .w_full()
24091                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24092                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24093                        }))
24094                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24095                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24096                        })),
24097                )
24098        })
24099    }
24100}
24101
24102#[derive(Debug, Clone, Copy, PartialEq)]
24103pub struct LineHighlight {
24104    pub background: Background,
24105    pub border: Option<gpui::Hsla>,
24106    pub include_gutter: bool,
24107    pub type_id: Option<TypeId>,
24108}
24109
24110struct LineManipulationResult {
24111    pub new_text: String,
24112    pub line_count_before: usize,
24113    pub line_count_after: usize,
24114}
24115
24116fn render_diff_hunk_controls(
24117    row: u32,
24118    status: &DiffHunkStatus,
24119    hunk_range: Range<Anchor>,
24120    is_created_file: bool,
24121    line_height: Pixels,
24122    editor: &Entity<Editor>,
24123    _window: &mut Window,
24124    cx: &mut App,
24125) -> AnyElement {
24126    h_flex()
24127        .h(line_height)
24128        .mr_1()
24129        .gap_1()
24130        .px_0p5()
24131        .pb_1()
24132        .border_x_1()
24133        .border_b_1()
24134        .border_color(cx.theme().colors().border_variant)
24135        .rounded_b_lg()
24136        .bg(cx.theme().colors().editor_background)
24137        .gap_1()
24138        .block_mouse_except_scroll()
24139        .shadow_md()
24140        .child(if status.has_secondary_hunk() {
24141            Button::new(("stage", row as u64), "Stage")
24142                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24143                .tooltip({
24144                    let focus_handle = editor.focus_handle(cx);
24145                    move |window, cx| {
24146                        Tooltip::for_action_in(
24147                            "Stage Hunk",
24148                            &::git::ToggleStaged,
24149                            &focus_handle,
24150                            window,
24151                            cx,
24152                        )
24153                    }
24154                })
24155                .on_click({
24156                    let editor = editor.clone();
24157                    move |_event, _window, cx| {
24158                        editor.update(cx, |editor, cx| {
24159                            editor.stage_or_unstage_diff_hunks(
24160                                true,
24161                                vec![hunk_range.start..hunk_range.start],
24162                                cx,
24163                            );
24164                        });
24165                    }
24166                })
24167        } else {
24168            Button::new(("unstage", row as u64), "Unstage")
24169                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24170                .tooltip({
24171                    let focus_handle = editor.focus_handle(cx);
24172                    move |window, cx| {
24173                        Tooltip::for_action_in(
24174                            "Unstage Hunk",
24175                            &::git::ToggleStaged,
24176                            &focus_handle,
24177                            window,
24178                            cx,
24179                        )
24180                    }
24181                })
24182                .on_click({
24183                    let editor = editor.clone();
24184                    move |_event, _window, cx| {
24185                        editor.update(cx, |editor, cx| {
24186                            editor.stage_or_unstage_diff_hunks(
24187                                false,
24188                                vec![hunk_range.start..hunk_range.start],
24189                                cx,
24190                            );
24191                        });
24192                    }
24193                })
24194        })
24195        .child(
24196            Button::new(("restore", row as u64), "Restore")
24197                .tooltip({
24198                    let focus_handle = editor.focus_handle(cx);
24199                    move |window, cx| {
24200                        Tooltip::for_action_in(
24201                            "Restore Hunk",
24202                            &::git::Restore,
24203                            &focus_handle,
24204                            window,
24205                            cx,
24206                        )
24207                    }
24208                })
24209                .on_click({
24210                    let editor = editor.clone();
24211                    move |_event, window, cx| {
24212                        editor.update(cx, |editor, cx| {
24213                            let snapshot = editor.snapshot(window, cx);
24214                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24215                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24216                        });
24217                    }
24218                })
24219                .disabled(is_created_file),
24220        )
24221        .when(
24222            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24223            |el| {
24224                el.child(
24225                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24226                        .shape(IconButtonShape::Square)
24227                        .icon_size(IconSize::Small)
24228                        // .disabled(!has_multiple_hunks)
24229                        .tooltip({
24230                            let focus_handle = editor.focus_handle(cx);
24231                            move |window, cx| {
24232                                Tooltip::for_action_in(
24233                                    "Next Hunk",
24234                                    &GoToHunk,
24235                                    &focus_handle,
24236                                    window,
24237                                    cx,
24238                                )
24239                            }
24240                        })
24241                        .on_click({
24242                            let editor = editor.clone();
24243                            move |_event, window, cx| {
24244                                editor.update(cx, |editor, cx| {
24245                                    let snapshot = editor.snapshot(window, cx);
24246                                    let position =
24247                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24248                                    editor.go_to_hunk_before_or_after_position(
24249                                        &snapshot,
24250                                        position,
24251                                        Direction::Next,
24252                                        window,
24253                                        cx,
24254                                    );
24255                                    editor.expand_selected_diff_hunks(cx);
24256                                });
24257                            }
24258                        }),
24259                )
24260                .child(
24261                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24262                        .shape(IconButtonShape::Square)
24263                        .icon_size(IconSize::Small)
24264                        // .disabled(!has_multiple_hunks)
24265                        .tooltip({
24266                            let focus_handle = editor.focus_handle(cx);
24267                            move |window, cx| {
24268                                Tooltip::for_action_in(
24269                                    "Previous Hunk",
24270                                    &GoToPreviousHunk,
24271                                    &focus_handle,
24272                                    window,
24273                                    cx,
24274                                )
24275                            }
24276                        })
24277                        .on_click({
24278                            let editor = editor.clone();
24279                            move |_event, window, cx| {
24280                                editor.update(cx, |editor, cx| {
24281                                    let snapshot = editor.snapshot(window, cx);
24282                                    let point =
24283                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24284                                    editor.go_to_hunk_before_or_after_position(
24285                                        &snapshot,
24286                                        point,
24287                                        Direction::Prev,
24288                                        window,
24289                                        cx,
24290                                    );
24291                                    editor.expand_selected_diff_hunks(cx);
24292                                });
24293                            }
24294                        }),
24295                )
24296            },
24297        )
24298        .into_any_element()
24299}
24300
24301pub fn multibuffer_context_lines(cx: &App) -> u32 {
24302    EditorSettings::try_get(cx)
24303        .map(|settings| settings.excerpt_context_lines)
24304        .unwrap_or(2)
24305        .clamp(1, 32)
24306}