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)) = buffer.syntax_ancestor(new_range.clone())
14950                {
14951                    if !node.is_named() {
14952                        new_range = node.start_byte()..node.end_byte();
14953                        continue;
14954                    }
14955
14956                    new_range = match containing_range {
14957                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14958                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14959                    };
14960                    if !display_map.intersects_fold(new_range.start)
14961                        && !display_map.intersects_fold(new_range.end)
14962                    {
14963                        break;
14964                    }
14965                }
14966
14967                selected_larger_node |= new_range != old_range;
14968                Selection {
14969                    id: selection.id,
14970                    start: new_range.start,
14971                    end: new_range.end,
14972                    goal: SelectionGoal::None,
14973                    reversed: selection.reversed,
14974                }
14975            })
14976            .collect::<Vec<_>>();
14977
14978        if !selected_larger_node {
14979            return; // don't put this call in the history
14980        }
14981
14982        // scroll based on transformation done to the last selection created by the user
14983        let (last_old, last_new) = old_selections
14984            .last()
14985            .zip(new_selections.last().cloned())
14986            .expect("old_selections isn't empty");
14987
14988        // revert selection
14989        let is_selection_reversed = {
14990            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14991            new_selections.last_mut().expect("checked above").reversed =
14992                should_newest_selection_be_reversed;
14993            should_newest_selection_be_reversed
14994        };
14995
14996        if selected_larger_node {
14997            self.select_syntax_node_history.disable_clearing = true;
14998            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14999                s.select(new_selections.clone());
15000            });
15001            self.select_syntax_node_history.disable_clearing = false;
15002        }
15003
15004        let start_row = last_new.start.to_display_point(&display_map).row().0;
15005        let end_row = last_new.end.to_display_point(&display_map).row().0;
15006        let selection_height = end_row - start_row + 1;
15007        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15008
15009        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15010        let scroll_behavior = if fits_on_the_screen {
15011            self.request_autoscroll(Autoscroll::fit(), cx);
15012            SelectSyntaxNodeScrollBehavior::FitSelection
15013        } else if is_selection_reversed {
15014            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15015            SelectSyntaxNodeScrollBehavior::CursorTop
15016        } else {
15017            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15018            SelectSyntaxNodeScrollBehavior::CursorBottom
15019        };
15020
15021        self.select_syntax_node_history.push((
15022            old_selections,
15023            scroll_behavior,
15024            is_selection_reversed,
15025        ));
15026    }
15027
15028    pub fn select_smaller_syntax_node(
15029        &mut self,
15030        _: &SelectSmallerSyntaxNode,
15031        window: &mut Window,
15032        cx: &mut Context<Self>,
15033    ) {
15034        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15035
15036        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15037            self.select_syntax_node_history.pop()
15038        {
15039            if let Some(selection) = selections.last_mut() {
15040                selection.reversed = is_selection_reversed;
15041            }
15042
15043            self.select_syntax_node_history.disable_clearing = true;
15044            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15045                s.select(selections.to_vec());
15046            });
15047            self.select_syntax_node_history.disable_clearing = false;
15048
15049            match scroll_behavior {
15050                SelectSyntaxNodeScrollBehavior::CursorTop => {
15051                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15052                }
15053                SelectSyntaxNodeScrollBehavior::FitSelection => {
15054                    self.request_autoscroll(Autoscroll::fit(), cx);
15055                }
15056                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15057                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15058                }
15059            }
15060        }
15061    }
15062
15063    pub fn unwrap_syntax_node(
15064        &mut self,
15065        _: &UnwrapSyntaxNode,
15066        window: &mut Window,
15067        cx: &mut Context<Self>,
15068    ) {
15069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15070
15071        let buffer = self.buffer.read(cx).snapshot(cx);
15072        let selections = self
15073            .selections
15074            .all::<usize>(cx)
15075            .into_iter()
15076            // subtracting the offset requires sorting
15077            .sorted_by_key(|i| i.start);
15078
15079        let full_edits = selections
15080            .into_iter()
15081            .filter_map(|selection| {
15082                // Only requires two branches once if-let-chains stabilize (#53667)
15083                let child = if !selection.is_empty() {
15084                    selection.range()
15085                } else if let Some((_, ancestor_range)) =
15086                    buffer.syntax_ancestor(selection.start..selection.end)
15087                {
15088                    match ancestor_range {
15089                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15090                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15091                    }
15092                } else {
15093                    selection.range()
15094                };
15095
15096                let mut parent = child.clone();
15097                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15098                    parent = match ancestor_range {
15099                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15100                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15101                    };
15102                    if parent.start < child.start || parent.end > child.end {
15103                        break;
15104                    }
15105                }
15106
15107                if parent == child {
15108                    return None;
15109                }
15110                let text = buffer.text_for_range(child).collect::<String>();
15111                Some((selection.id, parent, text))
15112            })
15113            .collect::<Vec<_>>();
15114
15115        self.transact(window, cx, |this, window, cx| {
15116            this.buffer.update(cx, |buffer, cx| {
15117                buffer.edit(
15118                    full_edits
15119                        .iter()
15120                        .map(|(_, p, t)| (p.clone(), t.clone()))
15121                        .collect::<Vec<_>>(),
15122                    None,
15123                    cx,
15124                );
15125            });
15126            this.change_selections(Default::default(), window, cx, |s| {
15127                let mut offset = 0;
15128                let mut selections = vec![];
15129                for (id, parent, text) in full_edits {
15130                    let start = parent.start - offset;
15131                    offset += parent.len() - text.len();
15132                    selections.push(Selection {
15133                        id,
15134                        start,
15135                        end: start + text.len(),
15136                        reversed: false,
15137                        goal: Default::default(),
15138                    });
15139                }
15140                s.select(selections);
15141            });
15142        });
15143    }
15144
15145    pub fn select_next_syntax_node(
15146        &mut self,
15147        _: &SelectNextSyntaxNode,
15148        window: &mut Window,
15149        cx: &mut Context<Self>,
15150    ) {
15151        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15152        if old_selections.is_empty() {
15153            return;
15154        }
15155
15156        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15157
15158        let buffer = self.buffer.read(cx).snapshot(cx);
15159        let mut selected_sibling = false;
15160
15161        let new_selections = old_selections
15162            .iter()
15163            .map(|selection| {
15164                let old_range = selection.start..selection.end;
15165
15166                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15167                    let new_range = node.byte_range();
15168                    selected_sibling = true;
15169                    Selection {
15170                        id: selection.id,
15171                        start: new_range.start,
15172                        end: new_range.end,
15173                        goal: SelectionGoal::None,
15174                        reversed: selection.reversed,
15175                    }
15176                } else {
15177                    selection.clone()
15178                }
15179            })
15180            .collect::<Vec<_>>();
15181
15182        if selected_sibling {
15183            self.change_selections(
15184                SelectionEffects::scroll(Autoscroll::fit()),
15185                window,
15186                cx,
15187                |s| {
15188                    s.select(new_selections);
15189                },
15190            );
15191        }
15192    }
15193
15194    pub fn select_prev_syntax_node(
15195        &mut self,
15196        _: &SelectPreviousSyntaxNode,
15197        window: &mut Window,
15198        cx: &mut Context<Self>,
15199    ) {
15200        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15201        if old_selections.is_empty() {
15202            return;
15203        }
15204
15205        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15206
15207        let buffer = self.buffer.read(cx).snapshot(cx);
15208        let mut selected_sibling = false;
15209
15210        let new_selections = old_selections
15211            .iter()
15212            .map(|selection| {
15213                let old_range = selection.start..selection.end;
15214
15215                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15216                    let new_range = node.byte_range();
15217                    selected_sibling = true;
15218                    Selection {
15219                        id: selection.id,
15220                        start: new_range.start,
15221                        end: new_range.end,
15222                        goal: SelectionGoal::None,
15223                        reversed: selection.reversed,
15224                    }
15225                } else {
15226                    selection.clone()
15227                }
15228            })
15229            .collect::<Vec<_>>();
15230
15231        if selected_sibling {
15232            self.change_selections(
15233                SelectionEffects::scroll(Autoscroll::fit()),
15234                window,
15235                cx,
15236                |s| {
15237                    s.select(new_selections);
15238                },
15239            );
15240        }
15241    }
15242
15243    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15244        if !EditorSettings::get_global(cx).gutter.runnables {
15245            self.clear_tasks();
15246            return Task::ready(());
15247        }
15248        let project = self.project().map(Entity::downgrade);
15249        let task_sources = self.lsp_task_sources(cx);
15250        let multi_buffer = self.buffer.downgrade();
15251        cx.spawn_in(window, async move |editor, cx| {
15252            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15253            let Some(project) = project.and_then(|p| p.upgrade()) else {
15254                return;
15255            };
15256            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15257                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15258            }) else {
15259                return;
15260            };
15261
15262            let hide_runnables = project
15263                .update(cx, |project, _| project.is_via_collab())
15264                .unwrap_or(true);
15265            if hide_runnables {
15266                return;
15267            }
15268            let new_rows =
15269                cx.background_spawn({
15270                    let snapshot = display_snapshot.clone();
15271                    async move {
15272                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15273                    }
15274                })
15275                    .await;
15276            let Ok(lsp_tasks) =
15277                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15278            else {
15279                return;
15280            };
15281            let lsp_tasks = lsp_tasks.await;
15282
15283            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15284                lsp_tasks
15285                    .into_iter()
15286                    .flat_map(|(kind, tasks)| {
15287                        tasks.into_iter().filter_map(move |(location, task)| {
15288                            Some((kind.clone(), location?, task))
15289                        })
15290                    })
15291                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15292                        let buffer = location.target.buffer;
15293                        let buffer_snapshot = buffer.read(cx).snapshot();
15294                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15295                            |(excerpt_id, snapshot, _)| {
15296                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15297                                    display_snapshot
15298                                        .buffer_snapshot
15299                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15300                                } else {
15301                                    None
15302                                }
15303                            },
15304                        );
15305                        if let Some(offset) = offset {
15306                            let task_buffer_range =
15307                                location.target.range.to_point(&buffer_snapshot);
15308                            let context_buffer_range =
15309                                task_buffer_range.to_offset(&buffer_snapshot);
15310                            let context_range = BufferOffset(context_buffer_range.start)
15311                                ..BufferOffset(context_buffer_range.end);
15312
15313                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15314                                .or_insert_with(|| RunnableTasks {
15315                                    templates: Vec::new(),
15316                                    offset,
15317                                    column: task_buffer_range.start.column,
15318                                    extra_variables: HashMap::default(),
15319                                    context_range,
15320                                })
15321                                .templates
15322                                .push((kind, task.original_task().clone()));
15323                        }
15324
15325                        acc
15326                    })
15327            }) else {
15328                return;
15329            };
15330
15331            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15332                buffer.language_settings(cx).tasks.prefer_lsp
15333            }) else {
15334                return;
15335            };
15336
15337            let rows = Self::runnable_rows(
15338                project,
15339                display_snapshot,
15340                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15341                new_rows,
15342                cx.clone(),
15343            )
15344            .await;
15345            editor
15346                .update(cx, |editor, _| {
15347                    editor.clear_tasks();
15348                    for (key, mut value) in rows {
15349                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15350                            value.templates.extend(lsp_tasks.templates);
15351                        }
15352
15353                        editor.insert_tasks(key, value);
15354                    }
15355                    for (key, value) in lsp_tasks_by_rows {
15356                        editor.insert_tasks(key, value);
15357                    }
15358                })
15359                .ok();
15360        })
15361    }
15362    fn fetch_runnable_ranges(
15363        snapshot: &DisplaySnapshot,
15364        range: Range<Anchor>,
15365    ) -> Vec<language::RunnableRange> {
15366        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15367    }
15368
15369    fn runnable_rows(
15370        project: Entity<Project>,
15371        snapshot: DisplaySnapshot,
15372        prefer_lsp: bool,
15373        runnable_ranges: Vec<RunnableRange>,
15374        cx: AsyncWindowContext,
15375    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15376        cx.spawn(async move |cx| {
15377            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15378            for mut runnable in runnable_ranges {
15379                let Some(tasks) = cx
15380                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15381                    .ok()
15382                else {
15383                    continue;
15384                };
15385                let mut tasks = tasks.await;
15386
15387                if prefer_lsp {
15388                    tasks.retain(|(task_kind, _)| {
15389                        !matches!(task_kind, TaskSourceKind::Language { .. })
15390                    });
15391                }
15392                if tasks.is_empty() {
15393                    continue;
15394                }
15395
15396                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15397                let Some(row) = snapshot
15398                    .buffer_snapshot
15399                    .buffer_line_for_row(MultiBufferRow(point.row))
15400                    .map(|(_, range)| range.start.row)
15401                else {
15402                    continue;
15403                };
15404
15405                let context_range =
15406                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15407                runnable_rows.push((
15408                    (runnable.buffer_id, row),
15409                    RunnableTasks {
15410                        templates: tasks,
15411                        offset: snapshot
15412                            .buffer_snapshot
15413                            .anchor_before(runnable.run_range.start),
15414                        context_range,
15415                        column: point.column,
15416                        extra_variables: runnable.extra_captures,
15417                    },
15418                ));
15419            }
15420            runnable_rows
15421        })
15422    }
15423
15424    fn templates_with_tags(
15425        project: &Entity<Project>,
15426        runnable: &mut Runnable,
15427        cx: &mut App,
15428    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15429        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15430            let (worktree_id, file) = project
15431                .buffer_for_id(runnable.buffer, cx)
15432                .and_then(|buffer| buffer.read(cx).file())
15433                .map(|file| (file.worktree_id(cx), file.clone()))
15434                .unzip();
15435
15436            (
15437                project.task_store().read(cx).task_inventory().cloned(),
15438                worktree_id,
15439                file,
15440            )
15441        });
15442
15443        let tags = mem::take(&mut runnable.tags);
15444        let language = runnable.language.clone();
15445        cx.spawn(async move |cx| {
15446            let mut templates_with_tags = Vec::new();
15447            if let Some(inventory) = inventory {
15448                for RunnableTag(tag) in tags {
15449                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15450                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15451                    }) else {
15452                        return templates_with_tags;
15453                    };
15454                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15455                        move |(_, template)| {
15456                            template.tags.iter().any(|source_tag| source_tag == &tag)
15457                        },
15458                    ));
15459                }
15460            }
15461            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15462
15463            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15464                // Strongest source wins; if we have worktree tag binding, prefer that to
15465                // global and language bindings;
15466                // if we have a global binding, prefer that to language binding.
15467                let first_mismatch = templates_with_tags
15468                    .iter()
15469                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15470                if let Some(index) = first_mismatch {
15471                    templates_with_tags.truncate(index);
15472                }
15473            }
15474
15475            templates_with_tags
15476        })
15477    }
15478
15479    pub fn move_to_enclosing_bracket(
15480        &mut self,
15481        _: &MoveToEnclosingBracket,
15482        window: &mut Window,
15483        cx: &mut Context<Self>,
15484    ) {
15485        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15486        self.change_selections(Default::default(), window, cx, |s| {
15487            s.move_offsets_with(|snapshot, selection| {
15488                let Some(enclosing_bracket_ranges) =
15489                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15490                else {
15491                    return;
15492                };
15493
15494                let mut best_length = usize::MAX;
15495                let mut best_inside = false;
15496                let mut best_in_bracket_range = false;
15497                let mut best_destination = None;
15498                for (open, close) in enclosing_bracket_ranges {
15499                    let close = close.to_inclusive();
15500                    let length = close.end() - open.start;
15501                    let inside = selection.start >= open.end && selection.end <= *close.start();
15502                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15503                        || close.contains(&selection.head());
15504
15505                    // If best is next to a bracket and current isn't, skip
15506                    if !in_bracket_range && best_in_bracket_range {
15507                        continue;
15508                    }
15509
15510                    // Prefer smaller lengths unless best is inside and current isn't
15511                    if length > best_length && (best_inside || !inside) {
15512                        continue;
15513                    }
15514
15515                    best_length = length;
15516                    best_inside = inside;
15517                    best_in_bracket_range = in_bracket_range;
15518                    best_destination = Some(
15519                        if close.contains(&selection.start) && close.contains(&selection.end) {
15520                            if inside { open.end } else { open.start }
15521                        } else if inside {
15522                            *close.start()
15523                        } else {
15524                            *close.end()
15525                        },
15526                    );
15527                }
15528
15529                if let Some(destination) = best_destination {
15530                    selection.collapse_to(destination, SelectionGoal::None);
15531                }
15532            })
15533        });
15534    }
15535
15536    pub fn undo_selection(
15537        &mut self,
15538        _: &UndoSelection,
15539        window: &mut Window,
15540        cx: &mut Context<Self>,
15541    ) {
15542        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15543        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15544            self.selection_history.mode = SelectionHistoryMode::Undoing;
15545            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15546                this.end_selection(window, cx);
15547                this.change_selections(
15548                    SelectionEffects::scroll(Autoscroll::newest()),
15549                    window,
15550                    cx,
15551                    |s| s.select_anchors(entry.selections.to_vec()),
15552                );
15553            });
15554            self.selection_history.mode = SelectionHistoryMode::Normal;
15555
15556            self.select_next_state = entry.select_next_state;
15557            self.select_prev_state = entry.select_prev_state;
15558            self.add_selections_state = entry.add_selections_state;
15559        }
15560    }
15561
15562    pub fn redo_selection(
15563        &mut self,
15564        _: &RedoSelection,
15565        window: &mut Window,
15566        cx: &mut Context<Self>,
15567    ) {
15568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15569        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15570            self.selection_history.mode = SelectionHistoryMode::Redoing;
15571            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15572                this.end_selection(window, cx);
15573                this.change_selections(
15574                    SelectionEffects::scroll(Autoscroll::newest()),
15575                    window,
15576                    cx,
15577                    |s| s.select_anchors(entry.selections.to_vec()),
15578                );
15579            });
15580            self.selection_history.mode = SelectionHistoryMode::Normal;
15581
15582            self.select_next_state = entry.select_next_state;
15583            self.select_prev_state = entry.select_prev_state;
15584            self.add_selections_state = entry.add_selections_state;
15585        }
15586    }
15587
15588    pub fn expand_excerpts(
15589        &mut self,
15590        action: &ExpandExcerpts,
15591        _: &mut Window,
15592        cx: &mut Context<Self>,
15593    ) {
15594        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15595    }
15596
15597    pub fn expand_excerpts_down(
15598        &mut self,
15599        action: &ExpandExcerptsDown,
15600        _: &mut Window,
15601        cx: &mut Context<Self>,
15602    ) {
15603        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15604    }
15605
15606    pub fn expand_excerpts_up(
15607        &mut self,
15608        action: &ExpandExcerptsUp,
15609        _: &mut Window,
15610        cx: &mut Context<Self>,
15611    ) {
15612        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15613    }
15614
15615    pub fn expand_excerpts_for_direction(
15616        &mut self,
15617        lines: u32,
15618        direction: ExpandExcerptDirection,
15619
15620        cx: &mut Context<Self>,
15621    ) {
15622        let selections = self.selections.disjoint_anchors();
15623
15624        let lines = if lines == 0 {
15625            EditorSettings::get_global(cx).expand_excerpt_lines
15626        } else {
15627            lines
15628        };
15629
15630        self.buffer.update(cx, |buffer, cx| {
15631            let snapshot = buffer.snapshot(cx);
15632            let mut excerpt_ids = selections
15633                .iter()
15634                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15635                .collect::<Vec<_>>();
15636            excerpt_ids.sort();
15637            excerpt_ids.dedup();
15638            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15639        })
15640    }
15641
15642    pub fn expand_excerpt(
15643        &mut self,
15644        excerpt: ExcerptId,
15645        direction: ExpandExcerptDirection,
15646        window: &mut Window,
15647        cx: &mut Context<Self>,
15648    ) {
15649        let current_scroll_position = self.scroll_position(cx);
15650        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15651        let mut should_scroll_up = false;
15652
15653        if direction == ExpandExcerptDirection::Down {
15654            let multi_buffer = self.buffer.read(cx);
15655            let snapshot = multi_buffer.snapshot(cx);
15656            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15657                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15658                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15659            {
15660                let buffer_snapshot = buffer.read(cx).snapshot();
15661                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15662                let last_row = buffer_snapshot.max_point().row;
15663                let lines_below = last_row.saturating_sub(excerpt_end_row);
15664                should_scroll_up = lines_below >= lines_to_expand;
15665            }
15666        }
15667
15668        self.buffer.update(cx, |buffer, cx| {
15669            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15670        });
15671
15672        if should_scroll_up {
15673            let new_scroll_position =
15674                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15675            self.set_scroll_position(new_scroll_position, window, cx);
15676        }
15677    }
15678
15679    pub fn go_to_singleton_buffer_point(
15680        &mut self,
15681        point: Point,
15682        window: &mut Window,
15683        cx: &mut Context<Self>,
15684    ) {
15685        self.go_to_singleton_buffer_range(point..point, window, cx);
15686    }
15687
15688    pub fn go_to_singleton_buffer_range(
15689        &mut self,
15690        range: Range<Point>,
15691        window: &mut Window,
15692        cx: &mut Context<Self>,
15693    ) {
15694        let multibuffer = self.buffer().read(cx);
15695        let Some(buffer) = multibuffer.as_singleton() else {
15696            return;
15697        };
15698        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15699            return;
15700        };
15701        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15702            return;
15703        };
15704        self.change_selections(
15705            SelectionEffects::default().nav_history(true),
15706            window,
15707            cx,
15708            |s| s.select_anchor_ranges([start..end]),
15709        );
15710    }
15711
15712    pub fn go_to_diagnostic(
15713        &mut self,
15714        action: &GoToDiagnostic,
15715        window: &mut Window,
15716        cx: &mut Context<Self>,
15717    ) {
15718        if !self.diagnostics_enabled() {
15719            return;
15720        }
15721        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15722        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15723    }
15724
15725    pub fn go_to_prev_diagnostic(
15726        &mut self,
15727        action: &GoToPreviousDiagnostic,
15728        window: &mut Window,
15729        cx: &mut Context<Self>,
15730    ) {
15731        if !self.diagnostics_enabled() {
15732            return;
15733        }
15734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15735        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15736    }
15737
15738    pub fn go_to_diagnostic_impl(
15739        &mut self,
15740        direction: Direction,
15741        severity: GoToDiagnosticSeverityFilter,
15742        window: &mut Window,
15743        cx: &mut Context<Self>,
15744    ) {
15745        let buffer = self.buffer.read(cx).snapshot(cx);
15746        let selection = self.selections.newest::<usize>(cx);
15747
15748        let mut active_group_id = None;
15749        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15750            && active_group.active_range.start.to_offset(&buffer) == selection.start
15751        {
15752            active_group_id = Some(active_group.group_id);
15753        }
15754
15755        fn filtered(
15756            snapshot: EditorSnapshot,
15757            severity: GoToDiagnosticSeverityFilter,
15758            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15759        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15760            diagnostics
15761                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15762                .filter(|entry| entry.range.start != entry.range.end)
15763                .filter(|entry| !entry.diagnostic.is_unnecessary)
15764                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15765        }
15766
15767        let snapshot = self.snapshot(window, cx);
15768        let before = filtered(
15769            snapshot.clone(),
15770            severity,
15771            buffer
15772                .diagnostics_in_range(0..selection.start)
15773                .filter(|entry| entry.range.start <= selection.start),
15774        );
15775        let after = filtered(
15776            snapshot,
15777            severity,
15778            buffer
15779                .diagnostics_in_range(selection.start..buffer.len())
15780                .filter(|entry| entry.range.start >= selection.start),
15781        );
15782
15783        let mut found: Option<DiagnosticEntry<usize>> = None;
15784        if direction == Direction::Prev {
15785            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15786            {
15787                for diagnostic in prev_diagnostics.into_iter().rev() {
15788                    if diagnostic.range.start != selection.start
15789                        || active_group_id
15790                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15791                    {
15792                        found = Some(diagnostic);
15793                        break 'outer;
15794                    }
15795                }
15796            }
15797        } else {
15798            for diagnostic in after.chain(before) {
15799                if diagnostic.range.start != selection.start
15800                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15801                {
15802                    found = Some(diagnostic);
15803                    break;
15804                }
15805            }
15806        }
15807        let Some(next_diagnostic) = found else {
15808            return;
15809        };
15810
15811        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15812        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15813            return;
15814        };
15815        self.change_selections(Default::default(), window, cx, |s| {
15816            s.select_ranges(vec![
15817                next_diagnostic.range.start..next_diagnostic.range.start,
15818            ])
15819        });
15820        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15821        self.refresh_edit_prediction(false, true, window, cx);
15822    }
15823
15824    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15826        let snapshot = self.snapshot(window, cx);
15827        let selection = self.selections.newest::<Point>(cx);
15828        self.go_to_hunk_before_or_after_position(
15829            &snapshot,
15830            selection.head(),
15831            Direction::Next,
15832            window,
15833            cx,
15834        );
15835    }
15836
15837    pub fn go_to_hunk_before_or_after_position(
15838        &mut self,
15839        snapshot: &EditorSnapshot,
15840        position: Point,
15841        direction: Direction,
15842        window: &mut Window,
15843        cx: &mut Context<Editor>,
15844    ) {
15845        let row = if direction == Direction::Next {
15846            self.hunk_after_position(snapshot, position)
15847                .map(|hunk| hunk.row_range.start)
15848        } else {
15849            self.hunk_before_position(snapshot, position)
15850        };
15851
15852        if let Some(row) = row {
15853            let destination = Point::new(row.0, 0);
15854            let autoscroll = Autoscroll::center();
15855
15856            self.unfold_ranges(&[destination..destination], false, false, cx);
15857            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15858                s.select_ranges([destination..destination]);
15859            });
15860        }
15861    }
15862
15863    fn hunk_after_position(
15864        &mut self,
15865        snapshot: &EditorSnapshot,
15866        position: Point,
15867    ) -> Option<MultiBufferDiffHunk> {
15868        snapshot
15869            .buffer_snapshot
15870            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15871            .find(|hunk| hunk.row_range.start.0 > position.row)
15872            .or_else(|| {
15873                snapshot
15874                    .buffer_snapshot
15875                    .diff_hunks_in_range(Point::zero()..position)
15876                    .find(|hunk| hunk.row_range.end.0 < position.row)
15877            })
15878    }
15879
15880    fn go_to_prev_hunk(
15881        &mut self,
15882        _: &GoToPreviousHunk,
15883        window: &mut Window,
15884        cx: &mut Context<Self>,
15885    ) {
15886        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15887        let snapshot = self.snapshot(window, cx);
15888        let selection = self.selections.newest::<Point>(cx);
15889        self.go_to_hunk_before_or_after_position(
15890            &snapshot,
15891            selection.head(),
15892            Direction::Prev,
15893            window,
15894            cx,
15895        );
15896    }
15897
15898    fn hunk_before_position(
15899        &mut self,
15900        snapshot: &EditorSnapshot,
15901        position: Point,
15902    ) -> Option<MultiBufferRow> {
15903        snapshot
15904            .buffer_snapshot
15905            .diff_hunk_before(position)
15906            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15907    }
15908
15909    fn go_to_next_change(
15910        &mut self,
15911        _: &GoToNextChange,
15912        window: &mut Window,
15913        cx: &mut Context<Self>,
15914    ) {
15915        if let Some(selections) = self
15916            .change_list
15917            .next_change(1, Direction::Next)
15918            .map(|s| s.to_vec())
15919        {
15920            self.change_selections(Default::default(), window, cx, |s| {
15921                let map = s.display_map();
15922                s.select_display_ranges(selections.iter().map(|a| {
15923                    let point = a.to_display_point(&map);
15924                    point..point
15925                }))
15926            })
15927        }
15928    }
15929
15930    fn go_to_previous_change(
15931        &mut self,
15932        _: &GoToPreviousChange,
15933        window: &mut Window,
15934        cx: &mut Context<Self>,
15935    ) {
15936        if let Some(selections) = self
15937            .change_list
15938            .next_change(1, Direction::Prev)
15939            .map(|s| s.to_vec())
15940        {
15941            self.change_selections(Default::default(), window, cx, |s| {
15942                let map = s.display_map();
15943                s.select_display_ranges(selections.iter().map(|a| {
15944                    let point = a.to_display_point(&map);
15945                    point..point
15946                }))
15947            })
15948        }
15949    }
15950
15951    pub fn go_to_next_document_highlight(
15952        &mut self,
15953        _: &GoToNextDocumentHighlight,
15954        window: &mut Window,
15955        cx: &mut Context<Self>,
15956    ) {
15957        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
15958    }
15959
15960    pub fn go_to_prev_document_highlight(
15961        &mut self,
15962        _: &GoToPreviousDocumentHighlight,
15963        window: &mut Window,
15964        cx: &mut Context<Self>,
15965    ) {
15966        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
15967    }
15968
15969    pub fn go_to_document_highlight_before_or_after_position(
15970        &mut self,
15971        direction: Direction,
15972        window: &mut Window,
15973        cx: &mut Context<Editor>,
15974    ) {
15975        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15976        let snapshot = self.snapshot(window, cx);
15977        let buffer = &snapshot.buffer_snapshot;
15978        let position = self.selections.newest::<Point>(cx).head();
15979        let anchor_position = buffer.anchor_after(position);
15980
15981        // Get all document highlights (both read and write)
15982        let mut all_highlights = Vec::new();
15983
15984        if let Some((_, read_highlights)) = self
15985            .background_highlights
15986            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
15987        {
15988            all_highlights.extend(read_highlights.iter());
15989        }
15990
15991        if let Some((_, write_highlights)) = self
15992            .background_highlights
15993            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
15994        {
15995            all_highlights.extend(write_highlights.iter());
15996        }
15997
15998        if all_highlights.is_empty() {
15999            return;
16000        }
16001
16002        // Sort highlights by position
16003        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16004
16005        let target_highlight = match direction {
16006            Direction::Next => {
16007                // Find the first highlight after the current position
16008                all_highlights
16009                    .iter()
16010                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16011            }
16012            Direction::Prev => {
16013                // Find the last highlight before the current position
16014                all_highlights
16015                    .iter()
16016                    .rev()
16017                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16018            }
16019        };
16020
16021        if let Some(highlight) = target_highlight {
16022            let destination = highlight.start.to_point(buffer);
16023            let autoscroll = Autoscroll::center();
16024
16025            self.unfold_ranges(&[destination..destination], false, false, cx);
16026            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16027                s.select_ranges([destination..destination]);
16028            });
16029        }
16030    }
16031
16032    fn go_to_line<T: 'static>(
16033        &mut self,
16034        position: Anchor,
16035        highlight_color: Option<Hsla>,
16036        window: &mut Window,
16037        cx: &mut Context<Self>,
16038    ) {
16039        let snapshot = self.snapshot(window, cx).display_snapshot;
16040        let position = position.to_point(&snapshot.buffer_snapshot);
16041        let start = snapshot
16042            .buffer_snapshot
16043            .clip_point(Point::new(position.row, 0), Bias::Left);
16044        let end = start + Point::new(1, 0);
16045        let start = snapshot.buffer_snapshot.anchor_before(start);
16046        let end = snapshot.buffer_snapshot.anchor_before(end);
16047
16048        self.highlight_rows::<T>(
16049            start..end,
16050            highlight_color
16051                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16052            Default::default(),
16053            cx,
16054        );
16055
16056        if self.buffer.read(cx).is_singleton() {
16057            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16058        }
16059    }
16060
16061    pub fn go_to_definition(
16062        &mut self,
16063        _: &GoToDefinition,
16064        window: &mut Window,
16065        cx: &mut Context<Self>,
16066    ) -> Task<Result<Navigated>> {
16067        let definition =
16068            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16069        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16070        cx.spawn_in(window, async move |editor, cx| {
16071            if definition.await? == Navigated::Yes {
16072                return Ok(Navigated::Yes);
16073            }
16074            match fallback_strategy {
16075                GoToDefinitionFallback::None => Ok(Navigated::No),
16076                GoToDefinitionFallback::FindAllReferences => {
16077                    match editor.update_in(cx, |editor, window, cx| {
16078                        editor.find_all_references(&FindAllReferences, window, cx)
16079                    })? {
16080                        Some(references) => references.await,
16081                        None => Ok(Navigated::No),
16082                    }
16083                }
16084            }
16085        })
16086    }
16087
16088    pub fn go_to_declaration(
16089        &mut self,
16090        _: &GoToDeclaration,
16091        window: &mut Window,
16092        cx: &mut Context<Self>,
16093    ) -> Task<Result<Navigated>> {
16094        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16095    }
16096
16097    pub fn go_to_declaration_split(
16098        &mut self,
16099        _: &GoToDeclaration,
16100        window: &mut Window,
16101        cx: &mut Context<Self>,
16102    ) -> Task<Result<Navigated>> {
16103        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16104    }
16105
16106    pub fn go_to_implementation(
16107        &mut self,
16108        _: &GoToImplementation,
16109        window: &mut Window,
16110        cx: &mut Context<Self>,
16111    ) -> Task<Result<Navigated>> {
16112        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16113    }
16114
16115    pub fn go_to_implementation_split(
16116        &mut self,
16117        _: &GoToImplementationSplit,
16118        window: &mut Window,
16119        cx: &mut Context<Self>,
16120    ) -> Task<Result<Navigated>> {
16121        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16122    }
16123
16124    pub fn go_to_type_definition(
16125        &mut self,
16126        _: &GoToTypeDefinition,
16127        window: &mut Window,
16128        cx: &mut Context<Self>,
16129    ) -> Task<Result<Navigated>> {
16130        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16131    }
16132
16133    pub fn go_to_definition_split(
16134        &mut self,
16135        _: &GoToDefinitionSplit,
16136        window: &mut Window,
16137        cx: &mut Context<Self>,
16138    ) -> Task<Result<Navigated>> {
16139        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16140    }
16141
16142    pub fn go_to_type_definition_split(
16143        &mut self,
16144        _: &GoToTypeDefinitionSplit,
16145        window: &mut Window,
16146        cx: &mut Context<Self>,
16147    ) -> Task<Result<Navigated>> {
16148        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16149    }
16150
16151    fn go_to_definition_of_kind(
16152        &mut self,
16153        kind: GotoDefinitionKind,
16154        split: bool,
16155        window: &mut Window,
16156        cx: &mut Context<Self>,
16157    ) -> Task<Result<Navigated>> {
16158        let Some(provider) = self.semantics_provider.clone() else {
16159            return Task::ready(Ok(Navigated::No));
16160        };
16161        let head = self.selections.newest::<usize>(cx).head();
16162        let buffer = self.buffer.read(cx);
16163        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16164            return Task::ready(Ok(Navigated::No));
16165        };
16166        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16167            return Task::ready(Ok(Navigated::No));
16168        };
16169
16170        cx.spawn_in(window, async move |editor, cx| {
16171            let Some(definitions) = definitions.await? else {
16172                return Ok(Navigated::No);
16173            };
16174            let navigated = editor
16175                .update_in(cx, |editor, window, cx| {
16176                    editor.navigate_to_hover_links(
16177                        Some(kind),
16178                        definitions
16179                            .into_iter()
16180                            .filter(|location| {
16181                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16182                            })
16183                            .map(HoverLink::Text)
16184                            .collect::<Vec<_>>(),
16185                        split,
16186                        window,
16187                        cx,
16188                    )
16189                })?
16190                .await?;
16191            anyhow::Ok(navigated)
16192        })
16193    }
16194
16195    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16196        let selection = self.selections.newest_anchor();
16197        let head = selection.head();
16198        let tail = selection.tail();
16199
16200        let Some((buffer, start_position)) =
16201            self.buffer.read(cx).text_anchor_for_position(head, cx)
16202        else {
16203            return;
16204        };
16205
16206        let end_position = if head != tail {
16207            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16208                return;
16209            };
16210            Some(pos)
16211        } else {
16212            None
16213        };
16214
16215        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16216            let url = if let Some(end_pos) = end_position {
16217                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16218            } else {
16219                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16220            };
16221
16222            if let Some(url) = url {
16223                editor.update(cx, |_, cx| {
16224                    cx.open_url(&url);
16225                })
16226            } else {
16227                Ok(())
16228            }
16229        });
16230
16231        url_finder.detach();
16232    }
16233
16234    pub fn open_selected_filename(
16235        &mut self,
16236        _: &OpenSelectedFilename,
16237        window: &mut Window,
16238        cx: &mut Context<Self>,
16239    ) {
16240        let Some(workspace) = self.workspace() else {
16241            return;
16242        };
16243
16244        let position = self.selections.newest_anchor().head();
16245
16246        let Some((buffer, buffer_position)) =
16247            self.buffer.read(cx).text_anchor_for_position(position, cx)
16248        else {
16249            return;
16250        };
16251
16252        let project = self.project.clone();
16253
16254        cx.spawn_in(window, async move |_, cx| {
16255            let result = find_file(&buffer, project, buffer_position, cx).await;
16256
16257            if let Some((_, path)) = result {
16258                workspace
16259                    .update_in(cx, |workspace, window, cx| {
16260                        workspace.open_resolved_path(path, window, cx)
16261                    })?
16262                    .await?;
16263            }
16264            anyhow::Ok(())
16265        })
16266        .detach();
16267    }
16268
16269    pub(crate) fn navigate_to_hover_links(
16270        &mut self,
16271        kind: Option<GotoDefinitionKind>,
16272        definitions: Vec<HoverLink>,
16273        split: bool,
16274        window: &mut Window,
16275        cx: &mut Context<Editor>,
16276    ) -> Task<Result<Navigated>> {
16277        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16278        let mut first_url_or_file = None;
16279        let definitions: Vec<_> = definitions
16280            .into_iter()
16281            .filter_map(|def| match def {
16282                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16283                HoverLink::InlayHint(lsp_location, server_id) => {
16284                    let computation =
16285                        self.compute_target_location(lsp_location, server_id, window, cx);
16286                    Some(cx.background_spawn(computation))
16287                }
16288                HoverLink::Url(url) => {
16289                    first_url_or_file = Some(Either::Left(url));
16290                    None
16291                }
16292                HoverLink::File(path) => {
16293                    first_url_or_file = Some(Either::Right(path));
16294                    None
16295                }
16296            })
16297            .collect();
16298
16299        let workspace = self.workspace();
16300
16301        cx.spawn_in(window, async move |editor, acx| {
16302            let mut locations: Vec<Location> = future::join_all(definitions)
16303                .await
16304                .into_iter()
16305                .filter_map(|location| location.transpose())
16306                .collect::<Result<_>>()
16307                .context("location tasks")?;
16308
16309            if locations.len() > 1 {
16310                let Some(workspace) = workspace else {
16311                    return Ok(Navigated::No);
16312                };
16313
16314                let tab_kind = match kind {
16315                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16316                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16317                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16318                    Some(GotoDefinitionKind::Type) => "Types",
16319                };
16320                let title = editor
16321                    .update_in(acx, |_, _, cx| {
16322                        let target = locations
16323                            .iter()
16324                            .map(|location| {
16325                                location
16326                                    .buffer
16327                                    .read(cx)
16328                                    .text_for_range(location.range.clone())
16329                                    .collect::<String>()
16330                            })
16331                            .filter(|text| !text.contains('\n'))
16332                            .unique()
16333                            .take(3)
16334                            .join(", ");
16335                        if target.is_empty() {
16336                            tab_kind.to_owned()
16337                        } else {
16338                            format!("{tab_kind} for {target}")
16339                        }
16340                    })
16341                    .context("buffer title")?;
16342
16343                let opened = workspace
16344                    .update_in(acx, |workspace, window, cx| {
16345                        Self::open_locations_in_multibuffer(
16346                            workspace,
16347                            locations,
16348                            title,
16349                            split,
16350                            MultibufferSelectionMode::First,
16351                            window,
16352                            cx,
16353                        )
16354                    })
16355                    .is_ok();
16356
16357                anyhow::Ok(Navigated::from_bool(opened))
16358            } else if locations.is_empty() {
16359                // If there is one definition, just open it directly
16360                match first_url_or_file {
16361                    Some(Either::Left(url)) => {
16362                        acx.update(|_, cx| cx.open_url(&url))?;
16363                        Ok(Navigated::Yes)
16364                    }
16365                    Some(Either::Right(path)) => {
16366                        let Some(workspace) = workspace else {
16367                            return Ok(Navigated::No);
16368                        };
16369
16370                        workspace
16371                            .update_in(acx, |workspace, window, cx| {
16372                                workspace.open_resolved_path(path, window, cx)
16373                            })?
16374                            .await?;
16375                        Ok(Navigated::Yes)
16376                    }
16377                    None => Ok(Navigated::No),
16378                }
16379            } else {
16380                let Some(workspace) = workspace else {
16381                    return Ok(Navigated::No);
16382                };
16383
16384                let target = locations.pop().unwrap();
16385                editor.update_in(acx, |editor, window, cx| {
16386                    let pane = workspace.read(cx).active_pane().clone();
16387
16388                    let range = target.range.to_point(target.buffer.read(cx));
16389                    let range = editor.range_for_match(&range);
16390                    let range = collapse_multiline_range(range);
16391
16392                    if !split
16393                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16394                    {
16395                        editor.go_to_singleton_buffer_range(range, window, cx);
16396                    } else {
16397                        window.defer(cx, move |window, cx| {
16398                            let target_editor: Entity<Self> =
16399                                workspace.update(cx, |workspace, cx| {
16400                                    let pane = if split {
16401                                        workspace.adjacent_pane(window, cx)
16402                                    } else {
16403                                        workspace.active_pane().clone()
16404                                    };
16405
16406                                    workspace.open_project_item(
16407                                        pane,
16408                                        target.buffer.clone(),
16409                                        true,
16410                                        true,
16411                                        window,
16412                                        cx,
16413                                    )
16414                                });
16415                            target_editor.update(cx, |target_editor, cx| {
16416                                // When selecting a definition in a different buffer, disable the nav history
16417                                // to avoid creating a history entry at the previous cursor location.
16418                                pane.update(cx, |pane, _| pane.disable_history());
16419                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16420                                pane.update(cx, |pane, _| pane.enable_history());
16421                            });
16422                        });
16423                    }
16424                    Navigated::Yes
16425                })
16426            }
16427        })
16428    }
16429
16430    fn compute_target_location(
16431        &self,
16432        lsp_location: lsp::Location,
16433        server_id: LanguageServerId,
16434        window: &mut Window,
16435        cx: &mut Context<Self>,
16436    ) -> Task<anyhow::Result<Option<Location>>> {
16437        let Some(project) = self.project.clone() else {
16438            return Task::ready(Ok(None));
16439        };
16440
16441        cx.spawn_in(window, async move |editor, cx| {
16442            let location_task = editor.update(cx, |_, cx| {
16443                project.update(cx, |project, cx| {
16444                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16445                })
16446            })?;
16447            let location = Some({
16448                let target_buffer_handle = location_task.await.context("open local buffer")?;
16449                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16450                    let target_start = target_buffer
16451                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16452                    let target_end = target_buffer
16453                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16454                    target_buffer.anchor_after(target_start)
16455                        ..target_buffer.anchor_before(target_end)
16456                })?;
16457                Location {
16458                    buffer: target_buffer_handle,
16459                    range,
16460                }
16461            });
16462            Ok(location)
16463        })
16464    }
16465
16466    pub fn find_all_references(
16467        &mut self,
16468        _: &FindAllReferences,
16469        window: &mut Window,
16470        cx: &mut Context<Self>,
16471    ) -> Option<Task<Result<Navigated>>> {
16472        let selection = self.selections.newest::<usize>(cx);
16473        let multi_buffer = self.buffer.read(cx);
16474        let head = selection.head();
16475
16476        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16477        let head_anchor = multi_buffer_snapshot.anchor_at(
16478            head,
16479            if head < selection.tail() {
16480                Bias::Right
16481            } else {
16482                Bias::Left
16483            },
16484        );
16485
16486        match self
16487            .find_all_references_task_sources
16488            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16489        {
16490            Ok(_) => {
16491                log::info!(
16492                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16493                );
16494                return None;
16495            }
16496            Err(i) => {
16497                self.find_all_references_task_sources.insert(i, head_anchor);
16498            }
16499        }
16500
16501        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16502        let workspace = self.workspace()?;
16503        let project = workspace.read(cx).project().clone();
16504        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16505        Some(cx.spawn_in(window, async move |editor, cx| {
16506            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16507                if let Ok(i) = editor
16508                    .find_all_references_task_sources
16509                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16510                {
16511                    editor.find_all_references_task_sources.remove(i);
16512                }
16513            });
16514
16515            let Some(locations) = references.await? else {
16516                return anyhow::Ok(Navigated::No);
16517            };
16518            if locations.is_empty() {
16519                return anyhow::Ok(Navigated::No);
16520            }
16521
16522            workspace.update_in(cx, |workspace, window, cx| {
16523                let target = locations
16524                    .iter()
16525                    .map(|location| {
16526                        location
16527                            .buffer
16528                            .read(cx)
16529                            .text_for_range(location.range.clone())
16530                            .collect::<String>()
16531                    })
16532                    .filter(|text| !text.contains('\n'))
16533                    .unique()
16534                    .take(3)
16535                    .join(", ");
16536                let title = if target.is_empty() {
16537                    "References".to_owned()
16538                } else {
16539                    format!("References to {target}")
16540                };
16541                Self::open_locations_in_multibuffer(
16542                    workspace,
16543                    locations,
16544                    title,
16545                    false,
16546                    MultibufferSelectionMode::First,
16547                    window,
16548                    cx,
16549                );
16550                Navigated::Yes
16551            })
16552        }))
16553    }
16554
16555    /// Opens a multibuffer with the given project locations in it
16556    pub fn open_locations_in_multibuffer(
16557        workspace: &mut Workspace,
16558        mut locations: Vec<Location>,
16559        title: String,
16560        split: bool,
16561        multibuffer_selection_mode: MultibufferSelectionMode,
16562        window: &mut Window,
16563        cx: &mut Context<Workspace>,
16564    ) {
16565        if locations.is_empty() {
16566            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16567            return;
16568        }
16569
16570        // If there are multiple definitions, open them in a multibuffer
16571        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16572        let mut locations = locations.into_iter().peekable();
16573        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16574        let capability = workspace.project().read(cx).capability();
16575
16576        let excerpt_buffer = cx.new(|cx| {
16577            let mut multibuffer = MultiBuffer::new(capability);
16578            while let Some(location) = locations.next() {
16579                let buffer = location.buffer.read(cx);
16580                let mut ranges_for_buffer = Vec::new();
16581                let range = location.range.to_point(buffer);
16582                ranges_for_buffer.push(range.clone());
16583
16584                while let Some(next_location) = locations.peek() {
16585                    if next_location.buffer == location.buffer {
16586                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16587                        locations.next();
16588                    } else {
16589                        break;
16590                    }
16591                }
16592
16593                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16594                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16595                    PathKey::for_buffer(&location.buffer, cx),
16596                    location.buffer.clone(),
16597                    ranges_for_buffer,
16598                    multibuffer_context_lines(cx),
16599                    cx,
16600                );
16601                ranges.extend(new_ranges)
16602            }
16603
16604            multibuffer.with_title(title)
16605        });
16606
16607        let editor = cx.new(|cx| {
16608            Editor::for_multibuffer(
16609                excerpt_buffer,
16610                Some(workspace.project().clone()),
16611                window,
16612                cx,
16613            )
16614        });
16615        editor.update(cx, |editor, cx| {
16616            match multibuffer_selection_mode {
16617                MultibufferSelectionMode::First => {
16618                    if let Some(first_range) = ranges.first() {
16619                        editor.change_selections(
16620                            SelectionEffects::no_scroll(),
16621                            window,
16622                            cx,
16623                            |selections| {
16624                                selections.clear_disjoint();
16625                                selections
16626                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16627                            },
16628                        );
16629                    }
16630                    editor.highlight_background::<Self>(
16631                        &ranges,
16632                        |theme| theme.colors().editor_highlighted_line_background,
16633                        cx,
16634                    );
16635                }
16636                MultibufferSelectionMode::All => {
16637                    editor.change_selections(
16638                        SelectionEffects::no_scroll(),
16639                        window,
16640                        cx,
16641                        |selections| {
16642                            selections.clear_disjoint();
16643                            selections.select_anchor_ranges(ranges);
16644                        },
16645                    );
16646                }
16647            }
16648            editor.register_buffers_with_language_servers(cx);
16649        });
16650
16651        let item = Box::new(editor);
16652        let item_id = item.item_id();
16653
16654        if split {
16655            workspace.split_item(SplitDirection::Right, item, window, cx);
16656        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16657            let (preview_item_id, preview_item_idx) =
16658                workspace.active_pane().read_with(cx, |pane, _| {
16659                    (pane.preview_item_id(), pane.preview_item_idx())
16660                });
16661
16662            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16663
16664            if let Some(preview_item_id) = preview_item_id {
16665                workspace.active_pane().update(cx, |pane, cx| {
16666                    pane.remove_item(preview_item_id, false, false, window, cx);
16667                });
16668            }
16669        } else {
16670            workspace.add_item_to_active_pane(item, None, true, window, cx);
16671        }
16672        workspace.active_pane().update(cx, |pane, cx| {
16673            pane.set_preview_item_id(Some(item_id), cx);
16674        });
16675    }
16676
16677    pub fn rename(
16678        &mut self,
16679        _: &Rename,
16680        window: &mut Window,
16681        cx: &mut Context<Self>,
16682    ) -> Option<Task<Result<()>>> {
16683        use language::ToOffset as _;
16684
16685        let provider = self.semantics_provider.clone()?;
16686        let selection = self.selections.newest_anchor().clone();
16687        let (cursor_buffer, cursor_buffer_position) = self
16688            .buffer
16689            .read(cx)
16690            .text_anchor_for_position(selection.head(), cx)?;
16691        let (tail_buffer, cursor_buffer_position_end) = self
16692            .buffer
16693            .read(cx)
16694            .text_anchor_for_position(selection.tail(), cx)?;
16695        if tail_buffer != cursor_buffer {
16696            return None;
16697        }
16698
16699        let snapshot = cursor_buffer.read(cx).snapshot();
16700        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16701        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16702        let prepare_rename = provider
16703            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16704            .unwrap_or_else(|| Task::ready(Ok(None)));
16705        drop(snapshot);
16706
16707        Some(cx.spawn_in(window, async move |this, cx| {
16708            let rename_range = if let Some(range) = prepare_rename.await? {
16709                Some(range)
16710            } else {
16711                this.update(cx, |this, cx| {
16712                    let buffer = this.buffer.read(cx).snapshot(cx);
16713                    let mut buffer_highlights = this
16714                        .document_highlights_for_position(selection.head(), &buffer)
16715                        .filter(|highlight| {
16716                            highlight.start.excerpt_id == selection.head().excerpt_id
16717                                && highlight.end.excerpt_id == selection.head().excerpt_id
16718                        });
16719                    buffer_highlights
16720                        .next()
16721                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16722                })?
16723            };
16724            if let Some(rename_range) = rename_range {
16725                this.update_in(cx, |this, window, cx| {
16726                    let snapshot = cursor_buffer.read(cx).snapshot();
16727                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16728                    let cursor_offset_in_rename_range =
16729                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16730                    let cursor_offset_in_rename_range_end =
16731                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16732
16733                    this.take_rename(false, window, cx);
16734                    let buffer = this.buffer.read(cx).read(cx);
16735                    let cursor_offset = selection.head().to_offset(&buffer);
16736                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16737                    let rename_end = rename_start + rename_buffer_range.len();
16738                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16739                    let mut old_highlight_id = None;
16740                    let old_name: Arc<str> = buffer
16741                        .chunks(rename_start..rename_end, true)
16742                        .map(|chunk| {
16743                            if old_highlight_id.is_none() {
16744                                old_highlight_id = chunk.syntax_highlight_id;
16745                            }
16746                            chunk.text
16747                        })
16748                        .collect::<String>()
16749                        .into();
16750
16751                    drop(buffer);
16752
16753                    // Position the selection in the rename editor so that it matches the current selection.
16754                    this.show_local_selections = false;
16755                    let rename_editor = cx.new(|cx| {
16756                        let mut editor = Editor::single_line(window, cx);
16757                        editor.buffer.update(cx, |buffer, cx| {
16758                            buffer.edit([(0..0, old_name.clone())], None, cx)
16759                        });
16760                        let rename_selection_range = match cursor_offset_in_rename_range
16761                            .cmp(&cursor_offset_in_rename_range_end)
16762                        {
16763                            Ordering::Equal => {
16764                                editor.select_all(&SelectAll, window, cx);
16765                                return editor;
16766                            }
16767                            Ordering::Less => {
16768                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16769                            }
16770                            Ordering::Greater => {
16771                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16772                            }
16773                        };
16774                        if rename_selection_range.end > old_name.len() {
16775                            editor.select_all(&SelectAll, window, cx);
16776                        } else {
16777                            editor.change_selections(Default::default(), window, cx, |s| {
16778                                s.select_ranges([rename_selection_range]);
16779                            });
16780                        }
16781                        editor
16782                    });
16783                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16784                        if e == &EditorEvent::Focused {
16785                            cx.emit(EditorEvent::FocusedIn)
16786                        }
16787                    })
16788                    .detach();
16789
16790                    let write_highlights =
16791                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16792                    let read_highlights =
16793                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16794                    let ranges = write_highlights
16795                        .iter()
16796                        .flat_map(|(_, ranges)| ranges.iter())
16797                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16798                        .cloned()
16799                        .collect();
16800
16801                    this.highlight_text::<Rename>(
16802                        ranges,
16803                        HighlightStyle {
16804                            fade_out: Some(0.6),
16805                            ..Default::default()
16806                        },
16807                        cx,
16808                    );
16809                    let rename_focus_handle = rename_editor.focus_handle(cx);
16810                    window.focus(&rename_focus_handle);
16811                    let block_id = this.insert_blocks(
16812                        [BlockProperties {
16813                            style: BlockStyle::Flex,
16814                            placement: BlockPlacement::Below(range.start),
16815                            height: Some(1),
16816                            render: Arc::new({
16817                                let rename_editor = rename_editor.clone();
16818                                move |cx: &mut BlockContext| {
16819                                    let mut text_style = cx.editor_style.text.clone();
16820                                    if let Some(highlight_style) = old_highlight_id
16821                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16822                                    {
16823                                        text_style = text_style.highlight(highlight_style);
16824                                    }
16825                                    div()
16826                                        .block_mouse_except_scroll()
16827                                        .pl(cx.anchor_x)
16828                                        .child(EditorElement::new(
16829                                            &rename_editor,
16830                                            EditorStyle {
16831                                                background: cx.theme().system().transparent,
16832                                                local_player: cx.editor_style.local_player,
16833                                                text: text_style,
16834                                                scrollbar_width: cx.editor_style.scrollbar_width,
16835                                                syntax: cx.editor_style.syntax.clone(),
16836                                                status: cx.editor_style.status.clone(),
16837                                                inlay_hints_style: HighlightStyle {
16838                                                    font_weight: Some(FontWeight::BOLD),
16839                                                    ..make_inlay_hints_style(cx.app)
16840                                                },
16841                                                edit_prediction_styles: make_suggestion_styles(
16842                                                    cx.app,
16843                                                ),
16844                                                ..EditorStyle::default()
16845                                            },
16846                                        ))
16847                                        .into_any_element()
16848                                }
16849                            }),
16850                            priority: 0,
16851                        }],
16852                        Some(Autoscroll::fit()),
16853                        cx,
16854                    )[0];
16855                    this.pending_rename = Some(RenameState {
16856                        range,
16857                        old_name,
16858                        editor: rename_editor,
16859                        block_id,
16860                    });
16861                })?;
16862            }
16863
16864            Ok(())
16865        }))
16866    }
16867
16868    pub fn confirm_rename(
16869        &mut self,
16870        _: &ConfirmRename,
16871        window: &mut Window,
16872        cx: &mut Context<Self>,
16873    ) -> Option<Task<Result<()>>> {
16874        let rename = self.take_rename(false, window, cx)?;
16875        let workspace = self.workspace()?.downgrade();
16876        let (buffer, start) = self
16877            .buffer
16878            .read(cx)
16879            .text_anchor_for_position(rename.range.start, cx)?;
16880        let (end_buffer, _) = self
16881            .buffer
16882            .read(cx)
16883            .text_anchor_for_position(rename.range.end, cx)?;
16884        if buffer != end_buffer {
16885            return None;
16886        }
16887
16888        let old_name = rename.old_name;
16889        let new_name = rename.editor.read(cx).text(cx);
16890
16891        let rename = self.semantics_provider.as_ref()?.perform_rename(
16892            &buffer,
16893            start,
16894            new_name.clone(),
16895            cx,
16896        )?;
16897
16898        Some(cx.spawn_in(window, async move |editor, cx| {
16899            let project_transaction = rename.await?;
16900            Self::open_project_transaction(
16901                &editor,
16902                workspace,
16903                project_transaction,
16904                format!("Rename: {}{}", old_name, new_name),
16905                cx,
16906            )
16907            .await?;
16908
16909            editor.update(cx, |editor, cx| {
16910                editor.refresh_document_highlights(cx);
16911            })?;
16912            Ok(())
16913        }))
16914    }
16915
16916    fn take_rename(
16917        &mut self,
16918        moving_cursor: bool,
16919        window: &mut Window,
16920        cx: &mut Context<Self>,
16921    ) -> Option<RenameState> {
16922        let rename = self.pending_rename.take()?;
16923        if rename.editor.focus_handle(cx).is_focused(window) {
16924            window.focus(&self.focus_handle);
16925        }
16926
16927        self.remove_blocks(
16928            [rename.block_id].into_iter().collect(),
16929            Some(Autoscroll::fit()),
16930            cx,
16931        );
16932        self.clear_highlights::<Rename>(cx);
16933        self.show_local_selections = true;
16934
16935        if moving_cursor {
16936            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16937                editor.selections.newest::<usize>(cx).head()
16938            });
16939
16940            // Update the selection to match the position of the selection inside
16941            // the rename editor.
16942            let snapshot = self.buffer.read(cx).read(cx);
16943            let rename_range = rename.range.to_offset(&snapshot);
16944            let cursor_in_editor = snapshot
16945                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16946                .min(rename_range.end);
16947            drop(snapshot);
16948
16949            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16950                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16951            });
16952        } else {
16953            self.refresh_document_highlights(cx);
16954        }
16955
16956        Some(rename)
16957    }
16958
16959    pub fn pending_rename(&self) -> Option<&RenameState> {
16960        self.pending_rename.as_ref()
16961    }
16962
16963    fn format(
16964        &mut self,
16965        _: &Format,
16966        window: &mut Window,
16967        cx: &mut Context<Self>,
16968    ) -> Option<Task<Result<()>>> {
16969        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16970
16971        let project = match &self.project {
16972            Some(project) => project.clone(),
16973            None => return None,
16974        };
16975
16976        Some(self.perform_format(
16977            project,
16978            FormatTrigger::Manual,
16979            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16980            window,
16981            cx,
16982        ))
16983    }
16984
16985    fn format_selections(
16986        &mut self,
16987        _: &FormatSelections,
16988        window: &mut Window,
16989        cx: &mut Context<Self>,
16990    ) -> Option<Task<Result<()>>> {
16991        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16992
16993        let project = match &self.project {
16994            Some(project) => project.clone(),
16995            None => return None,
16996        };
16997
16998        let ranges = self
16999            .selections
17000            .all_adjusted(cx)
17001            .into_iter()
17002            .map(|selection| selection.range())
17003            .collect_vec();
17004
17005        Some(self.perform_format(
17006            project,
17007            FormatTrigger::Manual,
17008            FormatTarget::Ranges(ranges),
17009            window,
17010            cx,
17011        ))
17012    }
17013
17014    fn perform_format(
17015        &mut self,
17016        project: Entity<Project>,
17017        trigger: FormatTrigger,
17018        target: FormatTarget,
17019        window: &mut Window,
17020        cx: &mut Context<Self>,
17021    ) -> Task<Result<()>> {
17022        let buffer = self.buffer.clone();
17023        let (buffers, target) = match target {
17024            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17025            FormatTarget::Ranges(selection_ranges) => {
17026                let multi_buffer = buffer.read(cx);
17027                let snapshot = multi_buffer.read(cx);
17028                let mut buffers = HashSet::default();
17029                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17030                    BTreeMap::new();
17031                for selection_range in selection_ranges {
17032                    for (buffer, buffer_range, _) in
17033                        snapshot.range_to_buffer_ranges(selection_range)
17034                    {
17035                        let buffer_id = buffer.remote_id();
17036                        let start = buffer.anchor_before(buffer_range.start);
17037                        let end = buffer.anchor_after(buffer_range.end);
17038                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17039                        buffer_id_to_ranges
17040                            .entry(buffer_id)
17041                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17042                            .or_insert_with(|| vec![start..end]);
17043                    }
17044                }
17045                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17046            }
17047        };
17048
17049        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17050        let selections_prev = transaction_id_prev
17051            .and_then(|transaction_id_prev| {
17052                // default to selections as they were after the last edit, if we have them,
17053                // instead of how they are now.
17054                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17055                // will take you back to where you made the last edit, instead of staying where you scrolled
17056                self.selection_history
17057                    .transaction(transaction_id_prev)
17058                    .map(|t| t.0.clone())
17059            })
17060            .unwrap_or_else(|| self.selections.disjoint_anchors());
17061
17062        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17063        let format = project.update(cx, |project, cx| {
17064            project.format(buffers, target, true, trigger, cx)
17065        });
17066
17067        cx.spawn_in(window, async move |editor, cx| {
17068            let transaction = futures::select_biased! {
17069                transaction = format.log_err().fuse() => transaction,
17070                () = timeout => {
17071                    log::warn!("timed out waiting for formatting");
17072                    None
17073                }
17074            };
17075
17076            buffer
17077                .update(cx, |buffer, cx| {
17078                    if let Some(transaction) = transaction
17079                        && !buffer.is_singleton()
17080                    {
17081                        buffer.push_transaction(&transaction.0, cx);
17082                    }
17083                    cx.notify();
17084                })
17085                .ok();
17086
17087            if let Some(transaction_id_now) =
17088                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17089            {
17090                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17091                if has_new_transaction {
17092                    _ = editor.update(cx, |editor, _| {
17093                        editor
17094                            .selection_history
17095                            .insert_transaction(transaction_id_now, selections_prev);
17096                    });
17097                }
17098            }
17099
17100            Ok(())
17101        })
17102    }
17103
17104    fn organize_imports(
17105        &mut self,
17106        _: &OrganizeImports,
17107        window: &mut Window,
17108        cx: &mut Context<Self>,
17109    ) -> Option<Task<Result<()>>> {
17110        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17111        let project = match &self.project {
17112            Some(project) => project.clone(),
17113            None => return None,
17114        };
17115        Some(self.perform_code_action_kind(
17116            project,
17117            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17118            window,
17119            cx,
17120        ))
17121    }
17122
17123    fn perform_code_action_kind(
17124        &mut self,
17125        project: Entity<Project>,
17126        kind: CodeActionKind,
17127        window: &mut Window,
17128        cx: &mut Context<Self>,
17129    ) -> Task<Result<()>> {
17130        let buffer = self.buffer.clone();
17131        let buffers = buffer.read(cx).all_buffers();
17132        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17133        let apply_action = project.update(cx, |project, cx| {
17134            project.apply_code_action_kind(buffers, kind, true, cx)
17135        });
17136        cx.spawn_in(window, async move |_, cx| {
17137            let transaction = futures::select_biased! {
17138                () = timeout => {
17139                    log::warn!("timed out waiting for executing code action");
17140                    None
17141                }
17142                transaction = apply_action.log_err().fuse() => transaction,
17143            };
17144            buffer
17145                .update(cx, |buffer, cx| {
17146                    // check if we need this
17147                    if let Some(transaction) = transaction
17148                        && !buffer.is_singleton()
17149                    {
17150                        buffer.push_transaction(&transaction.0, cx);
17151                    }
17152                    cx.notify();
17153                })
17154                .ok();
17155            Ok(())
17156        })
17157    }
17158
17159    pub fn restart_language_server(
17160        &mut self,
17161        _: &RestartLanguageServer,
17162        _: &mut Window,
17163        cx: &mut Context<Self>,
17164    ) {
17165        if let Some(project) = self.project.clone() {
17166            self.buffer.update(cx, |multi_buffer, cx| {
17167                project.update(cx, |project, cx| {
17168                    project.restart_language_servers_for_buffers(
17169                        multi_buffer.all_buffers().into_iter().collect(),
17170                        HashSet::default(),
17171                        cx,
17172                    );
17173                });
17174            })
17175        }
17176    }
17177
17178    pub fn stop_language_server(
17179        &mut self,
17180        _: &StopLanguageServer,
17181        _: &mut Window,
17182        cx: &mut Context<Self>,
17183    ) {
17184        if let Some(project) = self.project.clone() {
17185            self.buffer.update(cx, |multi_buffer, cx| {
17186                project.update(cx, |project, cx| {
17187                    project.stop_language_servers_for_buffers(
17188                        multi_buffer.all_buffers().into_iter().collect(),
17189                        HashSet::default(),
17190                        cx,
17191                    );
17192                    cx.emit(project::Event::RefreshInlayHints);
17193                });
17194            });
17195        }
17196    }
17197
17198    fn cancel_language_server_work(
17199        workspace: &mut Workspace,
17200        _: &actions::CancelLanguageServerWork,
17201        _: &mut Window,
17202        cx: &mut Context<Workspace>,
17203    ) {
17204        let project = workspace.project();
17205        let buffers = workspace
17206            .active_item(cx)
17207            .and_then(|item| item.act_as::<Editor>(cx))
17208            .map_or(HashSet::default(), |editor| {
17209                editor.read(cx).buffer.read(cx).all_buffers()
17210            });
17211        project.update(cx, |project, cx| {
17212            project.cancel_language_server_work_for_buffers(buffers, cx);
17213        });
17214    }
17215
17216    fn show_character_palette(
17217        &mut self,
17218        _: &ShowCharacterPalette,
17219        window: &mut Window,
17220        _: &mut Context<Self>,
17221    ) {
17222        window.show_character_palette();
17223    }
17224
17225    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17226        if !self.diagnostics_enabled() {
17227            return;
17228        }
17229
17230        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17231            let buffer = self.buffer.read(cx).snapshot(cx);
17232            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17233            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17234            let is_valid = buffer
17235                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17236                .any(|entry| {
17237                    entry.diagnostic.is_primary
17238                        && !entry.range.is_empty()
17239                        && entry.range.start == primary_range_start
17240                        && entry.diagnostic.message == active_diagnostics.active_message
17241                });
17242
17243            if !is_valid {
17244                self.dismiss_diagnostics(cx);
17245            }
17246        }
17247    }
17248
17249    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17250        match &self.active_diagnostics {
17251            ActiveDiagnostic::Group(group) => Some(group),
17252            _ => None,
17253        }
17254    }
17255
17256    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17257        if !self.diagnostics_enabled() {
17258            return;
17259        }
17260        self.dismiss_diagnostics(cx);
17261        self.active_diagnostics = ActiveDiagnostic::All;
17262    }
17263
17264    fn activate_diagnostics(
17265        &mut self,
17266        buffer_id: BufferId,
17267        diagnostic: DiagnosticEntry<usize>,
17268        window: &mut Window,
17269        cx: &mut Context<Self>,
17270    ) {
17271        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17272            return;
17273        }
17274        self.dismiss_diagnostics(cx);
17275        let snapshot = self.snapshot(window, cx);
17276        let buffer = self.buffer.read(cx).snapshot(cx);
17277        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17278            return;
17279        };
17280
17281        let diagnostic_group = buffer
17282            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17283            .collect::<Vec<_>>();
17284
17285        let blocks =
17286            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17287
17288        let blocks = self.display_map.update(cx, |display_map, cx| {
17289            display_map.insert_blocks(blocks, cx).into_iter().collect()
17290        });
17291        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17292            active_range: buffer.anchor_before(diagnostic.range.start)
17293                ..buffer.anchor_after(diagnostic.range.end),
17294            active_message: diagnostic.diagnostic.message.clone(),
17295            group_id: diagnostic.diagnostic.group_id,
17296            blocks,
17297        });
17298        cx.notify();
17299    }
17300
17301    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17302        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17303            return;
17304        };
17305
17306        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17307        if let ActiveDiagnostic::Group(group) = prev {
17308            self.display_map.update(cx, |display_map, cx| {
17309                display_map.remove_blocks(group.blocks, cx);
17310            });
17311            cx.notify();
17312        }
17313    }
17314
17315    /// Disable inline diagnostics rendering for this editor.
17316    pub fn disable_inline_diagnostics(&mut self) {
17317        self.inline_diagnostics_enabled = false;
17318        self.inline_diagnostics_update = Task::ready(());
17319        self.inline_diagnostics.clear();
17320    }
17321
17322    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17323        self.diagnostics_enabled = false;
17324        self.dismiss_diagnostics(cx);
17325        self.inline_diagnostics_update = Task::ready(());
17326        self.inline_diagnostics.clear();
17327    }
17328
17329    pub fn disable_word_completions(&mut self) {
17330        self.word_completions_enabled = false;
17331    }
17332
17333    pub fn diagnostics_enabled(&self) -> bool {
17334        self.diagnostics_enabled && self.mode.is_full()
17335    }
17336
17337    pub fn inline_diagnostics_enabled(&self) -> bool {
17338        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17339    }
17340
17341    pub fn show_inline_diagnostics(&self) -> bool {
17342        self.show_inline_diagnostics
17343    }
17344
17345    pub fn toggle_inline_diagnostics(
17346        &mut self,
17347        _: &ToggleInlineDiagnostics,
17348        window: &mut Window,
17349        cx: &mut Context<Editor>,
17350    ) {
17351        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17352        self.refresh_inline_diagnostics(false, window, cx);
17353    }
17354
17355    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17356        self.diagnostics_max_severity = severity;
17357        self.display_map.update(cx, |display_map, _| {
17358            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17359        });
17360    }
17361
17362    pub fn toggle_diagnostics(
17363        &mut self,
17364        _: &ToggleDiagnostics,
17365        window: &mut Window,
17366        cx: &mut Context<Editor>,
17367    ) {
17368        if !self.diagnostics_enabled() {
17369            return;
17370        }
17371
17372        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17373            EditorSettings::get_global(cx)
17374                .diagnostics_max_severity
17375                .filter(|severity| severity != &DiagnosticSeverity::Off)
17376                .unwrap_or(DiagnosticSeverity::Hint)
17377        } else {
17378            DiagnosticSeverity::Off
17379        };
17380        self.set_max_diagnostics_severity(new_severity, cx);
17381        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17382            self.active_diagnostics = ActiveDiagnostic::None;
17383            self.inline_diagnostics_update = Task::ready(());
17384            self.inline_diagnostics.clear();
17385        } else {
17386            self.refresh_inline_diagnostics(false, window, cx);
17387        }
17388
17389        cx.notify();
17390    }
17391
17392    pub fn toggle_minimap(
17393        &mut self,
17394        _: &ToggleMinimap,
17395        window: &mut Window,
17396        cx: &mut Context<Editor>,
17397    ) {
17398        if self.supports_minimap(cx) {
17399            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17400        }
17401    }
17402
17403    fn refresh_inline_diagnostics(
17404        &mut self,
17405        debounce: bool,
17406        window: &mut Window,
17407        cx: &mut Context<Self>,
17408    ) {
17409        let max_severity = ProjectSettings::get_global(cx)
17410            .diagnostics
17411            .inline
17412            .max_severity
17413            .unwrap_or(self.diagnostics_max_severity);
17414
17415        if !self.inline_diagnostics_enabled()
17416            || !self.show_inline_diagnostics
17417            || max_severity == DiagnosticSeverity::Off
17418        {
17419            self.inline_diagnostics_update = Task::ready(());
17420            self.inline_diagnostics.clear();
17421            return;
17422        }
17423
17424        let debounce_ms = ProjectSettings::get_global(cx)
17425            .diagnostics
17426            .inline
17427            .update_debounce_ms;
17428        let debounce = if debounce && debounce_ms > 0 {
17429            Some(Duration::from_millis(debounce_ms))
17430        } else {
17431            None
17432        };
17433        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17434            if let Some(debounce) = debounce {
17435                cx.background_executor().timer(debounce).await;
17436            }
17437            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17438                editor
17439                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17440                    .ok()
17441            }) else {
17442                return;
17443            };
17444
17445            let new_inline_diagnostics = cx
17446                .background_spawn(async move {
17447                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17448                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17449                        let message = diagnostic_entry
17450                            .diagnostic
17451                            .message
17452                            .split_once('\n')
17453                            .map(|(line, _)| line)
17454                            .map(SharedString::new)
17455                            .unwrap_or_else(|| {
17456                                SharedString::from(diagnostic_entry.diagnostic.message)
17457                            });
17458                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17459                        let (Ok(i) | Err(i)) = inline_diagnostics
17460                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17461                        inline_diagnostics.insert(
17462                            i,
17463                            (
17464                                start_anchor,
17465                                InlineDiagnostic {
17466                                    message,
17467                                    group_id: diagnostic_entry.diagnostic.group_id,
17468                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17469                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17470                                    severity: diagnostic_entry.diagnostic.severity,
17471                                },
17472                            ),
17473                        );
17474                    }
17475                    inline_diagnostics
17476                })
17477                .await;
17478
17479            editor
17480                .update(cx, |editor, cx| {
17481                    editor.inline_diagnostics = new_inline_diagnostics;
17482                    cx.notify();
17483                })
17484                .ok();
17485        });
17486    }
17487
17488    fn pull_diagnostics(
17489        &mut self,
17490        buffer_id: Option<BufferId>,
17491        window: &Window,
17492        cx: &mut Context<Self>,
17493    ) -> Option<()> {
17494        if !self.mode().is_full() {
17495            return None;
17496        }
17497        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17498            .diagnostics
17499            .lsp_pull_diagnostics;
17500        if !pull_diagnostics_settings.enabled {
17501            return None;
17502        }
17503        let project = self.project()?.downgrade();
17504        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17505        let mut buffers = self.buffer.read(cx).all_buffers();
17506        if let Some(buffer_id) = buffer_id {
17507            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17508        }
17509
17510        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17511            cx.background_executor().timer(debounce).await;
17512
17513            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17514                buffers
17515                    .into_iter()
17516                    .filter_map(|buffer| {
17517                        project
17518                            .update(cx, |project, cx| {
17519                                project.lsp_store().update(cx, |lsp_store, cx| {
17520                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17521                                })
17522                            })
17523                            .ok()
17524                    })
17525                    .collect::<FuturesUnordered<_>>()
17526            }) else {
17527                return;
17528            };
17529
17530            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17531                match pull_task {
17532                    Ok(()) => {
17533                        if editor
17534                            .update_in(cx, |editor, window, cx| {
17535                                editor.update_diagnostics_state(window, cx);
17536                            })
17537                            .is_err()
17538                        {
17539                            return;
17540                        }
17541                    }
17542                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17543                }
17544            }
17545        });
17546
17547        Some(())
17548    }
17549
17550    pub fn set_selections_from_remote(
17551        &mut self,
17552        selections: Vec<Selection<Anchor>>,
17553        pending_selection: Option<Selection<Anchor>>,
17554        window: &mut Window,
17555        cx: &mut Context<Self>,
17556    ) {
17557        let old_cursor_position = self.selections.newest_anchor().head();
17558        self.selections.change_with(cx, |s| {
17559            s.select_anchors(selections);
17560            if let Some(pending_selection) = pending_selection {
17561                s.set_pending(pending_selection, SelectMode::Character);
17562            } else {
17563                s.clear_pending();
17564            }
17565        });
17566        self.selections_did_change(
17567            false,
17568            &old_cursor_position,
17569            SelectionEffects::default(),
17570            window,
17571            cx,
17572        );
17573    }
17574
17575    pub fn transact(
17576        &mut self,
17577        window: &mut Window,
17578        cx: &mut Context<Self>,
17579        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17580    ) -> Option<TransactionId> {
17581        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17582            this.start_transaction_at(Instant::now(), window, cx);
17583            update(this, window, cx);
17584            this.end_transaction_at(Instant::now(), cx)
17585        })
17586    }
17587
17588    pub fn start_transaction_at(
17589        &mut self,
17590        now: Instant,
17591        window: &mut Window,
17592        cx: &mut Context<Self>,
17593    ) -> Option<TransactionId> {
17594        self.end_selection(window, cx);
17595        if let Some(tx_id) = self
17596            .buffer
17597            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17598        {
17599            self.selection_history
17600                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17601            cx.emit(EditorEvent::TransactionBegun {
17602                transaction_id: tx_id,
17603            });
17604            Some(tx_id)
17605        } else {
17606            None
17607        }
17608    }
17609
17610    pub fn end_transaction_at(
17611        &mut self,
17612        now: Instant,
17613        cx: &mut Context<Self>,
17614    ) -> Option<TransactionId> {
17615        if let Some(transaction_id) = self
17616            .buffer
17617            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17618        {
17619            if let Some((_, end_selections)) =
17620                self.selection_history.transaction_mut(transaction_id)
17621            {
17622                *end_selections = Some(self.selections.disjoint_anchors());
17623            } else {
17624                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17625            }
17626
17627            cx.emit(EditorEvent::Edited { transaction_id });
17628            Some(transaction_id)
17629        } else {
17630            None
17631        }
17632    }
17633
17634    pub fn modify_transaction_selection_history(
17635        &mut self,
17636        transaction_id: TransactionId,
17637        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17638    ) -> bool {
17639        self.selection_history
17640            .transaction_mut(transaction_id)
17641            .map(modify)
17642            .is_some()
17643    }
17644
17645    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17646        if self.selection_mark_mode {
17647            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17648                s.move_with(|_, sel| {
17649                    sel.collapse_to(sel.head(), SelectionGoal::None);
17650                });
17651            })
17652        }
17653        self.selection_mark_mode = true;
17654        cx.notify();
17655    }
17656
17657    pub fn swap_selection_ends(
17658        &mut self,
17659        _: &actions::SwapSelectionEnds,
17660        window: &mut Window,
17661        cx: &mut Context<Self>,
17662    ) {
17663        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17664            s.move_with(|_, sel| {
17665                if sel.start != sel.end {
17666                    sel.reversed = !sel.reversed
17667                }
17668            });
17669        });
17670        self.request_autoscroll(Autoscroll::newest(), cx);
17671        cx.notify();
17672    }
17673
17674    pub fn toggle_focus(
17675        workspace: &mut Workspace,
17676        _: &actions::ToggleFocus,
17677        window: &mut Window,
17678        cx: &mut Context<Workspace>,
17679    ) {
17680        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17681            return;
17682        };
17683        workspace.activate_item(&item, true, true, window, cx);
17684    }
17685
17686    pub fn toggle_fold(
17687        &mut self,
17688        _: &actions::ToggleFold,
17689        window: &mut Window,
17690        cx: &mut Context<Self>,
17691    ) {
17692        if self.is_singleton(cx) {
17693            let selection = self.selections.newest::<Point>(cx);
17694
17695            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17696            let range = if selection.is_empty() {
17697                let point = selection.head().to_display_point(&display_map);
17698                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17699                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17700                    .to_point(&display_map);
17701                start..end
17702            } else {
17703                selection.range()
17704            };
17705            if display_map.folds_in_range(range).next().is_some() {
17706                self.unfold_lines(&Default::default(), window, cx)
17707            } else {
17708                self.fold(&Default::default(), window, cx)
17709            }
17710        } else {
17711            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17712            let buffer_ids: HashSet<_> = self
17713                .selections
17714                .disjoint_anchor_ranges()
17715                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17716                .collect();
17717
17718            let should_unfold = buffer_ids
17719                .iter()
17720                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17721
17722            for buffer_id in buffer_ids {
17723                if should_unfold {
17724                    self.unfold_buffer(buffer_id, cx);
17725                } else {
17726                    self.fold_buffer(buffer_id, cx);
17727                }
17728            }
17729        }
17730    }
17731
17732    pub fn toggle_fold_recursive(
17733        &mut self,
17734        _: &actions::ToggleFoldRecursive,
17735        window: &mut Window,
17736        cx: &mut Context<Self>,
17737    ) {
17738        let selection = self.selections.newest::<Point>(cx);
17739
17740        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17741        let range = if selection.is_empty() {
17742            let point = selection.head().to_display_point(&display_map);
17743            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17744            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17745                .to_point(&display_map);
17746            start..end
17747        } else {
17748            selection.range()
17749        };
17750        if display_map.folds_in_range(range).next().is_some() {
17751            self.unfold_recursive(&Default::default(), window, cx)
17752        } else {
17753            self.fold_recursive(&Default::default(), window, cx)
17754        }
17755    }
17756
17757    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17758        if self.is_singleton(cx) {
17759            let mut to_fold = Vec::new();
17760            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17761            let selections = self.selections.all_adjusted(cx);
17762
17763            for selection in selections {
17764                let range = selection.range().sorted();
17765                let buffer_start_row = range.start.row;
17766
17767                if range.start.row != range.end.row {
17768                    let mut found = false;
17769                    let mut row = range.start.row;
17770                    while row <= range.end.row {
17771                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17772                        {
17773                            found = true;
17774                            row = crease.range().end.row + 1;
17775                            to_fold.push(crease);
17776                        } else {
17777                            row += 1
17778                        }
17779                    }
17780                    if found {
17781                        continue;
17782                    }
17783                }
17784
17785                for row in (0..=range.start.row).rev() {
17786                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17787                        && crease.range().end.row >= buffer_start_row
17788                    {
17789                        to_fold.push(crease);
17790                        if row <= range.start.row {
17791                            break;
17792                        }
17793                    }
17794                }
17795            }
17796
17797            self.fold_creases(to_fold, true, window, cx);
17798        } else {
17799            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17800            let buffer_ids = self
17801                .selections
17802                .disjoint_anchor_ranges()
17803                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17804                .collect::<HashSet<_>>();
17805            for buffer_id in buffer_ids {
17806                self.fold_buffer(buffer_id, cx);
17807            }
17808        }
17809    }
17810
17811    pub fn toggle_fold_all(
17812        &mut self,
17813        _: &actions::ToggleFoldAll,
17814        window: &mut Window,
17815        cx: &mut Context<Self>,
17816    ) {
17817        if self.buffer.read(cx).is_singleton() {
17818            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17819            let has_folds = display_map
17820                .folds_in_range(0..display_map.buffer_snapshot.len())
17821                .next()
17822                .is_some();
17823
17824            if has_folds {
17825                self.unfold_all(&actions::UnfoldAll, window, cx);
17826            } else {
17827                self.fold_all(&actions::FoldAll, window, cx);
17828            }
17829        } else {
17830            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17831            let should_unfold = buffer_ids
17832                .iter()
17833                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17834
17835            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17836                editor
17837                    .update_in(cx, |editor, _, cx| {
17838                        for buffer_id in buffer_ids {
17839                            if should_unfold {
17840                                editor.unfold_buffer(buffer_id, cx);
17841                            } else {
17842                                editor.fold_buffer(buffer_id, cx);
17843                            }
17844                        }
17845                    })
17846                    .ok();
17847            });
17848        }
17849    }
17850
17851    fn fold_at_level(
17852        &mut self,
17853        fold_at: &FoldAtLevel,
17854        window: &mut Window,
17855        cx: &mut Context<Self>,
17856    ) {
17857        if !self.buffer.read(cx).is_singleton() {
17858            return;
17859        }
17860
17861        let fold_at_level = fold_at.0;
17862        let snapshot = self.buffer.read(cx).snapshot(cx);
17863        let mut to_fold = Vec::new();
17864        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17865
17866        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17867            while start_row < end_row {
17868                match self
17869                    .snapshot(window, cx)
17870                    .crease_for_buffer_row(MultiBufferRow(start_row))
17871                {
17872                    Some(crease) => {
17873                        let nested_start_row = crease.range().start.row + 1;
17874                        let nested_end_row = crease.range().end.row;
17875
17876                        if current_level < fold_at_level {
17877                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17878                        } else if current_level == fold_at_level {
17879                            to_fold.push(crease);
17880                        }
17881
17882                        start_row = nested_end_row + 1;
17883                    }
17884                    None => start_row += 1,
17885                }
17886            }
17887        }
17888
17889        self.fold_creases(to_fold, true, window, cx);
17890    }
17891
17892    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17893        if self.buffer.read(cx).is_singleton() {
17894            let mut fold_ranges = Vec::new();
17895            let snapshot = self.buffer.read(cx).snapshot(cx);
17896
17897            for row in 0..snapshot.max_row().0 {
17898                if let Some(foldable_range) = self
17899                    .snapshot(window, cx)
17900                    .crease_for_buffer_row(MultiBufferRow(row))
17901                {
17902                    fold_ranges.push(foldable_range);
17903                }
17904            }
17905
17906            self.fold_creases(fold_ranges, true, window, cx);
17907        } else {
17908            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17909                editor
17910                    .update_in(cx, |editor, _, cx| {
17911                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17912                            editor.fold_buffer(buffer_id, cx);
17913                        }
17914                    })
17915                    .ok();
17916            });
17917        }
17918    }
17919
17920    pub fn fold_function_bodies(
17921        &mut self,
17922        _: &actions::FoldFunctionBodies,
17923        window: &mut Window,
17924        cx: &mut Context<Self>,
17925    ) {
17926        let snapshot = self.buffer.read(cx).snapshot(cx);
17927
17928        let ranges = snapshot
17929            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17930            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17931            .collect::<Vec<_>>();
17932
17933        let creases = ranges
17934            .into_iter()
17935            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17936            .collect();
17937
17938        self.fold_creases(creases, true, window, cx);
17939    }
17940
17941    pub fn fold_recursive(
17942        &mut self,
17943        _: &actions::FoldRecursive,
17944        window: &mut Window,
17945        cx: &mut Context<Self>,
17946    ) {
17947        let mut to_fold = Vec::new();
17948        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17949        let selections = self.selections.all_adjusted(cx);
17950
17951        for selection in selections {
17952            let range = selection.range().sorted();
17953            let buffer_start_row = range.start.row;
17954
17955            if range.start.row != range.end.row {
17956                let mut found = false;
17957                for row in range.start.row..=range.end.row {
17958                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17959                        found = true;
17960                        to_fold.push(crease);
17961                    }
17962                }
17963                if found {
17964                    continue;
17965                }
17966            }
17967
17968            for row in (0..=range.start.row).rev() {
17969                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17970                    if crease.range().end.row >= buffer_start_row {
17971                        to_fold.push(crease);
17972                    } else {
17973                        break;
17974                    }
17975                }
17976            }
17977        }
17978
17979        self.fold_creases(to_fold, true, window, cx);
17980    }
17981
17982    pub fn fold_at(
17983        &mut self,
17984        buffer_row: MultiBufferRow,
17985        window: &mut Window,
17986        cx: &mut Context<Self>,
17987    ) {
17988        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17989
17990        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17991            let autoscroll = self
17992                .selections
17993                .all::<Point>(cx)
17994                .iter()
17995                .any(|selection| crease.range().overlaps(&selection.range()));
17996
17997            self.fold_creases(vec![crease], autoscroll, window, cx);
17998        }
17999    }
18000
18001    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18002        if self.is_singleton(cx) {
18003            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18004            let buffer = &display_map.buffer_snapshot;
18005            let selections = self.selections.all::<Point>(cx);
18006            let ranges = selections
18007                .iter()
18008                .map(|s| {
18009                    let range = s.display_range(&display_map).sorted();
18010                    let mut start = range.start.to_point(&display_map);
18011                    let mut end = range.end.to_point(&display_map);
18012                    start.column = 0;
18013                    end.column = buffer.line_len(MultiBufferRow(end.row));
18014                    start..end
18015                })
18016                .collect::<Vec<_>>();
18017
18018            self.unfold_ranges(&ranges, true, true, cx);
18019        } else {
18020            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18021            let buffer_ids = self
18022                .selections
18023                .disjoint_anchor_ranges()
18024                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18025                .collect::<HashSet<_>>();
18026            for buffer_id in buffer_ids {
18027                self.unfold_buffer(buffer_id, cx);
18028            }
18029        }
18030    }
18031
18032    pub fn unfold_recursive(
18033        &mut self,
18034        _: &UnfoldRecursive,
18035        _window: &mut Window,
18036        cx: &mut Context<Self>,
18037    ) {
18038        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18039        let selections = self.selections.all::<Point>(cx);
18040        let ranges = selections
18041            .iter()
18042            .map(|s| {
18043                let mut range = s.display_range(&display_map).sorted();
18044                *range.start.column_mut() = 0;
18045                *range.end.column_mut() = display_map.line_len(range.end.row());
18046                let start = range.start.to_point(&display_map);
18047                let end = range.end.to_point(&display_map);
18048                start..end
18049            })
18050            .collect::<Vec<_>>();
18051
18052        self.unfold_ranges(&ranges, true, true, cx);
18053    }
18054
18055    pub fn unfold_at(
18056        &mut self,
18057        buffer_row: MultiBufferRow,
18058        _window: &mut Window,
18059        cx: &mut Context<Self>,
18060    ) {
18061        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18062
18063        let intersection_range = Point::new(buffer_row.0, 0)
18064            ..Point::new(
18065                buffer_row.0,
18066                display_map.buffer_snapshot.line_len(buffer_row),
18067            );
18068
18069        let autoscroll = self
18070            .selections
18071            .all::<Point>(cx)
18072            .iter()
18073            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18074
18075        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18076    }
18077
18078    pub fn unfold_all(
18079        &mut self,
18080        _: &actions::UnfoldAll,
18081        _window: &mut Window,
18082        cx: &mut Context<Self>,
18083    ) {
18084        if self.buffer.read(cx).is_singleton() {
18085            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18086            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18087        } else {
18088            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18089                editor
18090                    .update(cx, |editor, cx| {
18091                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18092                            editor.unfold_buffer(buffer_id, cx);
18093                        }
18094                    })
18095                    .ok();
18096            });
18097        }
18098    }
18099
18100    pub fn fold_selected_ranges(
18101        &mut self,
18102        _: &FoldSelectedRanges,
18103        window: &mut Window,
18104        cx: &mut Context<Self>,
18105    ) {
18106        let selections = self.selections.all_adjusted(cx);
18107        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18108        let ranges = selections
18109            .into_iter()
18110            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18111            .collect::<Vec<_>>();
18112        self.fold_creases(ranges, true, window, cx);
18113    }
18114
18115    pub fn fold_ranges<T: ToOffset + Clone>(
18116        &mut self,
18117        ranges: Vec<Range<T>>,
18118        auto_scroll: bool,
18119        window: &mut Window,
18120        cx: &mut Context<Self>,
18121    ) {
18122        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18123        let ranges = ranges
18124            .into_iter()
18125            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18126            .collect::<Vec<_>>();
18127        self.fold_creases(ranges, auto_scroll, window, cx);
18128    }
18129
18130    pub fn fold_creases<T: ToOffset + Clone>(
18131        &mut self,
18132        creases: Vec<Crease<T>>,
18133        auto_scroll: bool,
18134        _window: &mut Window,
18135        cx: &mut Context<Self>,
18136    ) {
18137        if creases.is_empty() {
18138            return;
18139        }
18140
18141        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18142
18143        if auto_scroll {
18144            self.request_autoscroll(Autoscroll::fit(), cx);
18145        }
18146
18147        cx.notify();
18148
18149        self.scrollbar_marker_state.dirty = true;
18150        self.folds_did_change(cx);
18151    }
18152
18153    /// Removes any folds whose ranges intersect any of the given ranges.
18154    pub fn unfold_ranges<T: ToOffset + Clone>(
18155        &mut self,
18156        ranges: &[Range<T>],
18157        inclusive: bool,
18158        auto_scroll: bool,
18159        cx: &mut Context<Self>,
18160    ) {
18161        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18162            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18163        });
18164        self.folds_did_change(cx);
18165    }
18166
18167    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18168        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18169            return;
18170        }
18171        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18172        self.display_map.update(cx, |display_map, cx| {
18173            display_map.fold_buffers([buffer_id], cx)
18174        });
18175        cx.emit(EditorEvent::BufferFoldToggled {
18176            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18177            folded: true,
18178        });
18179        cx.notify();
18180    }
18181
18182    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18183        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18184            return;
18185        }
18186        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18187        self.display_map.update(cx, |display_map, cx| {
18188            display_map.unfold_buffers([buffer_id], cx);
18189        });
18190        cx.emit(EditorEvent::BufferFoldToggled {
18191            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18192            folded: false,
18193        });
18194        cx.notify();
18195    }
18196
18197    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18198        self.display_map.read(cx).is_buffer_folded(buffer)
18199    }
18200
18201    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18202        self.display_map.read(cx).folded_buffers()
18203    }
18204
18205    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18206        self.display_map.update(cx, |display_map, cx| {
18207            display_map.disable_header_for_buffer(buffer_id, cx);
18208        });
18209        cx.notify();
18210    }
18211
18212    /// Removes any folds with the given ranges.
18213    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18214        &mut self,
18215        ranges: &[Range<T>],
18216        type_id: TypeId,
18217        auto_scroll: bool,
18218        cx: &mut Context<Self>,
18219    ) {
18220        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18221            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18222        });
18223        self.folds_did_change(cx);
18224    }
18225
18226    fn remove_folds_with<T: ToOffset + Clone>(
18227        &mut self,
18228        ranges: &[Range<T>],
18229        auto_scroll: bool,
18230        cx: &mut Context<Self>,
18231        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18232    ) {
18233        if ranges.is_empty() {
18234            return;
18235        }
18236
18237        let mut buffers_affected = HashSet::default();
18238        let multi_buffer = self.buffer().read(cx);
18239        for range in ranges {
18240            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18241                buffers_affected.insert(buffer.read(cx).remote_id());
18242            };
18243        }
18244
18245        self.display_map.update(cx, update);
18246
18247        if auto_scroll {
18248            self.request_autoscroll(Autoscroll::fit(), cx);
18249        }
18250
18251        cx.notify();
18252        self.scrollbar_marker_state.dirty = true;
18253        self.active_indent_guides_state.dirty = true;
18254    }
18255
18256    pub fn update_renderer_widths(
18257        &mut self,
18258        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18259        cx: &mut Context<Self>,
18260    ) -> bool {
18261        self.display_map
18262            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18263    }
18264
18265    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18266        self.display_map.read(cx).fold_placeholder.clone()
18267    }
18268
18269    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18270        self.buffer.update(cx, |buffer, cx| {
18271            buffer.set_all_diff_hunks_expanded(cx);
18272        });
18273    }
18274
18275    pub fn expand_all_diff_hunks(
18276        &mut self,
18277        _: &ExpandAllDiffHunks,
18278        _window: &mut Window,
18279        cx: &mut Context<Self>,
18280    ) {
18281        self.buffer.update(cx, |buffer, cx| {
18282            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18283        });
18284    }
18285
18286    pub fn toggle_selected_diff_hunks(
18287        &mut self,
18288        _: &ToggleSelectedDiffHunks,
18289        _window: &mut Window,
18290        cx: &mut Context<Self>,
18291    ) {
18292        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18293        self.toggle_diff_hunks_in_ranges(ranges, cx);
18294    }
18295
18296    pub fn diff_hunks_in_ranges<'a>(
18297        &'a self,
18298        ranges: &'a [Range<Anchor>],
18299        buffer: &'a MultiBufferSnapshot,
18300    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18301        ranges.iter().flat_map(move |range| {
18302            let end_excerpt_id = range.end.excerpt_id;
18303            let range = range.to_point(buffer);
18304            let mut peek_end = range.end;
18305            if range.end.row < buffer.max_row().0 {
18306                peek_end = Point::new(range.end.row + 1, 0);
18307            }
18308            buffer
18309                .diff_hunks_in_range(range.start..peek_end)
18310                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18311        })
18312    }
18313
18314    pub fn has_stageable_diff_hunks_in_ranges(
18315        &self,
18316        ranges: &[Range<Anchor>],
18317        snapshot: &MultiBufferSnapshot,
18318    ) -> bool {
18319        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18320        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18321    }
18322
18323    pub fn toggle_staged_selected_diff_hunks(
18324        &mut self,
18325        _: &::git::ToggleStaged,
18326        _: &mut Window,
18327        cx: &mut Context<Self>,
18328    ) {
18329        let snapshot = self.buffer.read(cx).snapshot(cx);
18330        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18331        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18332        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18333    }
18334
18335    pub fn set_render_diff_hunk_controls(
18336        &mut self,
18337        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18338        cx: &mut Context<Self>,
18339    ) {
18340        self.render_diff_hunk_controls = render_diff_hunk_controls;
18341        cx.notify();
18342    }
18343
18344    pub fn stage_and_next(
18345        &mut self,
18346        _: &::git::StageAndNext,
18347        window: &mut Window,
18348        cx: &mut Context<Self>,
18349    ) {
18350        self.do_stage_or_unstage_and_next(true, window, cx);
18351    }
18352
18353    pub fn unstage_and_next(
18354        &mut self,
18355        _: &::git::UnstageAndNext,
18356        window: &mut Window,
18357        cx: &mut Context<Self>,
18358    ) {
18359        self.do_stage_or_unstage_and_next(false, window, cx);
18360    }
18361
18362    pub fn stage_or_unstage_diff_hunks(
18363        &mut self,
18364        stage: bool,
18365        ranges: Vec<Range<Anchor>>,
18366        cx: &mut Context<Self>,
18367    ) {
18368        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18369        cx.spawn(async move |this, cx| {
18370            task.await?;
18371            this.update(cx, |this, cx| {
18372                let snapshot = this.buffer.read(cx).snapshot(cx);
18373                let chunk_by = this
18374                    .diff_hunks_in_ranges(&ranges, &snapshot)
18375                    .chunk_by(|hunk| hunk.buffer_id);
18376                for (buffer_id, hunks) in &chunk_by {
18377                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18378                }
18379            })
18380        })
18381        .detach_and_log_err(cx);
18382    }
18383
18384    fn save_buffers_for_ranges_if_needed(
18385        &mut self,
18386        ranges: &[Range<Anchor>],
18387        cx: &mut Context<Editor>,
18388    ) -> Task<Result<()>> {
18389        let multibuffer = self.buffer.read(cx);
18390        let snapshot = multibuffer.read(cx);
18391        let buffer_ids: HashSet<_> = ranges
18392            .iter()
18393            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18394            .collect();
18395        drop(snapshot);
18396
18397        let mut buffers = HashSet::default();
18398        for buffer_id in buffer_ids {
18399            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18400                let buffer = buffer_entity.read(cx);
18401                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18402                {
18403                    buffers.insert(buffer_entity);
18404                }
18405            }
18406        }
18407
18408        if let Some(project) = &self.project {
18409            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18410        } else {
18411            Task::ready(Ok(()))
18412        }
18413    }
18414
18415    fn do_stage_or_unstage_and_next(
18416        &mut self,
18417        stage: bool,
18418        window: &mut Window,
18419        cx: &mut Context<Self>,
18420    ) {
18421        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18422
18423        if ranges.iter().any(|range| range.start != range.end) {
18424            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18425            return;
18426        }
18427
18428        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18429        let snapshot = self.snapshot(window, cx);
18430        let position = self.selections.newest::<Point>(cx).head();
18431        let mut row = snapshot
18432            .buffer_snapshot
18433            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18434            .find(|hunk| hunk.row_range.start.0 > position.row)
18435            .map(|hunk| hunk.row_range.start);
18436
18437        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18438        // Outside of the project diff editor, wrap around to the beginning.
18439        if !all_diff_hunks_expanded {
18440            row = row.or_else(|| {
18441                snapshot
18442                    .buffer_snapshot
18443                    .diff_hunks_in_range(Point::zero()..position)
18444                    .find(|hunk| hunk.row_range.end.0 < position.row)
18445                    .map(|hunk| hunk.row_range.start)
18446            });
18447        }
18448
18449        if let Some(row) = row {
18450            let destination = Point::new(row.0, 0);
18451            let autoscroll = Autoscroll::center();
18452
18453            self.unfold_ranges(&[destination..destination], false, false, cx);
18454            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18455                s.select_ranges([destination..destination]);
18456            });
18457        }
18458    }
18459
18460    fn do_stage_or_unstage(
18461        &self,
18462        stage: bool,
18463        buffer_id: BufferId,
18464        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18465        cx: &mut App,
18466    ) -> Option<()> {
18467        let project = self.project()?;
18468        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18469        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18470        let buffer_snapshot = buffer.read(cx).snapshot();
18471        let file_exists = buffer_snapshot
18472            .file()
18473            .is_some_and(|file| file.disk_state().exists());
18474        diff.update(cx, |diff, cx| {
18475            diff.stage_or_unstage_hunks(
18476                stage,
18477                &hunks
18478                    .map(|hunk| buffer_diff::DiffHunk {
18479                        buffer_range: hunk.buffer_range,
18480                        diff_base_byte_range: hunk.diff_base_byte_range,
18481                        secondary_status: hunk.secondary_status,
18482                        range: Point::zero()..Point::zero(), // unused
18483                    })
18484                    .collect::<Vec<_>>(),
18485                &buffer_snapshot,
18486                file_exists,
18487                cx,
18488            )
18489        });
18490        None
18491    }
18492
18493    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18494        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18495        self.buffer
18496            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18497    }
18498
18499    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18500        self.buffer.update(cx, |buffer, cx| {
18501            let ranges = vec![Anchor::min()..Anchor::max()];
18502            if !buffer.all_diff_hunks_expanded()
18503                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18504            {
18505                buffer.collapse_diff_hunks(ranges, cx);
18506                true
18507            } else {
18508                false
18509            }
18510        })
18511    }
18512
18513    fn toggle_diff_hunks_in_ranges(
18514        &mut self,
18515        ranges: Vec<Range<Anchor>>,
18516        cx: &mut Context<Editor>,
18517    ) {
18518        self.buffer.update(cx, |buffer, cx| {
18519            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18520            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18521        })
18522    }
18523
18524    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18525        self.buffer.update(cx, |buffer, cx| {
18526            let snapshot = buffer.snapshot(cx);
18527            let excerpt_id = range.end.excerpt_id;
18528            let point_range = range.to_point(&snapshot);
18529            let expand = !buffer.single_hunk_is_expanded(range, cx);
18530            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18531        })
18532    }
18533
18534    pub(crate) fn apply_all_diff_hunks(
18535        &mut self,
18536        _: &ApplyAllDiffHunks,
18537        window: &mut Window,
18538        cx: &mut Context<Self>,
18539    ) {
18540        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18541
18542        let buffers = self.buffer.read(cx).all_buffers();
18543        for branch_buffer in buffers {
18544            branch_buffer.update(cx, |branch_buffer, cx| {
18545                branch_buffer.merge_into_base(Vec::new(), cx);
18546            });
18547        }
18548
18549        if let Some(project) = self.project.clone() {
18550            self.save(
18551                SaveOptions {
18552                    format: true,
18553                    autosave: false,
18554                },
18555                project,
18556                window,
18557                cx,
18558            )
18559            .detach_and_log_err(cx);
18560        }
18561    }
18562
18563    pub(crate) fn apply_selected_diff_hunks(
18564        &mut self,
18565        _: &ApplyDiffHunk,
18566        window: &mut Window,
18567        cx: &mut Context<Self>,
18568    ) {
18569        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18570        let snapshot = self.snapshot(window, cx);
18571        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18572        let mut ranges_by_buffer = HashMap::default();
18573        self.transact(window, cx, |editor, _window, cx| {
18574            for hunk in hunks {
18575                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18576                    ranges_by_buffer
18577                        .entry(buffer.clone())
18578                        .or_insert_with(Vec::new)
18579                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18580                }
18581            }
18582
18583            for (buffer, ranges) in ranges_by_buffer {
18584                buffer.update(cx, |buffer, cx| {
18585                    buffer.merge_into_base(ranges, cx);
18586                });
18587            }
18588        });
18589
18590        if let Some(project) = self.project.clone() {
18591            self.save(
18592                SaveOptions {
18593                    format: true,
18594                    autosave: false,
18595                },
18596                project,
18597                window,
18598                cx,
18599            )
18600            .detach_and_log_err(cx);
18601        }
18602    }
18603
18604    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18605        if hovered != self.gutter_hovered {
18606            self.gutter_hovered = hovered;
18607            cx.notify();
18608        }
18609    }
18610
18611    pub fn insert_blocks(
18612        &mut self,
18613        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18614        autoscroll: Option<Autoscroll>,
18615        cx: &mut Context<Self>,
18616    ) -> Vec<CustomBlockId> {
18617        let blocks = self
18618            .display_map
18619            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18620        if let Some(autoscroll) = autoscroll {
18621            self.request_autoscroll(autoscroll, cx);
18622        }
18623        cx.notify();
18624        blocks
18625    }
18626
18627    pub fn resize_blocks(
18628        &mut self,
18629        heights: HashMap<CustomBlockId, u32>,
18630        autoscroll: Option<Autoscroll>,
18631        cx: &mut Context<Self>,
18632    ) {
18633        self.display_map
18634            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18635        if let Some(autoscroll) = autoscroll {
18636            self.request_autoscroll(autoscroll, cx);
18637        }
18638        cx.notify();
18639    }
18640
18641    pub fn replace_blocks(
18642        &mut self,
18643        renderers: HashMap<CustomBlockId, RenderBlock>,
18644        autoscroll: Option<Autoscroll>,
18645        cx: &mut Context<Self>,
18646    ) {
18647        self.display_map
18648            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18649        if let Some(autoscroll) = autoscroll {
18650            self.request_autoscroll(autoscroll, cx);
18651        }
18652        cx.notify();
18653    }
18654
18655    pub fn remove_blocks(
18656        &mut self,
18657        block_ids: HashSet<CustomBlockId>,
18658        autoscroll: Option<Autoscroll>,
18659        cx: &mut Context<Self>,
18660    ) {
18661        self.display_map.update(cx, |display_map, cx| {
18662            display_map.remove_blocks(block_ids, cx)
18663        });
18664        if let Some(autoscroll) = autoscroll {
18665            self.request_autoscroll(autoscroll, cx);
18666        }
18667        cx.notify();
18668    }
18669
18670    pub fn row_for_block(
18671        &self,
18672        block_id: CustomBlockId,
18673        cx: &mut Context<Self>,
18674    ) -> Option<DisplayRow> {
18675        self.display_map
18676            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18677    }
18678
18679    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18680        self.focused_block = Some(focused_block);
18681    }
18682
18683    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18684        self.focused_block.take()
18685    }
18686
18687    pub fn insert_creases(
18688        &mut self,
18689        creases: impl IntoIterator<Item = Crease<Anchor>>,
18690        cx: &mut Context<Self>,
18691    ) -> Vec<CreaseId> {
18692        self.display_map
18693            .update(cx, |map, cx| map.insert_creases(creases, cx))
18694    }
18695
18696    pub fn remove_creases(
18697        &mut self,
18698        ids: impl IntoIterator<Item = CreaseId>,
18699        cx: &mut Context<Self>,
18700    ) -> Vec<(CreaseId, Range<Anchor>)> {
18701        self.display_map
18702            .update(cx, |map, cx| map.remove_creases(ids, cx))
18703    }
18704
18705    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18706        self.display_map
18707            .update(cx, |map, cx| map.snapshot(cx))
18708            .longest_row()
18709    }
18710
18711    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18712        self.display_map
18713            .update(cx, |map, cx| map.snapshot(cx))
18714            .max_point()
18715    }
18716
18717    pub fn text(&self, cx: &App) -> String {
18718        self.buffer.read(cx).read(cx).text()
18719    }
18720
18721    pub fn is_empty(&self, cx: &App) -> bool {
18722        self.buffer.read(cx).read(cx).is_empty()
18723    }
18724
18725    pub fn text_option(&self, cx: &App) -> Option<String> {
18726        let text = self.text(cx);
18727        let text = text.trim();
18728
18729        if text.is_empty() {
18730            return None;
18731        }
18732
18733        Some(text.to_string())
18734    }
18735
18736    pub fn set_text(
18737        &mut self,
18738        text: impl Into<Arc<str>>,
18739        window: &mut Window,
18740        cx: &mut Context<Self>,
18741    ) {
18742        self.transact(window, cx, |this, _, cx| {
18743            this.buffer
18744                .read(cx)
18745                .as_singleton()
18746                .expect("you can only call set_text on editors for singleton buffers")
18747                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18748        });
18749    }
18750
18751    pub fn display_text(&self, cx: &mut App) -> String {
18752        self.display_map
18753            .update(cx, |map, cx| map.snapshot(cx))
18754            .text()
18755    }
18756
18757    fn create_minimap(
18758        &self,
18759        minimap_settings: MinimapSettings,
18760        window: &mut Window,
18761        cx: &mut Context<Self>,
18762    ) -> Option<Entity<Self>> {
18763        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18764            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18765    }
18766
18767    fn initialize_new_minimap(
18768        &self,
18769        minimap_settings: MinimapSettings,
18770        window: &mut Window,
18771        cx: &mut Context<Self>,
18772    ) -> Entity<Self> {
18773        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18774
18775        let mut minimap = Editor::new_internal(
18776            EditorMode::Minimap {
18777                parent: cx.weak_entity(),
18778            },
18779            self.buffer.clone(),
18780            None,
18781            Some(self.display_map.clone()),
18782            window,
18783            cx,
18784        );
18785        minimap.scroll_manager.clone_state(&self.scroll_manager);
18786        minimap.set_text_style_refinement(TextStyleRefinement {
18787            font_size: Some(MINIMAP_FONT_SIZE),
18788            font_weight: Some(MINIMAP_FONT_WEIGHT),
18789            ..Default::default()
18790        });
18791        minimap.update_minimap_configuration(minimap_settings, cx);
18792        cx.new(|_| minimap)
18793    }
18794
18795    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18796        let current_line_highlight = minimap_settings
18797            .current_line_highlight
18798            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18799        self.set_current_line_highlight(Some(current_line_highlight));
18800    }
18801
18802    pub fn minimap(&self) -> Option<&Entity<Self>> {
18803        self.minimap
18804            .as_ref()
18805            .filter(|_| self.minimap_visibility.visible())
18806    }
18807
18808    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18809        let mut wrap_guides = smallvec![];
18810
18811        if self.show_wrap_guides == Some(false) {
18812            return wrap_guides;
18813        }
18814
18815        let settings = self.buffer.read(cx).language_settings(cx);
18816        if settings.show_wrap_guides {
18817            match self.soft_wrap_mode(cx) {
18818                SoftWrap::Column(soft_wrap) => {
18819                    wrap_guides.push((soft_wrap as usize, true));
18820                }
18821                SoftWrap::Bounded(soft_wrap) => {
18822                    wrap_guides.push((soft_wrap as usize, true));
18823                }
18824                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18825            }
18826            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18827        }
18828
18829        wrap_guides
18830    }
18831
18832    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18833        let settings = self.buffer.read(cx).language_settings(cx);
18834        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18835        match mode {
18836            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18837                SoftWrap::None
18838            }
18839            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18840            language_settings::SoftWrap::PreferredLineLength => {
18841                SoftWrap::Column(settings.preferred_line_length)
18842            }
18843            language_settings::SoftWrap::Bounded => {
18844                SoftWrap::Bounded(settings.preferred_line_length)
18845            }
18846        }
18847    }
18848
18849    pub fn set_soft_wrap_mode(
18850        &mut self,
18851        mode: language_settings::SoftWrap,
18852
18853        cx: &mut Context<Self>,
18854    ) {
18855        self.soft_wrap_mode_override = Some(mode);
18856        cx.notify();
18857    }
18858
18859    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18860        self.hard_wrap = hard_wrap;
18861        cx.notify();
18862    }
18863
18864    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18865        self.text_style_refinement = Some(style);
18866    }
18867
18868    /// called by the Element so we know what style we were most recently rendered with.
18869    pub(crate) fn set_style(
18870        &mut self,
18871        style: EditorStyle,
18872        window: &mut Window,
18873        cx: &mut Context<Self>,
18874    ) {
18875        // We intentionally do not inform the display map about the minimap style
18876        // so that wrapping is not recalculated and stays consistent for the editor
18877        // and its linked minimap.
18878        if !self.mode.is_minimap() {
18879            let rem_size = window.rem_size();
18880            self.display_map.update(cx, |map, cx| {
18881                map.set_font(
18882                    style.text.font(),
18883                    style.text.font_size.to_pixels(rem_size),
18884                    cx,
18885                )
18886            });
18887        }
18888        self.style = Some(style);
18889    }
18890
18891    pub fn style(&self) -> Option<&EditorStyle> {
18892        self.style.as_ref()
18893    }
18894
18895    // Called by the element. This method is not designed to be called outside of the editor
18896    // element's layout code because it does not notify when rewrapping is computed synchronously.
18897    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18898        self.display_map
18899            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18900    }
18901
18902    pub fn set_soft_wrap(&mut self) {
18903        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18904    }
18905
18906    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18907        if self.soft_wrap_mode_override.is_some() {
18908            self.soft_wrap_mode_override.take();
18909        } else {
18910            let soft_wrap = match self.soft_wrap_mode(cx) {
18911                SoftWrap::GitDiff => return,
18912                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18913                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18914                    language_settings::SoftWrap::None
18915                }
18916            };
18917            self.soft_wrap_mode_override = Some(soft_wrap);
18918        }
18919        cx.notify();
18920    }
18921
18922    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18923        let Some(workspace) = self.workspace() else {
18924            return;
18925        };
18926        let fs = workspace.read(cx).app_state().fs.clone();
18927        let current_show = TabBarSettings::get_global(cx).show;
18928        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18929            setting.show = Some(!current_show);
18930        });
18931    }
18932
18933    pub fn toggle_indent_guides(
18934        &mut self,
18935        _: &ToggleIndentGuides,
18936        _: &mut Window,
18937        cx: &mut Context<Self>,
18938    ) {
18939        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18940            self.buffer
18941                .read(cx)
18942                .language_settings(cx)
18943                .indent_guides
18944                .enabled
18945        });
18946        self.show_indent_guides = Some(!currently_enabled);
18947        cx.notify();
18948    }
18949
18950    fn should_show_indent_guides(&self) -> Option<bool> {
18951        self.show_indent_guides
18952    }
18953
18954    pub fn toggle_line_numbers(
18955        &mut self,
18956        _: &ToggleLineNumbers,
18957        _: &mut Window,
18958        cx: &mut Context<Self>,
18959    ) {
18960        let mut editor_settings = EditorSettings::get_global(cx).clone();
18961        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18962        EditorSettings::override_global(editor_settings, cx);
18963    }
18964
18965    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18966        if let Some(show_line_numbers) = self.show_line_numbers {
18967            return show_line_numbers;
18968        }
18969        EditorSettings::get_global(cx).gutter.line_numbers
18970    }
18971
18972    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18973        self.use_relative_line_numbers
18974            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18975    }
18976
18977    pub fn toggle_relative_line_numbers(
18978        &mut self,
18979        _: &ToggleRelativeLineNumbers,
18980        _: &mut Window,
18981        cx: &mut Context<Self>,
18982    ) {
18983        let is_relative = self.should_use_relative_line_numbers(cx);
18984        self.set_relative_line_number(Some(!is_relative), cx)
18985    }
18986
18987    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18988        self.use_relative_line_numbers = is_relative;
18989        cx.notify();
18990    }
18991
18992    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18993        self.show_gutter = show_gutter;
18994        cx.notify();
18995    }
18996
18997    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18998        self.show_scrollbars = ScrollbarAxes {
18999            horizontal: show,
19000            vertical: show,
19001        };
19002        cx.notify();
19003    }
19004
19005    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19006        self.show_scrollbars.vertical = show;
19007        cx.notify();
19008    }
19009
19010    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19011        self.show_scrollbars.horizontal = show;
19012        cx.notify();
19013    }
19014
19015    pub fn set_minimap_visibility(
19016        &mut self,
19017        minimap_visibility: MinimapVisibility,
19018        window: &mut Window,
19019        cx: &mut Context<Self>,
19020    ) {
19021        if self.minimap_visibility != minimap_visibility {
19022            if minimap_visibility.visible() && self.minimap.is_none() {
19023                let minimap_settings = EditorSettings::get_global(cx).minimap;
19024                self.minimap =
19025                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19026            }
19027            self.minimap_visibility = minimap_visibility;
19028            cx.notify();
19029        }
19030    }
19031
19032    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19033        self.set_show_scrollbars(false, cx);
19034        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19035    }
19036
19037    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19038        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19039    }
19040
19041    /// Normally the text in full mode and auto height editors is padded on the
19042    /// left side by roughly half a character width for improved hit testing.
19043    ///
19044    /// Use this method to disable this for cases where this is not wanted (e.g.
19045    /// if you want to align the editor text with some other text above or below)
19046    /// or if you want to add this padding to single-line editors.
19047    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19048        self.offset_content = offset_content;
19049        cx.notify();
19050    }
19051
19052    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19053        self.show_line_numbers = Some(show_line_numbers);
19054        cx.notify();
19055    }
19056
19057    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19058        self.disable_expand_excerpt_buttons = true;
19059        cx.notify();
19060    }
19061
19062    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19063        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19064        cx.notify();
19065    }
19066
19067    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19068        self.show_code_actions = Some(show_code_actions);
19069        cx.notify();
19070    }
19071
19072    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19073        self.show_runnables = Some(show_runnables);
19074        cx.notify();
19075    }
19076
19077    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19078        self.show_breakpoints = Some(show_breakpoints);
19079        cx.notify();
19080    }
19081
19082    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19083        if self.display_map.read(cx).masked != masked {
19084            self.display_map.update(cx, |map, _| map.masked = masked);
19085        }
19086        cx.notify()
19087    }
19088
19089    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19090        self.show_wrap_guides = Some(show_wrap_guides);
19091        cx.notify();
19092    }
19093
19094    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19095        self.show_indent_guides = Some(show_indent_guides);
19096        cx.notify();
19097    }
19098
19099    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19100        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19101            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19102                && let Some(dir) = file.abs_path(cx).parent()
19103            {
19104                return Some(dir.to_owned());
19105            }
19106
19107            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19108                return Some(project_path.path.to_path_buf());
19109            }
19110        }
19111
19112        None
19113    }
19114
19115    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19116        self.active_excerpt(cx)?
19117            .1
19118            .read(cx)
19119            .file()
19120            .and_then(|f| f.as_local())
19121    }
19122
19123    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19124        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19125            let buffer = buffer.read(cx);
19126            if let Some(project_path) = buffer.project_path(cx) {
19127                let project = self.project()?.read(cx);
19128                project.absolute_path(&project_path, cx)
19129            } else {
19130                buffer
19131                    .file()
19132                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19133            }
19134        })
19135    }
19136
19137    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19138        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19139            let project_path = buffer.read(cx).project_path(cx)?;
19140            let project = self.project()?.read(cx);
19141            let entry = project.entry_for_path(&project_path, cx)?;
19142            let path = entry.path.to_path_buf();
19143            Some(path)
19144        })
19145    }
19146
19147    pub fn reveal_in_finder(
19148        &mut self,
19149        _: &RevealInFileManager,
19150        _window: &mut Window,
19151        cx: &mut Context<Self>,
19152    ) {
19153        if let Some(target) = self.target_file(cx) {
19154            cx.reveal_path(&target.abs_path(cx));
19155        }
19156    }
19157
19158    pub fn copy_path(
19159        &mut self,
19160        _: &zed_actions::workspace::CopyPath,
19161        _window: &mut Window,
19162        cx: &mut Context<Self>,
19163    ) {
19164        if let Some(path) = self.target_file_abs_path(cx)
19165            && let Some(path) = path.to_str()
19166        {
19167            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19168        }
19169    }
19170
19171    pub fn copy_relative_path(
19172        &mut self,
19173        _: &zed_actions::workspace::CopyRelativePath,
19174        _window: &mut Window,
19175        cx: &mut Context<Self>,
19176    ) {
19177        if let Some(path) = self.target_file_path(cx)
19178            && let Some(path) = path.to_str()
19179        {
19180            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19181        }
19182    }
19183
19184    /// Returns the project path for the editor's buffer, if any buffer is
19185    /// opened in the editor.
19186    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19187        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19188            buffer.read(cx).project_path(cx)
19189        } else {
19190            None
19191        }
19192    }
19193
19194    // Returns true if the editor handled a go-to-line request
19195    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19196        maybe!({
19197            let breakpoint_store = self.breakpoint_store.as_ref()?;
19198
19199            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19200            else {
19201                self.clear_row_highlights::<ActiveDebugLine>();
19202                return None;
19203            };
19204
19205            let position = active_stack_frame.position;
19206            let buffer_id = position.buffer_id?;
19207            let snapshot = self
19208                .project
19209                .as_ref()?
19210                .read(cx)
19211                .buffer_for_id(buffer_id, cx)?
19212                .read(cx)
19213                .snapshot();
19214
19215            let mut handled = false;
19216            for (id, ExcerptRange { context, .. }) in
19217                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19218            {
19219                if context.start.cmp(&position, &snapshot).is_ge()
19220                    || context.end.cmp(&position, &snapshot).is_lt()
19221                {
19222                    continue;
19223                }
19224                let snapshot = self.buffer.read(cx).snapshot(cx);
19225                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19226
19227                handled = true;
19228                self.clear_row_highlights::<ActiveDebugLine>();
19229
19230                self.go_to_line::<ActiveDebugLine>(
19231                    multibuffer_anchor,
19232                    Some(cx.theme().colors().editor_debugger_active_line_background),
19233                    window,
19234                    cx,
19235                );
19236
19237                cx.notify();
19238            }
19239
19240            handled.then_some(())
19241        })
19242        .is_some()
19243    }
19244
19245    pub fn copy_file_name_without_extension(
19246        &mut self,
19247        _: &CopyFileNameWithoutExtension,
19248        _: &mut Window,
19249        cx: &mut Context<Self>,
19250    ) {
19251        if let Some(file) = self.target_file(cx)
19252            && let Some(file_stem) = file.path().file_stem()
19253            && let Some(name) = file_stem.to_str()
19254        {
19255            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19256        }
19257    }
19258
19259    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19260        if let Some(file) = self.target_file(cx)
19261            && let Some(file_name) = file.path().file_name()
19262            && let Some(name) = file_name.to_str()
19263        {
19264            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19265        }
19266    }
19267
19268    pub fn toggle_git_blame(
19269        &mut self,
19270        _: &::git::Blame,
19271        window: &mut Window,
19272        cx: &mut Context<Self>,
19273    ) {
19274        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19275
19276        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19277            self.start_git_blame(true, window, cx);
19278        }
19279
19280        cx.notify();
19281    }
19282
19283    pub fn toggle_git_blame_inline(
19284        &mut self,
19285        _: &ToggleGitBlameInline,
19286        window: &mut Window,
19287        cx: &mut Context<Self>,
19288    ) {
19289        self.toggle_git_blame_inline_internal(true, window, cx);
19290        cx.notify();
19291    }
19292
19293    pub fn open_git_blame_commit(
19294        &mut self,
19295        _: &OpenGitBlameCommit,
19296        window: &mut Window,
19297        cx: &mut Context<Self>,
19298    ) {
19299        self.open_git_blame_commit_internal(window, cx);
19300    }
19301
19302    fn open_git_blame_commit_internal(
19303        &mut self,
19304        window: &mut Window,
19305        cx: &mut Context<Self>,
19306    ) -> Option<()> {
19307        let blame = self.blame.as_ref()?;
19308        let snapshot = self.snapshot(window, cx);
19309        let cursor = self.selections.newest::<Point>(cx).head();
19310        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19311        let (_, blame_entry) = blame
19312            .update(cx, |blame, cx| {
19313                blame
19314                    .blame_for_rows(
19315                        &[RowInfo {
19316                            buffer_id: Some(buffer.remote_id()),
19317                            buffer_row: Some(point.row),
19318                            ..Default::default()
19319                        }],
19320                        cx,
19321                    )
19322                    .next()
19323            })
19324            .flatten()?;
19325        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19326        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19327        let workspace = self.workspace()?.downgrade();
19328        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19329        None
19330    }
19331
19332    pub fn git_blame_inline_enabled(&self) -> bool {
19333        self.git_blame_inline_enabled
19334    }
19335
19336    pub fn toggle_selection_menu(
19337        &mut self,
19338        _: &ToggleSelectionMenu,
19339        _: &mut Window,
19340        cx: &mut Context<Self>,
19341    ) {
19342        self.show_selection_menu = self
19343            .show_selection_menu
19344            .map(|show_selections_menu| !show_selections_menu)
19345            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19346
19347        cx.notify();
19348    }
19349
19350    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19351        self.show_selection_menu
19352            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19353    }
19354
19355    fn start_git_blame(
19356        &mut self,
19357        user_triggered: bool,
19358        window: &mut Window,
19359        cx: &mut Context<Self>,
19360    ) {
19361        if let Some(project) = self.project() {
19362            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19363                && buffer.read(cx).file().is_none()
19364            {
19365                return;
19366            }
19367
19368            let focused = self.focus_handle(cx).contains_focused(window, cx);
19369
19370            let project = project.clone();
19371            let blame = cx
19372                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19373            self.blame_subscription =
19374                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19375            self.blame = Some(blame);
19376        }
19377    }
19378
19379    fn toggle_git_blame_inline_internal(
19380        &mut self,
19381        user_triggered: bool,
19382        window: &mut Window,
19383        cx: &mut Context<Self>,
19384    ) {
19385        if self.git_blame_inline_enabled {
19386            self.git_blame_inline_enabled = false;
19387            self.show_git_blame_inline = false;
19388            self.show_git_blame_inline_delay_task.take();
19389        } else {
19390            self.git_blame_inline_enabled = true;
19391            self.start_git_blame_inline(user_triggered, window, cx);
19392        }
19393
19394        cx.notify();
19395    }
19396
19397    fn start_git_blame_inline(
19398        &mut self,
19399        user_triggered: bool,
19400        window: &mut Window,
19401        cx: &mut Context<Self>,
19402    ) {
19403        self.start_git_blame(user_triggered, window, cx);
19404
19405        if ProjectSettings::get_global(cx)
19406            .git
19407            .inline_blame_delay()
19408            .is_some()
19409        {
19410            self.start_inline_blame_timer(window, cx);
19411        } else {
19412            self.show_git_blame_inline = true
19413        }
19414    }
19415
19416    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19417        self.blame.as_ref()
19418    }
19419
19420    pub fn show_git_blame_gutter(&self) -> bool {
19421        self.show_git_blame_gutter
19422    }
19423
19424    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19425        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19426    }
19427
19428    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19429        self.show_git_blame_inline
19430            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19431            && !self.newest_selection_head_on_empty_line(cx)
19432            && self.has_blame_entries(cx)
19433    }
19434
19435    fn has_blame_entries(&self, cx: &App) -> bool {
19436        self.blame()
19437            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19438    }
19439
19440    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19441        let cursor_anchor = self.selections.newest_anchor().head();
19442
19443        let snapshot = self.buffer.read(cx).snapshot(cx);
19444        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19445
19446        snapshot.line_len(buffer_row) == 0
19447    }
19448
19449    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19450        let buffer_and_selection = maybe!({
19451            let selection = self.selections.newest::<Point>(cx);
19452            let selection_range = selection.range();
19453
19454            let multi_buffer = self.buffer().read(cx);
19455            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19456            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19457
19458            let (buffer, range, _) = if selection.reversed {
19459                buffer_ranges.first()
19460            } else {
19461                buffer_ranges.last()
19462            }?;
19463
19464            let selection = text::ToPoint::to_point(&range.start, buffer).row
19465                ..text::ToPoint::to_point(&range.end, buffer).row;
19466            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19467        });
19468
19469        let Some((buffer, selection)) = buffer_and_selection else {
19470            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19471        };
19472
19473        let Some(project) = self.project() else {
19474            return Task::ready(Err(anyhow!("editor does not have project")));
19475        };
19476
19477        project.update(cx, |project, cx| {
19478            project.get_permalink_to_line(&buffer, selection, cx)
19479        })
19480    }
19481
19482    pub fn copy_permalink_to_line(
19483        &mut self,
19484        _: &CopyPermalinkToLine,
19485        window: &mut Window,
19486        cx: &mut Context<Self>,
19487    ) {
19488        let permalink_task = self.get_permalink_to_line(cx);
19489        let workspace = self.workspace();
19490
19491        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19492            Ok(permalink) => {
19493                cx.update(|_, cx| {
19494                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19495                })
19496                .ok();
19497            }
19498            Err(err) => {
19499                let message = format!("Failed to copy permalink: {err}");
19500
19501                anyhow::Result::<()>::Err(err).log_err();
19502
19503                if let Some(workspace) = workspace {
19504                    workspace
19505                        .update_in(cx, |workspace, _, cx| {
19506                            struct CopyPermalinkToLine;
19507
19508                            workspace.show_toast(
19509                                Toast::new(
19510                                    NotificationId::unique::<CopyPermalinkToLine>(),
19511                                    message,
19512                                ),
19513                                cx,
19514                            )
19515                        })
19516                        .ok();
19517                }
19518            }
19519        })
19520        .detach();
19521    }
19522
19523    pub fn copy_file_location(
19524        &mut self,
19525        _: &CopyFileLocation,
19526        _: &mut Window,
19527        cx: &mut Context<Self>,
19528    ) {
19529        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19530        if let Some(file) = self.target_file(cx)
19531            && let Some(path) = file.path().to_str()
19532        {
19533            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19534        }
19535    }
19536
19537    pub fn open_permalink_to_line(
19538        &mut self,
19539        _: &OpenPermalinkToLine,
19540        window: &mut Window,
19541        cx: &mut Context<Self>,
19542    ) {
19543        let permalink_task = self.get_permalink_to_line(cx);
19544        let workspace = self.workspace();
19545
19546        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19547            Ok(permalink) => {
19548                cx.update(|_, cx| {
19549                    cx.open_url(permalink.as_ref());
19550                })
19551                .ok();
19552            }
19553            Err(err) => {
19554                let message = format!("Failed to open permalink: {err}");
19555
19556                anyhow::Result::<()>::Err(err).log_err();
19557
19558                if let Some(workspace) = workspace {
19559                    workspace
19560                        .update(cx, |workspace, cx| {
19561                            struct OpenPermalinkToLine;
19562
19563                            workspace.show_toast(
19564                                Toast::new(
19565                                    NotificationId::unique::<OpenPermalinkToLine>(),
19566                                    message,
19567                                ),
19568                                cx,
19569                            )
19570                        })
19571                        .ok();
19572                }
19573            }
19574        })
19575        .detach();
19576    }
19577
19578    pub fn insert_uuid_v4(
19579        &mut self,
19580        _: &InsertUuidV4,
19581        window: &mut Window,
19582        cx: &mut Context<Self>,
19583    ) {
19584        self.insert_uuid(UuidVersion::V4, window, cx);
19585    }
19586
19587    pub fn insert_uuid_v7(
19588        &mut self,
19589        _: &InsertUuidV7,
19590        window: &mut Window,
19591        cx: &mut Context<Self>,
19592    ) {
19593        self.insert_uuid(UuidVersion::V7, window, cx);
19594    }
19595
19596    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19597        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19598        self.transact(window, cx, |this, window, cx| {
19599            let edits = this
19600                .selections
19601                .all::<Point>(cx)
19602                .into_iter()
19603                .map(|selection| {
19604                    let uuid = match version {
19605                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19606                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19607                    };
19608
19609                    (selection.range(), uuid.to_string())
19610                });
19611            this.edit(edits, cx);
19612            this.refresh_edit_prediction(true, false, window, cx);
19613        });
19614    }
19615
19616    pub fn open_selections_in_multibuffer(
19617        &mut self,
19618        _: &OpenSelectionsInMultibuffer,
19619        window: &mut Window,
19620        cx: &mut Context<Self>,
19621    ) {
19622        let multibuffer = self.buffer.read(cx);
19623
19624        let Some(buffer) = multibuffer.as_singleton() else {
19625            return;
19626        };
19627
19628        let Some(workspace) = self.workspace() else {
19629            return;
19630        };
19631
19632        let title = multibuffer.title(cx).to_string();
19633
19634        let locations = self
19635            .selections
19636            .all_anchors(cx)
19637            .iter()
19638            .map(|selection| Location {
19639                buffer: buffer.clone(),
19640                range: selection.start.text_anchor..selection.end.text_anchor,
19641            })
19642            .collect::<Vec<_>>();
19643
19644        cx.spawn_in(window, async move |_, cx| {
19645            workspace.update_in(cx, |workspace, window, cx| {
19646                Self::open_locations_in_multibuffer(
19647                    workspace,
19648                    locations,
19649                    format!("Selections for '{title}'"),
19650                    false,
19651                    MultibufferSelectionMode::All,
19652                    window,
19653                    cx,
19654                );
19655            })
19656        })
19657        .detach();
19658    }
19659
19660    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19661    /// last highlight added will be used.
19662    ///
19663    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19664    pub fn highlight_rows<T: 'static>(
19665        &mut self,
19666        range: Range<Anchor>,
19667        color: Hsla,
19668        options: RowHighlightOptions,
19669        cx: &mut Context<Self>,
19670    ) {
19671        let snapshot = self.buffer().read(cx).snapshot(cx);
19672        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19673        let ix = row_highlights.binary_search_by(|highlight| {
19674            Ordering::Equal
19675                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19676                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19677        });
19678
19679        if let Err(mut ix) = ix {
19680            let index = post_inc(&mut self.highlight_order);
19681
19682            // If this range intersects with the preceding highlight, then merge it with
19683            // the preceding highlight. Otherwise insert a new highlight.
19684            let mut merged = false;
19685            if ix > 0 {
19686                let prev_highlight = &mut row_highlights[ix - 1];
19687                if prev_highlight
19688                    .range
19689                    .end
19690                    .cmp(&range.start, &snapshot)
19691                    .is_ge()
19692                {
19693                    ix -= 1;
19694                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19695                        prev_highlight.range.end = range.end;
19696                    }
19697                    merged = true;
19698                    prev_highlight.index = index;
19699                    prev_highlight.color = color;
19700                    prev_highlight.options = options;
19701                }
19702            }
19703
19704            if !merged {
19705                row_highlights.insert(
19706                    ix,
19707                    RowHighlight {
19708                        range,
19709                        index,
19710                        color,
19711                        options,
19712                        type_id: TypeId::of::<T>(),
19713                    },
19714                );
19715            }
19716
19717            // If any of the following highlights intersect with this one, merge them.
19718            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19719                let highlight = &row_highlights[ix];
19720                if next_highlight
19721                    .range
19722                    .start
19723                    .cmp(&highlight.range.end, &snapshot)
19724                    .is_le()
19725                {
19726                    if next_highlight
19727                        .range
19728                        .end
19729                        .cmp(&highlight.range.end, &snapshot)
19730                        .is_gt()
19731                    {
19732                        row_highlights[ix].range.end = next_highlight.range.end;
19733                    }
19734                    row_highlights.remove(ix + 1);
19735                } else {
19736                    break;
19737                }
19738            }
19739        }
19740    }
19741
19742    /// Remove any highlighted row ranges of the given type that intersect the
19743    /// given ranges.
19744    pub fn remove_highlighted_rows<T: 'static>(
19745        &mut self,
19746        ranges_to_remove: Vec<Range<Anchor>>,
19747        cx: &mut Context<Self>,
19748    ) {
19749        let snapshot = self.buffer().read(cx).snapshot(cx);
19750        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19751        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19752        row_highlights.retain(|highlight| {
19753            while let Some(range_to_remove) = ranges_to_remove.peek() {
19754                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19755                    Ordering::Less | Ordering::Equal => {
19756                        ranges_to_remove.next();
19757                    }
19758                    Ordering::Greater => {
19759                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19760                            Ordering::Less | Ordering::Equal => {
19761                                return false;
19762                            }
19763                            Ordering::Greater => break,
19764                        }
19765                    }
19766                }
19767            }
19768
19769            true
19770        })
19771    }
19772
19773    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19774    pub fn clear_row_highlights<T: 'static>(&mut self) {
19775        self.highlighted_rows.remove(&TypeId::of::<T>());
19776    }
19777
19778    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19779    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19780        self.highlighted_rows
19781            .get(&TypeId::of::<T>())
19782            .map_or(&[] as &[_], |vec| vec.as_slice())
19783            .iter()
19784            .map(|highlight| (highlight.range.clone(), highlight.color))
19785    }
19786
19787    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19788    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19789    /// Allows to ignore certain kinds of highlights.
19790    pub fn highlighted_display_rows(
19791        &self,
19792        window: &mut Window,
19793        cx: &mut App,
19794    ) -> BTreeMap<DisplayRow, LineHighlight> {
19795        let snapshot = self.snapshot(window, cx);
19796        let mut used_highlight_orders = HashMap::default();
19797        self.highlighted_rows
19798            .iter()
19799            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19800            .fold(
19801                BTreeMap::<DisplayRow, LineHighlight>::new(),
19802                |mut unique_rows, highlight| {
19803                    let start = highlight.range.start.to_display_point(&snapshot);
19804                    let end = highlight.range.end.to_display_point(&snapshot);
19805                    let start_row = start.row().0;
19806                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19807                        && end.column() == 0
19808                    {
19809                        end.row().0.saturating_sub(1)
19810                    } else {
19811                        end.row().0
19812                    };
19813                    for row in start_row..=end_row {
19814                        let used_index =
19815                            used_highlight_orders.entry(row).or_insert(highlight.index);
19816                        if highlight.index >= *used_index {
19817                            *used_index = highlight.index;
19818                            unique_rows.insert(
19819                                DisplayRow(row),
19820                                LineHighlight {
19821                                    include_gutter: highlight.options.include_gutter,
19822                                    border: None,
19823                                    background: highlight.color.into(),
19824                                    type_id: Some(highlight.type_id),
19825                                },
19826                            );
19827                        }
19828                    }
19829                    unique_rows
19830                },
19831            )
19832    }
19833
19834    pub fn highlighted_display_row_for_autoscroll(
19835        &self,
19836        snapshot: &DisplaySnapshot,
19837    ) -> Option<DisplayRow> {
19838        self.highlighted_rows
19839            .values()
19840            .flat_map(|highlighted_rows| highlighted_rows.iter())
19841            .filter_map(|highlight| {
19842                if highlight.options.autoscroll {
19843                    Some(highlight.range.start.to_display_point(snapshot).row())
19844                } else {
19845                    None
19846                }
19847            })
19848            .min()
19849    }
19850
19851    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19852        self.highlight_background::<SearchWithinRange>(
19853            ranges,
19854            |colors| colors.colors().editor_document_highlight_read_background,
19855            cx,
19856        )
19857    }
19858
19859    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19860        self.breadcrumb_header = Some(new_header);
19861    }
19862
19863    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19864        self.clear_background_highlights::<SearchWithinRange>(cx);
19865    }
19866
19867    pub fn highlight_background<T: 'static>(
19868        &mut self,
19869        ranges: &[Range<Anchor>],
19870        color_fetcher: fn(&Theme) -> Hsla,
19871        cx: &mut Context<Self>,
19872    ) {
19873        self.background_highlights.insert(
19874            HighlightKey::Type(TypeId::of::<T>()),
19875            (color_fetcher, Arc::from(ranges)),
19876        );
19877        self.scrollbar_marker_state.dirty = true;
19878        cx.notify();
19879    }
19880
19881    pub fn highlight_background_key<T: 'static>(
19882        &mut self,
19883        key: usize,
19884        ranges: &[Range<Anchor>],
19885        color_fetcher: fn(&Theme) -> Hsla,
19886        cx: &mut Context<Self>,
19887    ) {
19888        self.background_highlights.insert(
19889            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19890            (color_fetcher, Arc::from(ranges)),
19891        );
19892        self.scrollbar_marker_state.dirty = true;
19893        cx.notify();
19894    }
19895
19896    pub fn clear_background_highlights<T: 'static>(
19897        &mut self,
19898        cx: &mut Context<Self>,
19899    ) -> Option<BackgroundHighlight> {
19900        let text_highlights = self
19901            .background_highlights
19902            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19903        if !text_highlights.1.is_empty() {
19904            self.scrollbar_marker_state.dirty = true;
19905            cx.notify();
19906        }
19907        Some(text_highlights)
19908    }
19909
19910    pub fn highlight_gutter<T: 'static>(
19911        &mut self,
19912        ranges: impl Into<Vec<Range<Anchor>>>,
19913        color_fetcher: fn(&App) -> Hsla,
19914        cx: &mut Context<Self>,
19915    ) {
19916        self.gutter_highlights
19917            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19918        cx.notify();
19919    }
19920
19921    pub fn clear_gutter_highlights<T: 'static>(
19922        &mut self,
19923        cx: &mut Context<Self>,
19924    ) -> Option<GutterHighlight> {
19925        cx.notify();
19926        self.gutter_highlights.remove(&TypeId::of::<T>())
19927    }
19928
19929    pub fn insert_gutter_highlight<T: 'static>(
19930        &mut self,
19931        range: Range<Anchor>,
19932        color_fetcher: fn(&App) -> Hsla,
19933        cx: &mut Context<Self>,
19934    ) {
19935        let snapshot = self.buffer().read(cx).snapshot(cx);
19936        let mut highlights = self
19937            .gutter_highlights
19938            .remove(&TypeId::of::<T>())
19939            .map(|(_, highlights)| highlights)
19940            .unwrap_or_default();
19941        let ix = highlights.binary_search_by(|highlight| {
19942            Ordering::Equal
19943                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19944                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19945        });
19946        if let Err(ix) = ix {
19947            highlights.insert(ix, range);
19948        }
19949        self.gutter_highlights
19950            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19951    }
19952
19953    pub fn remove_gutter_highlights<T: 'static>(
19954        &mut self,
19955        ranges_to_remove: Vec<Range<Anchor>>,
19956        cx: &mut Context<Self>,
19957    ) {
19958        let snapshot = self.buffer().read(cx).snapshot(cx);
19959        let Some((color_fetcher, mut gutter_highlights)) =
19960            self.gutter_highlights.remove(&TypeId::of::<T>())
19961        else {
19962            return;
19963        };
19964        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19965        gutter_highlights.retain(|highlight| {
19966            while let Some(range_to_remove) = ranges_to_remove.peek() {
19967                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19968                    Ordering::Less | Ordering::Equal => {
19969                        ranges_to_remove.next();
19970                    }
19971                    Ordering::Greater => {
19972                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19973                            Ordering::Less | Ordering::Equal => {
19974                                return false;
19975                            }
19976                            Ordering::Greater => break,
19977                        }
19978                    }
19979                }
19980            }
19981
19982            true
19983        });
19984        self.gutter_highlights
19985            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19986    }
19987
19988    #[cfg(feature = "test-support")]
19989    pub fn all_text_highlights(
19990        &self,
19991        window: &mut Window,
19992        cx: &mut Context<Self>,
19993    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19994        let snapshot = self.snapshot(window, cx);
19995        self.display_map.update(cx, |display_map, _| {
19996            display_map
19997                .all_text_highlights()
19998                .map(|highlight| {
19999                    let (style, ranges) = highlight.as_ref();
20000                    (
20001                        *style,
20002                        ranges
20003                            .iter()
20004                            .map(|range| range.clone().to_display_points(&snapshot))
20005                            .collect(),
20006                    )
20007                })
20008                .collect()
20009        })
20010    }
20011
20012    #[cfg(feature = "test-support")]
20013    pub fn all_text_background_highlights(
20014        &self,
20015        window: &mut Window,
20016        cx: &mut Context<Self>,
20017    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20018        let snapshot = self.snapshot(window, cx);
20019        let buffer = &snapshot.buffer_snapshot;
20020        let start = buffer.anchor_before(0);
20021        let end = buffer.anchor_after(buffer.len());
20022        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20023    }
20024
20025    #[cfg(any(test, feature = "test-support"))]
20026    pub fn sorted_background_highlights_in_range(
20027        &self,
20028        search_range: Range<Anchor>,
20029        display_snapshot: &DisplaySnapshot,
20030        theme: &Theme,
20031    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20032        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20033        res.sort_by(|a, b| {
20034            a.0.start
20035                .cmp(&b.0.start)
20036                .then_with(|| a.0.end.cmp(&b.0.end))
20037                .then_with(|| a.1.cmp(&b.1))
20038        });
20039        res
20040    }
20041
20042    #[cfg(feature = "test-support")]
20043    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20044        let snapshot = self.buffer().read(cx).snapshot(cx);
20045
20046        let highlights = self
20047            .background_highlights
20048            .get(&HighlightKey::Type(TypeId::of::<
20049                items::BufferSearchHighlights,
20050            >()));
20051
20052        if let Some((_color, ranges)) = highlights {
20053            ranges
20054                .iter()
20055                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20056                .collect_vec()
20057        } else {
20058            vec![]
20059        }
20060    }
20061
20062    fn document_highlights_for_position<'a>(
20063        &'a self,
20064        position: Anchor,
20065        buffer: &'a MultiBufferSnapshot,
20066    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20067        let read_highlights = self
20068            .background_highlights
20069            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20070            .map(|h| &h.1);
20071        let write_highlights = self
20072            .background_highlights
20073            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20074            .map(|h| &h.1);
20075        let left_position = position.bias_left(buffer);
20076        let right_position = position.bias_right(buffer);
20077        read_highlights
20078            .into_iter()
20079            .chain(write_highlights)
20080            .flat_map(move |ranges| {
20081                let start_ix = match ranges.binary_search_by(|probe| {
20082                    let cmp = probe.end.cmp(&left_position, buffer);
20083                    if cmp.is_ge() {
20084                        Ordering::Greater
20085                    } else {
20086                        Ordering::Less
20087                    }
20088                }) {
20089                    Ok(i) | Err(i) => i,
20090                };
20091
20092                ranges[start_ix..]
20093                    .iter()
20094                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20095            })
20096    }
20097
20098    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20099        self.background_highlights
20100            .get(&HighlightKey::Type(TypeId::of::<T>()))
20101            .is_some_and(|(_, highlights)| !highlights.is_empty())
20102    }
20103
20104    /// Returns all background highlights for a given range.
20105    ///
20106    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20107    pub fn background_highlights_in_range(
20108        &self,
20109        search_range: Range<Anchor>,
20110        display_snapshot: &DisplaySnapshot,
20111        theme: &Theme,
20112    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20113        let mut results = Vec::new();
20114        for (color_fetcher, ranges) in self.background_highlights.values() {
20115            let color = color_fetcher(theme);
20116            let start_ix = match ranges.binary_search_by(|probe| {
20117                let cmp = probe
20118                    .end
20119                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20120                if cmp.is_gt() {
20121                    Ordering::Greater
20122                } else {
20123                    Ordering::Less
20124                }
20125            }) {
20126                Ok(i) | Err(i) => i,
20127            };
20128            for range in &ranges[start_ix..] {
20129                if range
20130                    .start
20131                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20132                    .is_ge()
20133                {
20134                    break;
20135                }
20136
20137                let start = range.start.to_display_point(display_snapshot);
20138                let end = range.end.to_display_point(display_snapshot);
20139                results.push((start..end, color))
20140            }
20141        }
20142        results
20143    }
20144
20145    pub fn gutter_highlights_in_range(
20146        &self,
20147        search_range: Range<Anchor>,
20148        display_snapshot: &DisplaySnapshot,
20149        cx: &App,
20150    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20151        let mut results = Vec::new();
20152        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20153            let color = color_fetcher(cx);
20154            let start_ix = match ranges.binary_search_by(|probe| {
20155                let cmp = probe
20156                    .end
20157                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20158                if cmp.is_gt() {
20159                    Ordering::Greater
20160                } else {
20161                    Ordering::Less
20162                }
20163            }) {
20164                Ok(i) | Err(i) => i,
20165            };
20166            for range in &ranges[start_ix..] {
20167                if range
20168                    .start
20169                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20170                    .is_ge()
20171                {
20172                    break;
20173                }
20174
20175                let start = range.start.to_display_point(display_snapshot);
20176                let end = range.end.to_display_point(display_snapshot);
20177                results.push((start..end, color))
20178            }
20179        }
20180        results
20181    }
20182
20183    /// Get the text ranges corresponding to the redaction query
20184    pub fn redacted_ranges(
20185        &self,
20186        search_range: Range<Anchor>,
20187        display_snapshot: &DisplaySnapshot,
20188        cx: &App,
20189    ) -> Vec<Range<DisplayPoint>> {
20190        display_snapshot
20191            .buffer_snapshot
20192            .redacted_ranges(search_range, |file| {
20193                if let Some(file) = file {
20194                    file.is_private()
20195                        && EditorSettings::get(
20196                            Some(SettingsLocation {
20197                                worktree_id: file.worktree_id(cx),
20198                                path: file.path().as_ref(),
20199                            }),
20200                            cx,
20201                        )
20202                        .redact_private_values
20203                } else {
20204                    false
20205                }
20206            })
20207            .map(|range| {
20208                range.start.to_display_point(display_snapshot)
20209                    ..range.end.to_display_point(display_snapshot)
20210            })
20211            .collect()
20212    }
20213
20214    pub fn highlight_text_key<T: 'static>(
20215        &mut self,
20216        key: usize,
20217        ranges: Vec<Range<Anchor>>,
20218        style: HighlightStyle,
20219        cx: &mut Context<Self>,
20220    ) {
20221        self.display_map.update(cx, |map, _| {
20222            map.highlight_text(
20223                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20224                ranges,
20225                style,
20226            );
20227        });
20228        cx.notify();
20229    }
20230
20231    pub fn highlight_text<T: 'static>(
20232        &mut self,
20233        ranges: Vec<Range<Anchor>>,
20234        style: HighlightStyle,
20235        cx: &mut Context<Self>,
20236    ) {
20237        self.display_map.update(cx, |map, _| {
20238            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20239        });
20240        cx.notify();
20241    }
20242
20243    pub(crate) fn highlight_inlays<T: 'static>(
20244        &mut self,
20245        highlights: Vec<InlayHighlight>,
20246        style: HighlightStyle,
20247        cx: &mut Context<Self>,
20248    ) {
20249        self.display_map.update(cx, |map, _| {
20250            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20251        });
20252        cx.notify();
20253    }
20254
20255    pub fn text_highlights<'a, T: 'static>(
20256        &'a self,
20257        cx: &'a App,
20258    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20259        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20260    }
20261
20262    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20263        let cleared = self
20264            .display_map
20265            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20266        if cleared {
20267            cx.notify();
20268        }
20269    }
20270
20271    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20272        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20273            && self.focus_handle.is_focused(window)
20274    }
20275
20276    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20277        self.show_cursor_when_unfocused = is_enabled;
20278        cx.notify();
20279    }
20280
20281    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20282        cx.notify();
20283    }
20284
20285    fn on_debug_session_event(
20286        &mut self,
20287        _session: Entity<Session>,
20288        event: &SessionEvent,
20289        cx: &mut Context<Self>,
20290    ) {
20291        if let SessionEvent::InvalidateInlineValue = event {
20292            self.refresh_inline_values(cx);
20293        }
20294    }
20295
20296    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20297        let Some(project) = self.project.clone() else {
20298            return;
20299        };
20300
20301        if !self.inline_value_cache.enabled {
20302            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20303            self.splice_inlays(&inlays, Vec::new(), cx);
20304            return;
20305        }
20306
20307        let current_execution_position = self
20308            .highlighted_rows
20309            .get(&TypeId::of::<ActiveDebugLine>())
20310            .and_then(|lines| lines.last().map(|line| line.range.end));
20311
20312        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20313            let inline_values = editor
20314                .update(cx, |editor, cx| {
20315                    let Some(current_execution_position) = current_execution_position else {
20316                        return Some(Task::ready(Ok(Vec::new())));
20317                    };
20318
20319                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20320                        let snapshot = buffer.snapshot(cx);
20321
20322                        let excerpt = snapshot.excerpt_containing(
20323                            current_execution_position..current_execution_position,
20324                        )?;
20325
20326                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20327                    })?;
20328
20329                    let range =
20330                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20331
20332                    project.inline_values(buffer, range, cx)
20333                })
20334                .ok()
20335                .flatten()?
20336                .await
20337                .context("refreshing debugger inlays")
20338                .log_err()?;
20339
20340            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20341
20342            for (buffer_id, inline_value) in inline_values
20343                .into_iter()
20344                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20345            {
20346                buffer_inline_values
20347                    .entry(buffer_id)
20348                    .or_default()
20349                    .push(inline_value);
20350            }
20351
20352            editor
20353                .update(cx, |editor, cx| {
20354                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20355                    let mut new_inlays = Vec::default();
20356
20357                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20358                        let buffer_id = buffer_snapshot.remote_id();
20359                        buffer_inline_values
20360                            .get(&buffer_id)
20361                            .into_iter()
20362                            .flatten()
20363                            .for_each(|hint| {
20364                                let inlay = Inlay::debugger(
20365                                    post_inc(&mut editor.next_inlay_id),
20366                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20367                                    hint.text(),
20368                                );
20369                                if !inlay.text.chars().contains(&'\n') {
20370                                    new_inlays.push(inlay);
20371                                }
20372                            });
20373                    }
20374
20375                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20376                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20377
20378                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20379                })
20380                .ok()?;
20381            Some(())
20382        });
20383    }
20384
20385    fn on_buffer_event(
20386        &mut self,
20387        multibuffer: &Entity<MultiBuffer>,
20388        event: &multi_buffer::Event,
20389        window: &mut Window,
20390        cx: &mut Context<Self>,
20391    ) {
20392        match event {
20393            multi_buffer::Event::Edited {
20394                singleton_buffer_edited,
20395                edited_buffer,
20396            } => {
20397                self.scrollbar_marker_state.dirty = true;
20398                self.active_indent_guides_state.dirty = true;
20399                self.refresh_active_diagnostics(cx);
20400                self.refresh_code_actions(window, cx);
20401                self.refresh_selected_text_highlights(true, window, cx);
20402                self.refresh_single_line_folds(window, cx);
20403                refresh_matching_bracket_highlights(self, window, cx);
20404                if self.has_active_edit_prediction() {
20405                    self.update_visible_edit_prediction(window, cx);
20406                }
20407                if let Some(project) = self.project.as_ref()
20408                    && let Some(edited_buffer) = edited_buffer
20409                {
20410                    project.update(cx, |project, cx| {
20411                        self.registered_buffers
20412                            .entry(edited_buffer.read(cx).remote_id())
20413                            .or_insert_with(|| {
20414                                project.register_buffer_with_language_servers(edited_buffer, cx)
20415                            });
20416                    });
20417                }
20418                cx.emit(EditorEvent::BufferEdited);
20419                cx.emit(SearchEvent::MatchesInvalidated);
20420
20421                if let Some(buffer) = edited_buffer {
20422                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20423                }
20424
20425                if *singleton_buffer_edited {
20426                    if let Some(buffer) = edited_buffer
20427                        && buffer.read(cx).file().is_none()
20428                    {
20429                        cx.emit(EditorEvent::TitleChanged);
20430                    }
20431                    if let Some(project) = &self.project {
20432                        #[allow(clippy::mutable_key_type)]
20433                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20434                            multibuffer
20435                                .all_buffers()
20436                                .into_iter()
20437                                .filter_map(|buffer| {
20438                                    buffer.update(cx, |buffer, cx| {
20439                                        let language = buffer.language()?;
20440                                        let should_discard = project.update(cx, |project, cx| {
20441                                            project.is_local()
20442                                                && !project.has_language_servers_for(buffer, cx)
20443                                        });
20444                                        should_discard.not().then_some(language.clone())
20445                                    })
20446                                })
20447                                .collect::<HashSet<_>>()
20448                        });
20449                        if !languages_affected.is_empty() {
20450                            self.refresh_inlay_hints(
20451                                InlayHintRefreshReason::BufferEdited(languages_affected),
20452                                cx,
20453                            );
20454                        }
20455                    }
20456                }
20457
20458                let Some(project) = &self.project else { return };
20459                let (telemetry, is_via_ssh) = {
20460                    let project = project.read(cx);
20461                    let telemetry = project.client().telemetry().clone();
20462                    let is_via_ssh = project.is_via_remote_server();
20463                    (telemetry, is_via_ssh)
20464                };
20465                refresh_linked_ranges(self, window, cx);
20466                telemetry.log_edit_event("editor", is_via_ssh);
20467            }
20468            multi_buffer::Event::ExcerptsAdded {
20469                buffer,
20470                predecessor,
20471                excerpts,
20472            } => {
20473                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20474                let buffer_id = buffer.read(cx).remote_id();
20475                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20476                    && let Some(project) = &self.project
20477                {
20478                    update_uncommitted_diff_for_buffer(
20479                        cx.entity(),
20480                        project,
20481                        [buffer.clone()],
20482                        self.buffer.clone(),
20483                        cx,
20484                    )
20485                    .detach();
20486                }
20487                self.update_lsp_data(false, Some(buffer_id), window, cx);
20488                cx.emit(EditorEvent::ExcerptsAdded {
20489                    buffer: buffer.clone(),
20490                    predecessor: *predecessor,
20491                    excerpts: excerpts.clone(),
20492                });
20493                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20494            }
20495            multi_buffer::Event::ExcerptsRemoved {
20496                ids,
20497                removed_buffer_ids,
20498            } => {
20499                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20500                let buffer = self.buffer.read(cx);
20501                self.registered_buffers
20502                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20503                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20504                cx.emit(EditorEvent::ExcerptsRemoved {
20505                    ids: ids.clone(),
20506                    removed_buffer_ids: removed_buffer_ids.clone(),
20507                });
20508            }
20509            multi_buffer::Event::ExcerptsEdited {
20510                excerpt_ids,
20511                buffer_ids,
20512            } => {
20513                self.display_map.update(cx, |map, cx| {
20514                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20515                });
20516                cx.emit(EditorEvent::ExcerptsEdited {
20517                    ids: excerpt_ids.clone(),
20518                });
20519            }
20520            multi_buffer::Event::ExcerptsExpanded { ids } => {
20521                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20522                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20523            }
20524            multi_buffer::Event::Reparsed(buffer_id) => {
20525                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20526                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20527
20528                cx.emit(EditorEvent::Reparsed(*buffer_id));
20529            }
20530            multi_buffer::Event::DiffHunksToggled => {
20531                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20532            }
20533            multi_buffer::Event::LanguageChanged(buffer_id) => {
20534                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20535                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20536                cx.emit(EditorEvent::Reparsed(*buffer_id));
20537                cx.notify();
20538            }
20539            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20540            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20541            multi_buffer::Event::FileHandleChanged
20542            | multi_buffer::Event::Reloaded
20543            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20544            multi_buffer::Event::DiagnosticsUpdated => {
20545                self.update_diagnostics_state(window, cx);
20546            }
20547            _ => {}
20548        };
20549    }
20550
20551    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20552        if !self.diagnostics_enabled() {
20553            return;
20554        }
20555        self.refresh_active_diagnostics(cx);
20556        self.refresh_inline_diagnostics(true, window, cx);
20557        self.scrollbar_marker_state.dirty = true;
20558        cx.notify();
20559    }
20560
20561    pub fn start_temporary_diff_override(&mut self) {
20562        self.load_diff_task.take();
20563        self.temporary_diff_override = true;
20564    }
20565
20566    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20567        self.temporary_diff_override = false;
20568        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20569        self.buffer.update(cx, |buffer, cx| {
20570            buffer.set_all_diff_hunks_collapsed(cx);
20571        });
20572
20573        if let Some(project) = self.project.clone() {
20574            self.load_diff_task = Some(
20575                update_uncommitted_diff_for_buffer(
20576                    cx.entity(),
20577                    &project,
20578                    self.buffer.read(cx).all_buffers(),
20579                    self.buffer.clone(),
20580                    cx,
20581                )
20582                .shared(),
20583            );
20584        }
20585    }
20586
20587    fn on_display_map_changed(
20588        &mut self,
20589        _: Entity<DisplayMap>,
20590        _: &mut Window,
20591        cx: &mut Context<Self>,
20592    ) {
20593        cx.notify();
20594    }
20595
20596    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20597        if self.diagnostics_enabled() {
20598            let new_severity = EditorSettings::get_global(cx)
20599                .diagnostics_max_severity
20600                .unwrap_or(DiagnosticSeverity::Hint);
20601            self.set_max_diagnostics_severity(new_severity, cx);
20602        }
20603        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20604        self.update_edit_prediction_settings(cx);
20605        self.refresh_edit_prediction(true, false, window, cx);
20606        self.refresh_inline_values(cx);
20607        self.refresh_inlay_hints(
20608            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20609                self.selections.newest_anchor().head(),
20610                &self.buffer.read(cx).snapshot(cx),
20611                cx,
20612            )),
20613            cx,
20614        );
20615
20616        let old_cursor_shape = self.cursor_shape;
20617        let old_show_breadcrumbs = self.show_breadcrumbs;
20618
20619        {
20620            let editor_settings = EditorSettings::get_global(cx);
20621            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20622            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20623            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20624            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20625        }
20626
20627        if old_cursor_shape != self.cursor_shape {
20628            cx.emit(EditorEvent::CursorShapeChanged);
20629        }
20630
20631        if old_show_breadcrumbs != self.show_breadcrumbs {
20632            cx.emit(EditorEvent::BreadcrumbsChanged);
20633        }
20634
20635        let project_settings = ProjectSettings::get_global(cx);
20636        self.serialize_dirty_buffers =
20637            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20638
20639        if self.mode.is_full() {
20640            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20641            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20642            if self.show_inline_diagnostics != show_inline_diagnostics {
20643                self.show_inline_diagnostics = show_inline_diagnostics;
20644                self.refresh_inline_diagnostics(false, window, cx);
20645            }
20646
20647            if self.git_blame_inline_enabled != inline_blame_enabled {
20648                self.toggle_git_blame_inline_internal(false, window, cx);
20649            }
20650
20651            let minimap_settings = EditorSettings::get_global(cx).minimap;
20652            if self.minimap_visibility != MinimapVisibility::Disabled {
20653                if self.minimap_visibility.settings_visibility()
20654                    != minimap_settings.minimap_enabled()
20655                {
20656                    self.set_minimap_visibility(
20657                        MinimapVisibility::for_mode(self.mode(), cx),
20658                        window,
20659                        cx,
20660                    );
20661                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20662                    minimap_entity.update(cx, |minimap_editor, cx| {
20663                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20664                    })
20665                }
20666            }
20667        }
20668
20669        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20670            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20671        }) {
20672            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20673                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20674            }
20675            self.refresh_colors(false, None, window, cx);
20676        }
20677
20678        cx.notify();
20679    }
20680
20681    pub fn set_searchable(&mut self, searchable: bool) {
20682        self.searchable = searchable;
20683    }
20684
20685    pub fn searchable(&self) -> bool {
20686        self.searchable
20687    }
20688
20689    fn open_proposed_changes_editor(
20690        &mut self,
20691        _: &OpenProposedChangesEditor,
20692        window: &mut Window,
20693        cx: &mut Context<Self>,
20694    ) {
20695        let Some(workspace) = self.workspace() else {
20696            cx.propagate();
20697            return;
20698        };
20699
20700        let selections = self.selections.all::<usize>(cx);
20701        let multi_buffer = self.buffer.read(cx);
20702        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20703        let mut new_selections_by_buffer = HashMap::default();
20704        for selection in selections {
20705            for (buffer, range, _) in
20706                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20707            {
20708                let mut range = range.to_point(buffer);
20709                range.start.column = 0;
20710                range.end.column = buffer.line_len(range.end.row);
20711                new_selections_by_buffer
20712                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20713                    .or_insert(Vec::new())
20714                    .push(range)
20715            }
20716        }
20717
20718        let proposed_changes_buffers = new_selections_by_buffer
20719            .into_iter()
20720            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20721            .collect::<Vec<_>>();
20722        let proposed_changes_editor = cx.new(|cx| {
20723            ProposedChangesEditor::new(
20724                "Proposed changes",
20725                proposed_changes_buffers,
20726                self.project.clone(),
20727                window,
20728                cx,
20729            )
20730        });
20731
20732        window.defer(cx, move |window, cx| {
20733            workspace.update(cx, |workspace, cx| {
20734                workspace.active_pane().update(cx, |pane, cx| {
20735                    pane.add_item(
20736                        Box::new(proposed_changes_editor),
20737                        true,
20738                        true,
20739                        None,
20740                        window,
20741                        cx,
20742                    );
20743                });
20744            });
20745        });
20746    }
20747
20748    pub fn open_excerpts_in_split(
20749        &mut self,
20750        _: &OpenExcerptsSplit,
20751        window: &mut Window,
20752        cx: &mut Context<Self>,
20753    ) {
20754        self.open_excerpts_common(None, true, window, cx)
20755    }
20756
20757    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20758        self.open_excerpts_common(None, false, window, cx)
20759    }
20760
20761    fn open_excerpts_common(
20762        &mut self,
20763        jump_data: Option<JumpData>,
20764        split: bool,
20765        window: &mut Window,
20766        cx: &mut Context<Self>,
20767    ) {
20768        let Some(workspace) = self.workspace() else {
20769            cx.propagate();
20770            return;
20771        };
20772
20773        if self.buffer.read(cx).is_singleton() {
20774            cx.propagate();
20775            return;
20776        }
20777
20778        let mut new_selections_by_buffer = HashMap::default();
20779        match &jump_data {
20780            Some(JumpData::MultiBufferPoint {
20781                excerpt_id,
20782                position,
20783                anchor,
20784                line_offset_from_top,
20785            }) => {
20786                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20787                if let Some(buffer) = multi_buffer_snapshot
20788                    .buffer_id_for_excerpt(*excerpt_id)
20789                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20790                {
20791                    let buffer_snapshot = buffer.read(cx).snapshot();
20792                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20793                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20794                    } else {
20795                        buffer_snapshot.clip_point(*position, Bias::Left)
20796                    };
20797                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20798                    new_selections_by_buffer.insert(
20799                        buffer,
20800                        (
20801                            vec![jump_to_offset..jump_to_offset],
20802                            Some(*line_offset_from_top),
20803                        ),
20804                    );
20805                }
20806            }
20807            Some(JumpData::MultiBufferRow {
20808                row,
20809                line_offset_from_top,
20810            }) => {
20811                let point = MultiBufferPoint::new(row.0, 0);
20812                if let Some((buffer, buffer_point, _)) =
20813                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20814                {
20815                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20816                    new_selections_by_buffer
20817                        .entry(buffer)
20818                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20819                        .0
20820                        .push(buffer_offset..buffer_offset)
20821                }
20822            }
20823            None => {
20824                let selections = self.selections.all::<usize>(cx);
20825                let multi_buffer = self.buffer.read(cx);
20826                for selection in selections {
20827                    for (snapshot, range, _, anchor) in multi_buffer
20828                        .snapshot(cx)
20829                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20830                    {
20831                        if let Some(anchor) = anchor {
20832                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20833                            else {
20834                                continue;
20835                            };
20836                            let offset = text::ToOffset::to_offset(
20837                                &anchor.text_anchor,
20838                                &buffer_handle.read(cx).snapshot(),
20839                            );
20840                            let range = offset..offset;
20841                            new_selections_by_buffer
20842                                .entry(buffer_handle)
20843                                .or_insert((Vec::new(), None))
20844                                .0
20845                                .push(range)
20846                        } else {
20847                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20848                            else {
20849                                continue;
20850                            };
20851                            new_selections_by_buffer
20852                                .entry(buffer_handle)
20853                                .or_insert((Vec::new(), None))
20854                                .0
20855                                .push(range)
20856                        }
20857                    }
20858                }
20859            }
20860        }
20861
20862        new_selections_by_buffer
20863            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20864
20865        if new_selections_by_buffer.is_empty() {
20866            return;
20867        }
20868
20869        // We defer the pane interaction because we ourselves are a workspace item
20870        // and activating a new item causes the pane to call a method on us reentrantly,
20871        // which panics if we're on the stack.
20872        window.defer(cx, move |window, cx| {
20873            workspace.update(cx, |workspace, cx| {
20874                let pane = if split {
20875                    workspace.adjacent_pane(window, cx)
20876                } else {
20877                    workspace.active_pane().clone()
20878                };
20879
20880                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20881                    let editor = buffer
20882                        .read(cx)
20883                        .file()
20884                        .is_none()
20885                        .then(|| {
20886                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20887                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20888                            // Instead, we try to activate the existing editor in the pane first.
20889                            let (editor, pane_item_index) =
20890                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20891                                    let editor = item.downcast::<Editor>()?;
20892                                    let singleton_buffer =
20893                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20894                                    if singleton_buffer == buffer {
20895                                        Some((editor, i))
20896                                    } else {
20897                                        None
20898                                    }
20899                                })?;
20900                            pane.update(cx, |pane, cx| {
20901                                pane.activate_item(pane_item_index, true, true, window, cx)
20902                            });
20903                            Some(editor)
20904                        })
20905                        .flatten()
20906                        .unwrap_or_else(|| {
20907                            workspace.open_project_item::<Self>(
20908                                pane.clone(),
20909                                buffer,
20910                                true,
20911                                true,
20912                                window,
20913                                cx,
20914                            )
20915                        });
20916
20917                    editor.update(cx, |editor, cx| {
20918                        let autoscroll = match scroll_offset {
20919                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20920                            None => Autoscroll::newest(),
20921                        };
20922                        let nav_history = editor.nav_history.take();
20923                        editor.change_selections(
20924                            SelectionEffects::scroll(autoscroll),
20925                            window,
20926                            cx,
20927                            |s| {
20928                                s.select_ranges(ranges);
20929                            },
20930                        );
20931                        editor.nav_history = nav_history;
20932                    });
20933                }
20934            })
20935        });
20936    }
20937
20938    // For now, don't allow opening excerpts in buffers that aren't backed by
20939    // regular project files.
20940    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20941        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20942    }
20943
20944    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20945        let snapshot = self.buffer.read(cx).read(cx);
20946        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20947        Some(
20948            ranges
20949                .iter()
20950                .map(move |range| {
20951                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20952                })
20953                .collect(),
20954        )
20955    }
20956
20957    fn selection_replacement_ranges(
20958        &self,
20959        range: Range<OffsetUtf16>,
20960        cx: &mut App,
20961    ) -> Vec<Range<OffsetUtf16>> {
20962        let selections = self.selections.all::<OffsetUtf16>(cx);
20963        let newest_selection = selections
20964            .iter()
20965            .max_by_key(|selection| selection.id)
20966            .unwrap();
20967        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20968        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20969        let snapshot = self.buffer.read(cx).read(cx);
20970        selections
20971            .into_iter()
20972            .map(|mut selection| {
20973                selection.start.0 =
20974                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20975                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20976                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20977                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20978            })
20979            .collect()
20980    }
20981
20982    fn report_editor_event(
20983        &self,
20984        reported_event: ReportEditorEvent,
20985        file_extension: Option<String>,
20986        cx: &App,
20987    ) {
20988        if cfg!(any(test, feature = "test-support")) {
20989            return;
20990        }
20991
20992        let Some(project) = &self.project else { return };
20993
20994        // If None, we are in a file without an extension
20995        let file = self
20996            .buffer
20997            .read(cx)
20998            .as_singleton()
20999            .and_then(|b| b.read(cx).file());
21000        let file_extension = file_extension.or(file
21001            .as_ref()
21002            .and_then(|file| Path::new(file.file_name(cx)).extension())
21003            .and_then(|e| e.to_str())
21004            .map(|a| a.to_string()));
21005
21006        let vim_mode = vim_enabled(cx);
21007
21008        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21009        let copilot_enabled = edit_predictions_provider
21010            == language::language_settings::EditPredictionProvider::Copilot;
21011        let copilot_enabled_for_language = self
21012            .buffer
21013            .read(cx)
21014            .language_settings(cx)
21015            .show_edit_predictions;
21016
21017        let project = project.read(cx);
21018        let event_type = reported_event.event_type();
21019
21020        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21021            telemetry::event!(
21022                event_type,
21023                type = if auto_saved {"autosave"} else {"manual"},
21024                file_extension,
21025                vim_mode,
21026                copilot_enabled,
21027                copilot_enabled_for_language,
21028                edit_predictions_provider,
21029                is_via_ssh = project.is_via_remote_server(),
21030            );
21031        } else {
21032            telemetry::event!(
21033                event_type,
21034                file_extension,
21035                vim_mode,
21036                copilot_enabled,
21037                copilot_enabled_for_language,
21038                edit_predictions_provider,
21039                is_via_ssh = project.is_via_remote_server(),
21040            );
21041        };
21042    }
21043
21044    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21045    /// with each line being an array of {text, highlight} objects.
21046    fn copy_highlight_json(
21047        &mut self,
21048        _: &CopyHighlightJson,
21049        window: &mut Window,
21050        cx: &mut Context<Self>,
21051    ) {
21052        #[derive(Serialize)]
21053        struct Chunk<'a> {
21054            text: String,
21055            highlight: Option<&'a str>,
21056        }
21057
21058        let snapshot = self.buffer.read(cx).snapshot(cx);
21059        let range = self
21060            .selected_text_range(false, window, cx)
21061            .and_then(|selection| {
21062                if selection.range.is_empty() {
21063                    None
21064                } else {
21065                    Some(selection.range)
21066                }
21067            })
21068            .unwrap_or_else(|| 0..snapshot.len());
21069
21070        let chunks = snapshot.chunks(range, true);
21071        let mut lines = Vec::new();
21072        let mut line: VecDeque<Chunk> = VecDeque::new();
21073
21074        let Some(style) = self.style.as_ref() else {
21075            return;
21076        };
21077
21078        for chunk in chunks {
21079            let highlight = chunk
21080                .syntax_highlight_id
21081                .and_then(|id| id.name(&style.syntax));
21082            let mut chunk_lines = chunk.text.split('\n').peekable();
21083            while let Some(text) = chunk_lines.next() {
21084                let mut merged_with_last_token = false;
21085                if let Some(last_token) = line.back_mut()
21086                    && last_token.highlight == highlight
21087                {
21088                    last_token.text.push_str(text);
21089                    merged_with_last_token = true;
21090                }
21091
21092                if !merged_with_last_token {
21093                    line.push_back(Chunk {
21094                        text: text.into(),
21095                        highlight,
21096                    });
21097                }
21098
21099                if chunk_lines.peek().is_some() {
21100                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21101                        line.pop_front();
21102                    }
21103                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21104                        line.pop_back();
21105                    }
21106
21107                    lines.push(mem::take(&mut line));
21108                }
21109            }
21110        }
21111
21112        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21113            return;
21114        };
21115        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21116    }
21117
21118    pub fn open_context_menu(
21119        &mut self,
21120        _: &OpenContextMenu,
21121        window: &mut Window,
21122        cx: &mut Context<Self>,
21123    ) {
21124        self.request_autoscroll(Autoscroll::newest(), cx);
21125        let position = self.selections.newest_display(cx).start;
21126        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21127    }
21128
21129    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21130        &self.inlay_hint_cache
21131    }
21132
21133    pub fn replay_insert_event(
21134        &mut self,
21135        text: &str,
21136        relative_utf16_range: Option<Range<isize>>,
21137        window: &mut Window,
21138        cx: &mut Context<Self>,
21139    ) {
21140        if !self.input_enabled {
21141            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21142            return;
21143        }
21144        if let Some(relative_utf16_range) = relative_utf16_range {
21145            let selections = self.selections.all::<OffsetUtf16>(cx);
21146            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21147                let new_ranges = selections.into_iter().map(|range| {
21148                    let start = OffsetUtf16(
21149                        range
21150                            .head()
21151                            .0
21152                            .saturating_add_signed(relative_utf16_range.start),
21153                    );
21154                    let end = OffsetUtf16(
21155                        range
21156                            .head()
21157                            .0
21158                            .saturating_add_signed(relative_utf16_range.end),
21159                    );
21160                    start..end
21161                });
21162                s.select_ranges(new_ranges);
21163            });
21164        }
21165
21166        self.handle_input(text, window, cx);
21167    }
21168
21169    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21170        let Some(provider) = self.semantics_provider.as_ref() else {
21171            return false;
21172        };
21173
21174        let mut supports = false;
21175        self.buffer().update(cx, |this, cx| {
21176            this.for_each_buffer(|buffer| {
21177                supports |= provider.supports_inlay_hints(buffer, cx);
21178            });
21179        });
21180
21181        supports
21182    }
21183
21184    pub fn is_focused(&self, window: &Window) -> bool {
21185        self.focus_handle.is_focused(window)
21186    }
21187
21188    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21189        cx.emit(EditorEvent::Focused);
21190
21191        if let Some(descendant) = self
21192            .last_focused_descendant
21193            .take()
21194            .and_then(|descendant| descendant.upgrade())
21195        {
21196            window.focus(&descendant);
21197        } else {
21198            if let Some(blame) = self.blame.as_ref() {
21199                blame.update(cx, GitBlame::focus)
21200            }
21201
21202            self.blink_manager.update(cx, BlinkManager::enable);
21203            self.show_cursor_names(window, cx);
21204            self.buffer.update(cx, |buffer, cx| {
21205                buffer.finalize_last_transaction(cx);
21206                if self.leader_id.is_none() {
21207                    buffer.set_active_selections(
21208                        &self.selections.disjoint_anchors(),
21209                        self.selections.line_mode,
21210                        self.cursor_shape,
21211                        cx,
21212                    );
21213                }
21214            });
21215        }
21216    }
21217
21218    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21219        cx.emit(EditorEvent::FocusedIn)
21220    }
21221
21222    fn handle_focus_out(
21223        &mut self,
21224        event: FocusOutEvent,
21225        _window: &mut Window,
21226        cx: &mut Context<Self>,
21227    ) {
21228        if event.blurred != self.focus_handle {
21229            self.last_focused_descendant = Some(event.blurred);
21230        }
21231        self.selection_drag_state = SelectionDragState::None;
21232        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21233    }
21234
21235    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21236        self.blink_manager.update(cx, BlinkManager::disable);
21237        self.buffer
21238            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21239
21240        if let Some(blame) = self.blame.as_ref() {
21241            blame.update(cx, GitBlame::blur)
21242        }
21243        if !self.hover_state.focused(window, cx) {
21244            hide_hover(self, cx);
21245        }
21246        if !self
21247            .context_menu
21248            .borrow()
21249            .as_ref()
21250            .is_some_and(|context_menu| context_menu.focused(window, cx))
21251        {
21252            self.hide_context_menu(window, cx);
21253        }
21254        self.discard_edit_prediction(false, cx);
21255        cx.emit(EditorEvent::Blurred);
21256        cx.notify();
21257    }
21258
21259    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21260        let mut pending: String = window
21261            .pending_input_keystrokes()
21262            .into_iter()
21263            .flatten()
21264            .filter_map(|keystroke| {
21265                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21266                    keystroke.key_char.clone()
21267                } else {
21268                    None
21269                }
21270            })
21271            .collect();
21272
21273        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21274            pending = "".to_string();
21275        }
21276
21277        let existing_pending = self
21278            .text_highlights::<PendingInput>(cx)
21279            .map(|(_, ranges)| ranges.to_vec());
21280        if existing_pending.is_none() && pending.is_empty() {
21281            return;
21282        }
21283        let transaction =
21284            self.transact(window, cx, |this, window, cx| {
21285                let selections = this.selections.all::<usize>(cx);
21286                let edits = selections
21287                    .iter()
21288                    .map(|selection| (selection.end..selection.end, pending.clone()));
21289                this.edit(edits, cx);
21290                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21291                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21292                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21293                    }));
21294                });
21295                if let Some(existing_ranges) = existing_pending {
21296                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21297                    this.edit(edits, cx);
21298                }
21299            });
21300
21301        let snapshot = self.snapshot(window, cx);
21302        let ranges = self
21303            .selections
21304            .all::<usize>(cx)
21305            .into_iter()
21306            .map(|selection| {
21307                snapshot.buffer_snapshot.anchor_after(selection.end)
21308                    ..snapshot
21309                        .buffer_snapshot
21310                        .anchor_before(selection.end + pending.len())
21311            })
21312            .collect();
21313
21314        if pending.is_empty() {
21315            self.clear_highlights::<PendingInput>(cx);
21316        } else {
21317            self.highlight_text::<PendingInput>(
21318                ranges,
21319                HighlightStyle {
21320                    underline: Some(UnderlineStyle {
21321                        thickness: px(1.),
21322                        color: None,
21323                        wavy: false,
21324                    }),
21325                    ..Default::default()
21326                },
21327                cx,
21328            );
21329        }
21330
21331        self.ime_transaction = self.ime_transaction.or(transaction);
21332        if let Some(transaction) = self.ime_transaction {
21333            self.buffer.update(cx, |buffer, cx| {
21334                buffer.group_until_transaction(transaction, cx);
21335            });
21336        }
21337
21338        if self.text_highlights::<PendingInput>(cx).is_none() {
21339            self.ime_transaction.take();
21340        }
21341    }
21342
21343    pub fn register_action_renderer(
21344        &mut self,
21345        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21346    ) -> Subscription {
21347        let id = self.next_editor_action_id.post_inc();
21348        self.editor_actions
21349            .borrow_mut()
21350            .insert(id, Box::new(listener));
21351
21352        let editor_actions = self.editor_actions.clone();
21353        Subscription::new(move || {
21354            editor_actions.borrow_mut().remove(&id);
21355        })
21356    }
21357
21358    pub fn register_action<A: Action>(
21359        &mut self,
21360        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21361    ) -> Subscription {
21362        let id = self.next_editor_action_id.post_inc();
21363        let listener = Arc::new(listener);
21364        self.editor_actions.borrow_mut().insert(
21365            id,
21366            Box::new(move |_, window, _| {
21367                let listener = listener.clone();
21368                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21369                    let action = action.downcast_ref().unwrap();
21370                    if phase == DispatchPhase::Bubble {
21371                        listener(action, window, cx)
21372                    }
21373                })
21374            }),
21375        );
21376
21377        let editor_actions = self.editor_actions.clone();
21378        Subscription::new(move || {
21379            editor_actions.borrow_mut().remove(&id);
21380        })
21381    }
21382
21383    pub fn file_header_size(&self) -> u32 {
21384        FILE_HEADER_HEIGHT
21385    }
21386
21387    pub fn restore(
21388        &mut self,
21389        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21390        window: &mut Window,
21391        cx: &mut Context<Self>,
21392    ) {
21393        let workspace = self.workspace();
21394        let project = self.project();
21395        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21396            let mut tasks = Vec::new();
21397            for (buffer_id, changes) in revert_changes {
21398                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21399                    buffer.update(cx, |buffer, cx| {
21400                        buffer.edit(
21401                            changes
21402                                .into_iter()
21403                                .map(|(range, text)| (range, text.to_string())),
21404                            None,
21405                            cx,
21406                        );
21407                    });
21408
21409                    if let Some(project) =
21410                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21411                    {
21412                        project.update(cx, |project, cx| {
21413                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21414                        })
21415                    }
21416                }
21417            }
21418            tasks
21419        });
21420        cx.spawn_in(window, async move |_, cx| {
21421            for (buffer, task) in save_tasks {
21422                let result = task.await;
21423                if result.is_err() {
21424                    let Some(path) = buffer
21425                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21426                        .ok()
21427                    else {
21428                        continue;
21429                    };
21430                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21431                        let Some(task) = cx
21432                            .update_window_entity(workspace, |workspace, window, cx| {
21433                                workspace
21434                                    .open_path_preview(path, None, false, false, false, window, cx)
21435                            })
21436                            .ok()
21437                        else {
21438                            continue;
21439                        };
21440                        task.await.log_err();
21441                    }
21442                }
21443            }
21444        })
21445        .detach();
21446        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21447            selections.refresh()
21448        });
21449    }
21450
21451    pub fn to_pixel_point(
21452        &self,
21453        source: multi_buffer::Anchor,
21454        editor_snapshot: &EditorSnapshot,
21455        window: &mut Window,
21456    ) -> Option<gpui::Point<Pixels>> {
21457        let source_point = source.to_display_point(editor_snapshot);
21458        self.display_to_pixel_point(source_point, editor_snapshot, window)
21459    }
21460
21461    pub fn display_to_pixel_point(
21462        &self,
21463        source: DisplayPoint,
21464        editor_snapshot: &EditorSnapshot,
21465        window: &mut Window,
21466    ) -> Option<gpui::Point<Pixels>> {
21467        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21468        let text_layout_details = self.text_layout_details(window);
21469        let scroll_top = text_layout_details
21470            .scroll_anchor
21471            .scroll_position(editor_snapshot)
21472            .y;
21473
21474        if source.row().as_f32() < scroll_top.floor() {
21475            return None;
21476        }
21477        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21478        let source_y = line_height * (source.row().as_f32() - scroll_top);
21479        Some(gpui::Point::new(source_x, source_y))
21480    }
21481
21482    pub fn has_visible_completions_menu(&self) -> bool {
21483        !self.edit_prediction_preview_is_active()
21484            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21485                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21486            })
21487    }
21488
21489    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21490        if self.mode.is_minimap() {
21491            return;
21492        }
21493        self.addons
21494            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21495    }
21496
21497    pub fn unregister_addon<T: Addon>(&mut self) {
21498        self.addons.remove(&std::any::TypeId::of::<T>());
21499    }
21500
21501    pub fn addon<T: Addon>(&self) -> Option<&T> {
21502        let type_id = std::any::TypeId::of::<T>();
21503        self.addons
21504            .get(&type_id)
21505            .and_then(|item| item.to_any().downcast_ref::<T>())
21506    }
21507
21508    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21509        let type_id = std::any::TypeId::of::<T>();
21510        self.addons
21511            .get_mut(&type_id)
21512            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21513    }
21514
21515    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21516        let text_layout_details = self.text_layout_details(window);
21517        let style = &text_layout_details.editor_style;
21518        let font_id = window.text_system().resolve_font(&style.text.font());
21519        let font_size = style.text.font_size.to_pixels(window.rem_size());
21520        let line_height = style.text.line_height_in_pixels(window.rem_size());
21521        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21522        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21523
21524        CharacterDimensions {
21525            em_width,
21526            em_advance,
21527            line_height,
21528        }
21529    }
21530
21531    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21532        self.load_diff_task.clone()
21533    }
21534
21535    fn read_metadata_from_db(
21536        &mut self,
21537        item_id: u64,
21538        workspace_id: WorkspaceId,
21539        window: &mut Window,
21540        cx: &mut Context<Editor>,
21541    ) {
21542        if self.is_singleton(cx)
21543            && !self.mode.is_minimap()
21544            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21545        {
21546            let buffer_snapshot = OnceCell::new();
21547
21548            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21549                && !folds.is_empty()
21550            {
21551                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21552                self.fold_ranges(
21553                    folds
21554                        .into_iter()
21555                        .map(|(start, end)| {
21556                            snapshot.clip_offset(start, Bias::Left)
21557                                ..snapshot.clip_offset(end, Bias::Right)
21558                        })
21559                        .collect(),
21560                    false,
21561                    window,
21562                    cx,
21563                );
21564            }
21565
21566            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21567                && !selections.is_empty()
21568            {
21569                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21570                // skip adding the initial selection to selection history
21571                self.selection_history.mode = SelectionHistoryMode::Skipping;
21572                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21573                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21574                        snapshot.clip_offset(start, Bias::Left)
21575                            ..snapshot.clip_offset(end, Bias::Right)
21576                    }));
21577                });
21578                self.selection_history.mode = SelectionHistoryMode::Normal;
21579            };
21580        }
21581
21582        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21583    }
21584
21585    fn update_lsp_data(
21586        &mut self,
21587        ignore_cache: bool,
21588        for_buffer: Option<BufferId>,
21589        window: &mut Window,
21590        cx: &mut Context<'_, Self>,
21591    ) {
21592        self.pull_diagnostics(for_buffer, window, cx);
21593        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21594    }
21595}
21596
21597fn vim_enabled(cx: &App) -> bool {
21598    cx.global::<SettingsStore>()
21599        .raw_user_settings()
21600        .get("vim_mode")
21601        == Some(&serde_json::Value::Bool(true))
21602}
21603
21604fn process_completion_for_edit(
21605    completion: &Completion,
21606    intent: CompletionIntent,
21607    buffer: &Entity<Buffer>,
21608    cursor_position: &text::Anchor,
21609    cx: &mut Context<Editor>,
21610) -> CompletionEdit {
21611    let buffer = buffer.read(cx);
21612    let buffer_snapshot = buffer.snapshot();
21613    let (snippet, new_text) = if completion.is_snippet() {
21614        // Workaround for typescript language server issues so that methods don't expand within
21615        // strings and functions with type expressions. The previous point is used because the query
21616        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21617        let mut snippet_source = completion.new_text.clone();
21618        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21619        previous_point.column = previous_point.column.saturating_sub(1);
21620        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21621            && scope.prefers_label_for_snippet_in_completion()
21622            && let Some(label) = completion.label()
21623            && matches!(
21624                completion.kind(),
21625                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21626            )
21627        {
21628            snippet_source = label;
21629        }
21630        match Snippet::parse(&snippet_source).log_err() {
21631            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21632            None => (None, completion.new_text.clone()),
21633        }
21634    } else {
21635        (None, completion.new_text.clone())
21636    };
21637
21638    let mut range_to_replace = {
21639        let replace_range = &completion.replace_range;
21640        if let CompletionSource::Lsp {
21641            insert_range: Some(insert_range),
21642            ..
21643        } = &completion.source
21644        {
21645            debug_assert_eq!(
21646                insert_range.start, replace_range.start,
21647                "insert_range and replace_range should start at the same position"
21648            );
21649            debug_assert!(
21650                insert_range
21651                    .start
21652                    .cmp(cursor_position, &buffer_snapshot)
21653                    .is_le(),
21654                "insert_range should start before or at cursor position"
21655            );
21656            debug_assert!(
21657                replace_range
21658                    .start
21659                    .cmp(cursor_position, &buffer_snapshot)
21660                    .is_le(),
21661                "replace_range should start before or at cursor position"
21662            );
21663
21664            let should_replace = match intent {
21665                CompletionIntent::CompleteWithInsert => false,
21666                CompletionIntent::CompleteWithReplace => true,
21667                CompletionIntent::Complete | CompletionIntent::Compose => {
21668                    let insert_mode =
21669                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21670                            .completions
21671                            .lsp_insert_mode;
21672                    match insert_mode {
21673                        LspInsertMode::Insert => false,
21674                        LspInsertMode::Replace => true,
21675                        LspInsertMode::ReplaceSubsequence => {
21676                            let mut text_to_replace = buffer.chars_for_range(
21677                                buffer.anchor_before(replace_range.start)
21678                                    ..buffer.anchor_after(replace_range.end),
21679                            );
21680                            let mut current_needle = text_to_replace.next();
21681                            for haystack_ch in completion.label.text.chars() {
21682                                if let Some(needle_ch) = current_needle
21683                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21684                                {
21685                                    current_needle = text_to_replace.next();
21686                                }
21687                            }
21688                            current_needle.is_none()
21689                        }
21690                        LspInsertMode::ReplaceSuffix => {
21691                            if replace_range
21692                                .end
21693                                .cmp(cursor_position, &buffer_snapshot)
21694                                .is_gt()
21695                            {
21696                                let range_after_cursor = *cursor_position..replace_range.end;
21697                                let text_after_cursor = buffer
21698                                    .text_for_range(
21699                                        buffer.anchor_before(range_after_cursor.start)
21700                                            ..buffer.anchor_after(range_after_cursor.end),
21701                                    )
21702                                    .collect::<String>()
21703                                    .to_ascii_lowercase();
21704                                completion
21705                                    .label
21706                                    .text
21707                                    .to_ascii_lowercase()
21708                                    .ends_with(&text_after_cursor)
21709                            } else {
21710                                true
21711                            }
21712                        }
21713                    }
21714                }
21715            };
21716
21717            if should_replace {
21718                replace_range.clone()
21719            } else {
21720                insert_range.clone()
21721            }
21722        } else {
21723            replace_range.clone()
21724        }
21725    };
21726
21727    if range_to_replace
21728        .end
21729        .cmp(cursor_position, &buffer_snapshot)
21730        .is_lt()
21731    {
21732        range_to_replace.end = *cursor_position;
21733    }
21734
21735    CompletionEdit {
21736        new_text,
21737        replace_range: range_to_replace.to_offset(buffer),
21738        snippet,
21739    }
21740}
21741
21742struct CompletionEdit {
21743    new_text: String,
21744    replace_range: Range<usize>,
21745    snippet: Option<Snippet>,
21746}
21747
21748fn insert_extra_newline_brackets(
21749    buffer: &MultiBufferSnapshot,
21750    range: Range<usize>,
21751    language: &language::LanguageScope,
21752) -> bool {
21753    let leading_whitespace_len = buffer
21754        .reversed_chars_at(range.start)
21755        .take_while(|c| c.is_whitespace() && *c != '\n')
21756        .map(|c| c.len_utf8())
21757        .sum::<usize>();
21758    let trailing_whitespace_len = buffer
21759        .chars_at(range.end)
21760        .take_while(|c| c.is_whitespace() && *c != '\n')
21761        .map(|c| c.len_utf8())
21762        .sum::<usize>();
21763    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21764
21765    language.brackets().any(|(pair, enabled)| {
21766        let pair_start = pair.start.trim_end();
21767        let pair_end = pair.end.trim_start();
21768
21769        enabled
21770            && pair.newline
21771            && buffer.contains_str_at(range.end, pair_end)
21772            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21773    })
21774}
21775
21776fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21777    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21778        [(buffer, range, _)] => (*buffer, range.clone()),
21779        _ => return false,
21780    };
21781    let pair = {
21782        let mut result: Option<BracketMatch> = None;
21783
21784        for pair in buffer
21785            .all_bracket_ranges(range.clone())
21786            .filter(move |pair| {
21787                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21788            })
21789        {
21790            let len = pair.close_range.end - pair.open_range.start;
21791
21792            if let Some(existing) = &result {
21793                let existing_len = existing.close_range.end - existing.open_range.start;
21794                if len > existing_len {
21795                    continue;
21796                }
21797            }
21798
21799            result = Some(pair);
21800        }
21801
21802        result
21803    };
21804    let Some(pair) = pair else {
21805        return false;
21806    };
21807    pair.newline_only
21808        && buffer
21809            .chars_for_range(pair.open_range.end..range.start)
21810            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21811            .all(|c| c.is_whitespace() && c != '\n')
21812}
21813
21814fn update_uncommitted_diff_for_buffer(
21815    editor: Entity<Editor>,
21816    project: &Entity<Project>,
21817    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21818    buffer: Entity<MultiBuffer>,
21819    cx: &mut App,
21820) -> Task<()> {
21821    let mut tasks = Vec::new();
21822    project.update(cx, |project, cx| {
21823        for buffer in buffers {
21824            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21825                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21826            }
21827        }
21828    });
21829    cx.spawn(async move |cx| {
21830        let diffs = future::join_all(tasks).await;
21831        if editor
21832            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21833            .unwrap_or(false)
21834        {
21835            return;
21836        }
21837
21838        buffer
21839            .update(cx, |buffer, cx| {
21840                for diff in diffs.into_iter().flatten() {
21841                    buffer.add_diff(diff, cx);
21842                }
21843            })
21844            .ok();
21845    })
21846}
21847
21848fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21849    let tab_size = tab_size.get() as usize;
21850    let mut width = offset;
21851
21852    for ch in text.chars() {
21853        width += if ch == '\t' {
21854            tab_size - (width % tab_size)
21855        } else {
21856            1
21857        };
21858    }
21859
21860    width - offset
21861}
21862
21863#[cfg(test)]
21864mod tests {
21865    use super::*;
21866
21867    #[test]
21868    fn test_string_size_with_expanded_tabs() {
21869        let nz = |val| NonZeroU32::new(val).unwrap();
21870        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21871        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21872        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21873        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21874        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21875        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21876        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21877        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21878    }
21879}
21880
21881/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21882struct WordBreakingTokenizer<'a> {
21883    input: &'a str,
21884}
21885
21886impl<'a> WordBreakingTokenizer<'a> {
21887    fn new(input: &'a str) -> Self {
21888        Self { input }
21889    }
21890}
21891
21892fn is_char_ideographic(ch: char) -> bool {
21893    use unicode_script::Script::*;
21894    use unicode_script::UnicodeScript;
21895    matches!(ch.script(), Han | Tangut | Yi)
21896}
21897
21898fn is_grapheme_ideographic(text: &str) -> bool {
21899    text.chars().any(is_char_ideographic)
21900}
21901
21902fn is_grapheme_whitespace(text: &str) -> bool {
21903    text.chars().any(|x| x.is_whitespace())
21904}
21905
21906fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21907    text.chars()
21908        .next()
21909        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21910}
21911
21912#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21913enum WordBreakToken<'a> {
21914    Word { token: &'a str, grapheme_len: usize },
21915    InlineWhitespace { token: &'a str, grapheme_len: usize },
21916    Newline,
21917}
21918
21919impl<'a> Iterator for WordBreakingTokenizer<'a> {
21920    /// Yields a span, the count of graphemes in the token, and whether it was
21921    /// whitespace. Note that it also breaks at word boundaries.
21922    type Item = WordBreakToken<'a>;
21923
21924    fn next(&mut self) -> Option<Self::Item> {
21925        use unicode_segmentation::UnicodeSegmentation;
21926        if self.input.is_empty() {
21927            return None;
21928        }
21929
21930        let mut iter = self.input.graphemes(true).peekable();
21931        let mut offset = 0;
21932        let mut grapheme_len = 0;
21933        if let Some(first_grapheme) = iter.next() {
21934            let is_newline = first_grapheme == "\n";
21935            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21936            offset += first_grapheme.len();
21937            grapheme_len += 1;
21938            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21939                if let Some(grapheme) = iter.peek().copied()
21940                    && should_stay_with_preceding_ideograph(grapheme)
21941                {
21942                    offset += grapheme.len();
21943                    grapheme_len += 1;
21944                }
21945            } else {
21946                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21947                let mut next_word_bound = words.peek().copied();
21948                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21949                    next_word_bound = words.next();
21950                }
21951                while let Some(grapheme) = iter.peek().copied() {
21952                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21953                        break;
21954                    };
21955                    if is_grapheme_whitespace(grapheme) != is_whitespace
21956                        || (grapheme == "\n") != is_newline
21957                    {
21958                        break;
21959                    };
21960                    offset += grapheme.len();
21961                    grapheme_len += 1;
21962                    iter.next();
21963                }
21964            }
21965            let token = &self.input[..offset];
21966            self.input = &self.input[offset..];
21967            if token == "\n" {
21968                Some(WordBreakToken::Newline)
21969            } else if is_whitespace {
21970                Some(WordBreakToken::InlineWhitespace {
21971                    token,
21972                    grapheme_len,
21973                })
21974            } else {
21975                Some(WordBreakToken::Word {
21976                    token,
21977                    grapheme_len,
21978                })
21979            }
21980        } else {
21981            None
21982        }
21983    }
21984}
21985
21986#[test]
21987fn test_word_breaking_tokenizer() {
21988    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21989        ("", &[]),
21990        ("  ", &[whitespace("  ", 2)]),
21991        ("Ʒ", &[word("Ʒ", 1)]),
21992        ("Ǽ", &[word("Ǽ", 1)]),
21993        ("", &[word("", 1)]),
21994        ("⋑⋑", &[word("⋑⋑", 2)]),
21995        (
21996            "原理,进而",
21997            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21998        ),
21999        (
22000            "hello world",
22001            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22002        ),
22003        (
22004            "hello, world",
22005            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22006        ),
22007        (
22008            "  hello world",
22009            &[
22010                whitespace("  ", 2),
22011                word("hello", 5),
22012                whitespace(" ", 1),
22013                word("world", 5),
22014            ],
22015        ),
22016        (
22017            "这是什么 \n 钢笔",
22018            &[
22019                word("", 1),
22020                word("", 1),
22021                word("", 1),
22022                word("", 1),
22023                whitespace(" ", 1),
22024                newline(),
22025                whitespace(" ", 1),
22026                word("", 1),
22027                word("", 1),
22028            ],
22029        ),
22030        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22031    ];
22032
22033    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22034        WordBreakToken::Word {
22035            token,
22036            grapheme_len,
22037        }
22038    }
22039
22040    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22041        WordBreakToken::InlineWhitespace {
22042            token,
22043            grapheme_len,
22044        }
22045    }
22046
22047    fn newline() -> WordBreakToken<'static> {
22048        WordBreakToken::Newline
22049    }
22050
22051    for (input, result) in tests {
22052        assert_eq!(
22053            WordBreakingTokenizer::new(input)
22054                .collect::<Vec<_>>()
22055                .as_slice(),
22056            *result,
22057        );
22058    }
22059}
22060
22061fn wrap_with_prefix(
22062    first_line_prefix: String,
22063    subsequent_lines_prefix: String,
22064    unwrapped_text: String,
22065    wrap_column: usize,
22066    tab_size: NonZeroU32,
22067    preserve_existing_whitespace: bool,
22068) -> String {
22069    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22070    let subsequent_lines_prefix_len =
22071        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22072    let mut wrapped_text = String::new();
22073    let mut current_line = first_line_prefix;
22074    let mut is_first_line = true;
22075
22076    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22077    let mut current_line_len = first_line_prefix_len;
22078    let mut in_whitespace = false;
22079    for token in tokenizer {
22080        let have_preceding_whitespace = in_whitespace;
22081        match token {
22082            WordBreakToken::Word {
22083                token,
22084                grapheme_len,
22085            } => {
22086                in_whitespace = false;
22087                let current_prefix_len = if is_first_line {
22088                    first_line_prefix_len
22089                } else {
22090                    subsequent_lines_prefix_len
22091                };
22092                if current_line_len + grapheme_len > wrap_column
22093                    && current_line_len != current_prefix_len
22094                {
22095                    wrapped_text.push_str(current_line.trim_end());
22096                    wrapped_text.push('\n');
22097                    is_first_line = false;
22098                    current_line = subsequent_lines_prefix.clone();
22099                    current_line_len = subsequent_lines_prefix_len;
22100                }
22101                current_line.push_str(token);
22102                current_line_len += grapheme_len;
22103            }
22104            WordBreakToken::InlineWhitespace {
22105                mut token,
22106                mut grapheme_len,
22107            } => {
22108                in_whitespace = true;
22109                if have_preceding_whitespace && !preserve_existing_whitespace {
22110                    continue;
22111                }
22112                if !preserve_existing_whitespace {
22113                    token = " ";
22114                    grapheme_len = 1;
22115                }
22116                let current_prefix_len = if is_first_line {
22117                    first_line_prefix_len
22118                } else {
22119                    subsequent_lines_prefix_len
22120                };
22121                if current_line_len + grapheme_len > wrap_column {
22122                    wrapped_text.push_str(current_line.trim_end());
22123                    wrapped_text.push('\n');
22124                    is_first_line = false;
22125                    current_line = subsequent_lines_prefix.clone();
22126                    current_line_len = subsequent_lines_prefix_len;
22127                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22128                    current_line.push_str(token);
22129                    current_line_len += grapheme_len;
22130                }
22131            }
22132            WordBreakToken::Newline => {
22133                in_whitespace = true;
22134                let current_prefix_len = if is_first_line {
22135                    first_line_prefix_len
22136                } else {
22137                    subsequent_lines_prefix_len
22138                };
22139                if preserve_existing_whitespace {
22140                    wrapped_text.push_str(current_line.trim_end());
22141                    wrapped_text.push('\n');
22142                    is_first_line = false;
22143                    current_line = subsequent_lines_prefix.clone();
22144                    current_line_len = subsequent_lines_prefix_len;
22145                } else if have_preceding_whitespace {
22146                    continue;
22147                } else if current_line_len + 1 > wrap_column
22148                    && current_line_len != current_prefix_len
22149                {
22150                    wrapped_text.push_str(current_line.trim_end());
22151                    wrapped_text.push('\n');
22152                    is_first_line = false;
22153                    current_line = subsequent_lines_prefix.clone();
22154                    current_line_len = subsequent_lines_prefix_len;
22155                } else if current_line_len != current_prefix_len {
22156                    current_line.push(' ');
22157                    current_line_len += 1;
22158                }
22159            }
22160        }
22161    }
22162
22163    if !current_line.is_empty() {
22164        wrapped_text.push_str(&current_line);
22165    }
22166    wrapped_text
22167}
22168
22169#[test]
22170fn test_wrap_with_prefix() {
22171    assert_eq!(
22172        wrap_with_prefix(
22173            "# ".to_string(),
22174            "# ".to_string(),
22175            "abcdefg".to_string(),
22176            4,
22177            NonZeroU32::new(4).unwrap(),
22178            false,
22179        ),
22180        "# abcdefg"
22181    );
22182    assert_eq!(
22183        wrap_with_prefix(
22184            "".to_string(),
22185            "".to_string(),
22186            "\thello world".to_string(),
22187            8,
22188            NonZeroU32::new(4).unwrap(),
22189            false,
22190        ),
22191        "hello\nworld"
22192    );
22193    assert_eq!(
22194        wrap_with_prefix(
22195            "// ".to_string(),
22196            "// ".to_string(),
22197            "xx \nyy zz aa bb cc".to_string(),
22198            12,
22199            NonZeroU32::new(4).unwrap(),
22200            false,
22201        ),
22202        "// xx yy zz\n// aa bb cc"
22203    );
22204    assert_eq!(
22205        wrap_with_prefix(
22206            String::new(),
22207            String::new(),
22208            "这是什么 \n 钢笔".to_string(),
22209            3,
22210            NonZeroU32::new(4).unwrap(),
22211            false,
22212        ),
22213        "这是什\n么 钢\n"
22214    );
22215}
22216
22217pub trait CollaborationHub {
22218    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22219    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22220    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22221}
22222
22223impl CollaborationHub for Entity<Project> {
22224    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22225        self.read(cx).collaborators()
22226    }
22227
22228    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22229        self.read(cx).user_store().read(cx).participant_indices()
22230    }
22231
22232    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22233        let this = self.read(cx);
22234        let user_ids = this.collaborators().values().map(|c| c.user_id);
22235        this.user_store().read(cx).participant_names(user_ids, cx)
22236    }
22237}
22238
22239pub trait SemanticsProvider {
22240    fn hover(
22241        &self,
22242        buffer: &Entity<Buffer>,
22243        position: text::Anchor,
22244        cx: &mut App,
22245    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22246
22247    fn inline_values(
22248        &self,
22249        buffer_handle: Entity<Buffer>,
22250        range: Range<text::Anchor>,
22251        cx: &mut App,
22252    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22253
22254    fn inlay_hints(
22255        &self,
22256        buffer_handle: Entity<Buffer>,
22257        range: Range<text::Anchor>,
22258        cx: &mut App,
22259    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22260
22261    fn resolve_inlay_hint(
22262        &self,
22263        hint: InlayHint,
22264        buffer_handle: Entity<Buffer>,
22265        server_id: LanguageServerId,
22266        cx: &mut App,
22267    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22268
22269    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22270
22271    fn document_highlights(
22272        &self,
22273        buffer: &Entity<Buffer>,
22274        position: text::Anchor,
22275        cx: &mut App,
22276    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22277
22278    fn definitions(
22279        &self,
22280        buffer: &Entity<Buffer>,
22281        position: text::Anchor,
22282        kind: GotoDefinitionKind,
22283        cx: &mut App,
22284    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22285
22286    fn range_for_rename(
22287        &self,
22288        buffer: &Entity<Buffer>,
22289        position: text::Anchor,
22290        cx: &mut App,
22291    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22292
22293    fn perform_rename(
22294        &self,
22295        buffer: &Entity<Buffer>,
22296        position: text::Anchor,
22297        new_name: String,
22298        cx: &mut App,
22299    ) -> Option<Task<Result<ProjectTransaction>>>;
22300}
22301
22302pub trait CompletionProvider {
22303    fn completions(
22304        &self,
22305        excerpt_id: ExcerptId,
22306        buffer: &Entity<Buffer>,
22307        buffer_position: text::Anchor,
22308        trigger: CompletionContext,
22309        window: &mut Window,
22310        cx: &mut Context<Editor>,
22311    ) -> Task<Result<Vec<CompletionResponse>>>;
22312
22313    fn resolve_completions(
22314        &self,
22315        _buffer: Entity<Buffer>,
22316        _completion_indices: Vec<usize>,
22317        _completions: Rc<RefCell<Box<[Completion]>>>,
22318        _cx: &mut Context<Editor>,
22319    ) -> Task<Result<bool>> {
22320        Task::ready(Ok(false))
22321    }
22322
22323    fn apply_additional_edits_for_completion(
22324        &self,
22325        _buffer: Entity<Buffer>,
22326        _completions: Rc<RefCell<Box<[Completion]>>>,
22327        _completion_index: usize,
22328        _push_to_history: bool,
22329        _cx: &mut Context<Editor>,
22330    ) -> Task<Result<Option<language::Transaction>>> {
22331        Task::ready(Ok(None))
22332    }
22333
22334    fn is_completion_trigger(
22335        &self,
22336        buffer: &Entity<Buffer>,
22337        position: language::Anchor,
22338        text: &str,
22339        trigger_in_words: bool,
22340        menu_is_open: bool,
22341        cx: &mut Context<Editor>,
22342    ) -> bool;
22343
22344    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22345
22346    fn sort_completions(&self) -> bool {
22347        true
22348    }
22349
22350    fn filter_completions(&self) -> bool {
22351        true
22352    }
22353}
22354
22355pub trait CodeActionProvider {
22356    fn id(&self) -> Arc<str>;
22357
22358    fn code_actions(
22359        &self,
22360        buffer: &Entity<Buffer>,
22361        range: Range<text::Anchor>,
22362        window: &mut Window,
22363        cx: &mut App,
22364    ) -> Task<Result<Vec<CodeAction>>>;
22365
22366    fn apply_code_action(
22367        &self,
22368        buffer_handle: Entity<Buffer>,
22369        action: CodeAction,
22370        excerpt_id: ExcerptId,
22371        push_to_history: bool,
22372        window: &mut Window,
22373        cx: &mut App,
22374    ) -> Task<Result<ProjectTransaction>>;
22375}
22376
22377impl CodeActionProvider for Entity<Project> {
22378    fn id(&self) -> Arc<str> {
22379        "project".into()
22380    }
22381
22382    fn code_actions(
22383        &self,
22384        buffer: &Entity<Buffer>,
22385        range: Range<text::Anchor>,
22386        _window: &mut Window,
22387        cx: &mut App,
22388    ) -> Task<Result<Vec<CodeAction>>> {
22389        self.update(cx, |project, cx| {
22390            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22391            let code_actions = project.code_actions(buffer, range, None, cx);
22392            cx.background_spawn(async move {
22393                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22394                Ok(code_lens_actions
22395                    .context("code lens fetch")?
22396                    .into_iter()
22397                    .flatten()
22398                    .chain(
22399                        code_actions
22400                            .context("code action fetch")?
22401                            .into_iter()
22402                            .flatten(),
22403                    )
22404                    .collect())
22405            })
22406        })
22407    }
22408
22409    fn apply_code_action(
22410        &self,
22411        buffer_handle: Entity<Buffer>,
22412        action: CodeAction,
22413        _excerpt_id: ExcerptId,
22414        push_to_history: bool,
22415        _window: &mut Window,
22416        cx: &mut App,
22417    ) -> Task<Result<ProjectTransaction>> {
22418        self.update(cx, |project, cx| {
22419            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22420        })
22421    }
22422}
22423
22424fn snippet_completions(
22425    project: &Project,
22426    buffer: &Entity<Buffer>,
22427    buffer_position: text::Anchor,
22428    cx: &mut App,
22429) -> Task<Result<CompletionResponse>> {
22430    let languages = buffer.read(cx).languages_at(buffer_position);
22431    let snippet_store = project.snippets().read(cx);
22432
22433    let scopes: Vec<_> = languages
22434        .iter()
22435        .filter_map(|language| {
22436            let language_name = language.lsp_id();
22437            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22438
22439            if snippets.is_empty() {
22440                None
22441            } else {
22442                Some((language.default_scope(), snippets))
22443            }
22444        })
22445        .collect();
22446
22447    if scopes.is_empty() {
22448        return Task::ready(Ok(CompletionResponse {
22449            completions: vec![],
22450            display_options: CompletionDisplayOptions::default(),
22451            is_incomplete: false,
22452        }));
22453    }
22454
22455    let snapshot = buffer.read(cx).text_snapshot();
22456    let chars: String = snapshot
22457        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22458        .collect();
22459    let executor = cx.background_executor().clone();
22460
22461    cx.background_spawn(async move {
22462        let mut is_incomplete = false;
22463        let mut completions: Vec<Completion> = Vec::new();
22464        for (scope, snippets) in scopes.into_iter() {
22465            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22466            let mut last_word = chars
22467                .chars()
22468                .take_while(|c| classifier.is_word(*c))
22469                .collect::<String>();
22470            last_word = last_word.chars().rev().collect();
22471
22472            if last_word.is_empty() {
22473                return Ok(CompletionResponse {
22474                    completions: vec![],
22475                    display_options: CompletionDisplayOptions::default(),
22476                    is_incomplete: true,
22477                });
22478            }
22479
22480            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22481            let to_lsp = |point: &text::Anchor| {
22482                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22483                point_to_lsp(end)
22484            };
22485            let lsp_end = to_lsp(&buffer_position);
22486
22487            let candidates = snippets
22488                .iter()
22489                .enumerate()
22490                .flat_map(|(ix, snippet)| {
22491                    snippet
22492                        .prefix
22493                        .iter()
22494                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22495                })
22496                .collect::<Vec<StringMatchCandidate>>();
22497
22498            const MAX_RESULTS: usize = 100;
22499            let mut matches = fuzzy::match_strings(
22500                &candidates,
22501                &last_word,
22502                last_word.chars().any(|c| c.is_uppercase()),
22503                true,
22504                MAX_RESULTS,
22505                &Default::default(),
22506                executor.clone(),
22507            )
22508            .await;
22509
22510            if matches.len() >= MAX_RESULTS {
22511                is_incomplete = true;
22512            }
22513
22514            // Remove all candidates where the query's start does not match the start of any word in the candidate
22515            if let Some(query_start) = last_word.chars().next() {
22516                matches.retain(|string_match| {
22517                    split_words(&string_match.string).any(|word| {
22518                        // Check that the first codepoint of the word as lowercase matches the first
22519                        // codepoint of the query as lowercase
22520                        word.chars()
22521                            .flat_map(|codepoint| codepoint.to_lowercase())
22522                            .zip(query_start.to_lowercase())
22523                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22524                    })
22525                });
22526            }
22527
22528            let matched_strings = matches
22529                .into_iter()
22530                .map(|m| m.string)
22531                .collect::<HashSet<_>>();
22532
22533            completions.extend(snippets.iter().filter_map(|snippet| {
22534                let matching_prefix = snippet
22535                    .prefix
22536                    .iter()
22537                    .find(|prefix| matched_strings.contains(*prefix))?;
22538                let start = as_offset - last_word.len();
22539                let start = snapshot.anchor_before(start);
22540                let range = start..buffer_position;
22541                let lsp_start = to_lsp(&start);
22542                let lsp_range = lsp::Range {
22543                    start: lsp_start,
22544                    end: lsp_end,
22545                };
22546                Some(Completion {
22547                    replace_range: range,
22548                    new_text: snippet.body.clone(),
22549                    source: CompletionSource::Lsp {
22550                        insert_range: None,
22551                        server_id: LanguageServerId(usize::MAX),
22552                        resolved: true,
22553                        lsp_completion: Box::new(lsp::CompletionItem {
22554                            label: snippet.prefix.first().unwrap().clone(),
22555                            kind: Some(CompletionItemKind::SNIPPET),
22556                            label_details: snippet.description.as_ref().map(|description| {
22557                                lsp::CompletionItemLabelDetails {
22558                                    detail: Some(description.clone()),
22559                                    description: None,
22560                                }
22561                            }),
22562                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22563                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22564                                lsp::InsertReplaceEdit {
22565                                    new_text: snippet.body.clone(),
22566                                    insert: lsp_range,
22567                                    replace: lsp_range,
22568                                },
22569                            )),
22570                            filter_text: Some(snippet.body.clone()),
22571                            sort_text: Some(char::MAX.to_string()),
22572                            ..lsp::CompletionItem::default()
22573                        }),
22574                        lsp_defaults: None,
22575                    },
22576                    label: CodeLabel {
22577                        text: matching_prefix.clone(),
22578                        runs: Vec::new(),
22579                        filter_range: 0..matching_prefix.len(),
22580                    },
22581                    icon_path: None,
22582                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22583                        single_line: snippet.name.clone().into(),
22584                        plain_text: snippet
22585                            .description
22586                            .clone()
22587                            .map(|description| description.into()),
22588                    }),
22589                    insert_text_mode: None,
22590                    confirm: None,
22591                })
22592            }))
22593        }
22594
22595        Ok(CompletionResponse {
22596            completions,
22597            display_options: CompletionDisplayOptions::default(),
22598            is_incomplete,
22599        })
22600    })
22601}
22602
22603impl CompletionProvider for Entity<Project> {
22604    fn completions(
22605        &self,
22606        _excerpt_id: ExcerptId,
22607        buffer: &Entity<Buffer>,
22608        buffer_position: text::Anchor,
22609        options: CompletionContext,
22610        _window: &mut Window,
22611        cx: &mut Context<Editor>,
22612    ) -> Task<Result<Vec<CompletionResponse>>> {
22613        self.update(cx, |project, cx| {
22614            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22615            let project_completions = project.completions(buffer, buffer_position, options, cx);
22616            cx.background_spawn(async move {
22617                let mut responses = project_completions.await?;
22618                let snippets = snippets.await?;
22619                if !snippets.completions.is_empty() {
22620                    responses.push(snippets);
22621                }
22622                Ok(responses)
22623            })
22624        })
22625    }
22626
22627    fn resolve_completions(
22628        &self,
22629        buffer: Entity<Buffer>,
22630        completion_indices: Vec<usize>,
22631        completions: Rc<RefCell<Box<[Completion]>>>,
22632        cx: &mut Context<Editor>,
22633    ) -> Task<Result<bool>> {
22634        self.update(cx, |project, cx| {
22635            project.lsp_store().update(cx, |lsp_store, cx| {
22636                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22637            })
22638        })
22639    }
22640
22641    fn apply_additional_edits_for_completion(
22642        &self,
22643        buffer: Entity<Buffer>,
22644        completions: Rc<RefCell<Box<[Completion]>>>,
22645        completion_index: usize,
22646        push_to_history: bool,
22647        cx: &mut Context<Editor>,
22648    ) -> Task<Result<Option<language::Transaction>>> {
22649        self.update(cx, |project, cx| {
22650            project.lsp_store().update(cx, |lsp_store, cx| {
22651                lsp_store.apply_additional_edits_for_completion(
22652                    buffer,
22653                    completions,
22654                    completion_index,
22655                    push_to_history,
22656                    cx,
22657                )
22658            })
22659        })
22660    }
22661
22662    fn is_completion_trigger(
22663        &self,
22664        buffer: &Entity<Buffer>,
22665        position: language::Anchor,
22666        text: &str,
22667        trigger_in_words: bool,
22668        menu_is_open: bool,
22669        cx: &mut Context<Editor>,
22670    ) -> bool {
22671        let mut chars = text.chars();
22672        let char = if let Some(char) = chars.next() {
22673            char
22674        } else {
22675            return false;
22676        };
22677        if chars.next().is_some() {
22678            return false;
22679        }
22680
22681        let buffer = buffer.read(cx);
22682        let snapshot = buffer.snapshot();
22683        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22684            return false;
22685        }
22686        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22687        if trigger_in_words && classifier.is_word(char) {
22688            return true;
22689        }
22690
22691        buffer.completion_triggers().contains(text)
22692    }
22693}
22694
22695impl SemanticsProvider for Entity<Project> {
22696    fn hover(
22697        &self,
22698        buffer: &Entity<Buffer>,
22699        position: text::Anchor,
22700        cx: &mut App,
22701    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22702        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22703    }
22704
22705    fn document_highlights(
22706        &self,
22707        buffer: &Entity<Buffer>,
22708        position: text::Anchor,
22709        cx: &mut App,
22710    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22711        Some(self.update(cx, |project, cx| {
22712            project.document_highlights(buffer, position, cx)
22713        }))
22714    }
22715
22716    fn definitions(
22717        &self,
22718        buffer: &Entity<Buffer>,
22719        position: text::Anchor,
22720        kind: GotoDefinitionKind,
22721        cx: &mut App,
22722    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22723        Some(self.update(cx, |project, cx| match kind {
22724            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22725            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22726            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22727            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22728        }))
22729    }
22730
22731    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22732        self.update(cx, |project, cx| {
22733            if project
22734                .active_debug_session(cx)
22735                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22736            {
22737                return true;
22738            }
22739
22740            buffer.update(cx, |buffer, cx| {
22741                project.any_language_server_supports_inlay_hints(buffer, cx)
22742            })
22743        })
22744    }
22745
22746    fn inline_values(
22747        &self,
22748        buffer_handle: Entity<Buffer>,
22749        range: Range<text::Anchor>,
22750        cx: &mut App,
22751    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22752        self.update(cx, |project, cx| {
22753            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22754
22755            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22756        })
22757    }
22758
22759    fn inlay_hints(
22760        &self,
22761        buffer_handle: Entity<Buffer>,
22762        range: Range<text::Anchor>,
22763        cx: &mut App,
22764    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22765        Some(self.update(cx, |project, cx| {
22766            project.inlay_hints(buffer_handle, range, cx)
22767        }))
22768    }
22769
22770    fn resolve_inlay_hint(
22771        &self,
22772        hint: InlayHint,
22773        buffer_handle: Entity<Buffer>,
22774        server_id: LanguageServerId,
22775        cx: &mut App,
22776    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22777        Some(self.update(cx, |project, cx| {
22778            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22779        }))
22780    }
22781
22782    fn range_for_rename(
22783        &self,
22784        buffer: &Entity<Buffer>,
22785        position: text::Anchor,
22786        cx: &mut App,
22787    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22788        Some(self.update(cx, |project, cx| {
22789            let buffer = buffer.clone();
22790            let task = project.prepare_rename(buffer.clone(), position, cx);
22791            cx.spawn(async move |_, cx| {
22792                Ok(match task.await? {
22793                    PrepareRenameResponse::Success(range) => Some(range),
22794                    PrepareRenameResponse::InvalidPosition => None,
22795                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22796                        // Fallback on using TreeSitter info to determine identifier range
22797                        buffer.read_with(cx, |buffer, _| {
22798                            let snapshot = buffer.snapshot();
22799                            let (range, kind) = snapshot.surrounding_word(position, false);
22800                            if kind != Some(CharKind::Word) {
22801                                return None;
22802                            }
22803                            Some(
22804                                snapshot.anchor_before(range.start)
22805                                    ..snapshot.anchor_after(range.end),
22806                            )
22807                        })?
22808                    }
22809                })
22810            })
22811        }))
22812    }
22813
22814    fn perform_rename(
22815        &self,
22816        buffer: &Entity<Buffer>,
22817        position: text::Anchor,
22818        new_name: String,
22819        cx: &mut App,
22820    ) -> Option<Task<Result<ProjectTransaction>>> {
22821        Some(self.update(cx, |project, cx| {
22822            project.perform_rename(buffer.clone(), position, new_name, cx)
22823        }))
22824    }
22825}
22826
22827fn inlay_hint_settings(
22828    location: Anchor,
22829    snapshot: &MultiBufferSnapshot,
22830    cx: &mut Context<Editor>,
22831) -> InlayHintSettings {
22832    let file = snapshot.file_at(location);
22833    let language = snapshot.language_at(location).map(|l| l.name());
22834    language_settings(language, file, cx).inlay_hints
22835}
22836
22837fn consume_contiguous_rows(
22838    contiguous_row_selections: &mut Vec<Selection<Point>>,
22839    selection: &Selection<Point>,
22840    display_map: &DisplaySnapshot,
22841    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22842) -> (MultiBufferRow, MultiBufferRow) {
22843    contiguous_row_selections.push(selection.clone());
22844    let start_row = starting_row(selection, display_map);
22845    let mut end_row = ending_row(selection, display_map);
22846
22847    while let Some(next_selection) = selections.peek() {
22848        if next_selection.start.row <= end_row.0 {
22849            end_row = ending_row(next_selection, display_map);
22850            contiguous_row_selections.push(selections.next().unwrap().clone());
22851        } else {
22852            break;
22853        }
22854    }
22855    (start_row, end_row)
22856}
22857
22858fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22859    if selection.start.column > 0 {
22860        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22861    } else {
22862        MultiBufferRow(selection.start.row)
22863    }
22864}
22865
22866fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22867    if next_selection.end.column > 0 || next_selection.is_empty() {
22868        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22869    } else {
22870        MultiBufferRow(next_selection.end.row)
22871    }
22872}
22873
22874impl EditorSnapshot {
22875    pub fn remote_selections_in_range<'a>(
22876        &'a self,
22877        range: &'a Range<Anchor>,
22878        collaboration_hub: &dyn CollaborationHub,
22879        cx: &'a App,
22880    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22881        let participant_names = collaboration_hub.user_names(cx);
22882        let participant_indices = collaboration_hub.user_participant_indices(cx);
22883        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22884        let collaborators_by_replica_id = collaborators_by_peer_id
22885            .values()
22886            .map(|collaborator| (collaborator.replica_id, collaborator))
22887            .collect::<HashMap<_, _>>();
22888        self.buffer_snapshot
22889            .selections_in_range(range, false)
22890            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22891                if replica_id == AGENT_REPLICA_ID {
22892                    Some(RemoteSelection {
22893                        replica_id,
22894                        selection,
22895                        cursor_shape,
22896                        line_mode,
22897                        collaborator_id: CollaboratorId::Agent,
22898                        user_name: Some("Agent".into()),
22899                        color: cx.theme().players().agent(),
22900                    })
22901                } else {
22902                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22903                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22904                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22905                    Some(RemoteSelection {
22906                        replica_id,
22907                        selection,
22908                        cursor_shape,
22909                        line_mode,
22910                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22911                        user_name,
22912                        color: if let Some(index) = participant_index {
22913                            cx.theme().players().color_for_participant(index.0)
22914                        } else {
22915                            cx.theme().players().absent()
22916                        },
22917                    })
22918                }
22919            })
22920    }
22921
22922    pub fn hunks_for_ranges(
22923        &self,
22924        ranges: impl IntoIterator<Item = Range<Point>>,
22925    ) -> Vec<MultiBufferDiffHunk> {
22926        let mut hunks = Vec::new();
22927        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22928            HashMap::default();
22929        for query_range in ranges {
22930            let query_rows =
22931                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22932            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22933                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22934            ) {
22935                // Include deleted hunks that are adjacent to the query range, because
22936                // otherwise they would be missed.
22937                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22938                if hunk.status().is_deleted() {
22939                    intersects_range |= hunk.row_range.start == query_rows.end;
22940                    intersects_range |= hunk.row_range.end == query_rows.start;
22941                }
22942                if intersects_range {
22943                    if !processed_buffer_rows
22944                        .entry(hunk.buffer_id)
22945                        .or_default()
22946                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22947                    {
22948                        continue;
22949                    }
22950                    hunks.push(hunk);
22951                }
22952            }
22953        }
22954
22955        hunks
22956    }
22957
22958    fn display_diff_hunks_for_rows<'a>(
22959        &'a self,
22960        display_rows: Range<DisplayRow>,
22961        folded_buffers: &'a HashSet<BufferId>,
22962    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22963        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22964        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22965
22966        self.buffer_snapshot
22967            .diff_hunks_in_range(buffer_start..buffer_end)
22968            .filter_map(|hunk| {
22969                if folded_buffers.contains(&hunk.buffer_id) {
22970                    return None;
22971                }
22972
22973                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22974                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22975
22976                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22977                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22978
22979                let display_hunk = if hunk_display_start.column() != 0 {
22980                    DisplayDiffHunk::Folded {
22981                        display_row: hunk_display_start.row(),
22982                    }
22983                } else {
22984                    let mut end_row = hunk_display_end.row();
22985                    if hunk_display_end.column() > 0 {
22986                        end_row.0 += 1;
22987                    }
22988                    let is_created_file = hunk.is_created_file();
22989                    DisplayDiffHunk::Unfolded {
22990                        status: hunk.status(),
22991                        diff_base_byte_range: hunk.diff_base_byte_range,
22992                        display_row_range: hunk_display_start.row()..end_row,
22993                        multi_buffer_range: Anchor::range_in_buffer(
22994                            hunk.excerpt_id,
22995                            hunk.buffer_id,
22996                            hunk.buffer_range,
22997                        ),
22998                        is_created_file,
22999                    }
23000                };
23001
23002                Some(display_hunk)
23003            })
23004    }
23005
23006    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23007        self.display_snapshot.buffer_snapshot.language_at(position)
23008    }
23009
23010    pub fn is_focused(&self) -> bool {
23011        self.is_focused
23012    }
23013
23014    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
23015        self.placeholder_text.as_ref()
23016    }
23017
23018    pub fn scroll_position(&self) -> gpui::Point<f32> {
23019        self.scroll_anchor.scroll_position(&self.display_snapshot)
23020    }
23021
23022    fn gutter_dimensions(
23023        &self,
23024        font_id: FontId,
23025        font_size: Pixels,
23026        max_line_number_width: Pixels,
23027        cx: &App,
23028    ) -> Option<GutterDimensions> {
23029        if !self.show_gutter {
23030            return None;
23031        }
23032
23033        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23034        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23035
23036        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23037            matches!(
23038                ProjectSettings::get_global(cx).git.git_gutter,
23039                Some(GitGutterSetting::TrackedFiles)
23040            )
23041        });
23042        let gutter_settings = EditorSettings::get_global(cx).gutter;
23043        let show_line_numbers = self
23044            .show_line_numbers
23045            .unwrap_or(gutter_settings.line_numbers);
23046        let line_gutter_width = if show_line_numbers {
23047            // Avoid flicker-like gutter resizes when the line number gains another digit by
23048            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23049            let min_width_for_number_on_gutter =
23050                ch_advance * gutter_settings.min_line_number_digits as f32;
23051            max_line_number_width.max(min_width_for_number_on_gutter)
23052        } else {
23053            0.0.into()
23054        };
23055
23056        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23057        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23058
23059        let git_blame_entries_width =
23060            self.git_blame_gutter_max_author_length
23061                .map(|max_author_length| {
23062                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23063                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23064
23065                    /// The number of characters to dedicate to gaps and margins.
23066                    const SPACING_WIDTH: usize = 4;
23067
23068                    let max_char_count = max_author_length.min(renderer.max_author_length())
23069                        + ::git::SHORT_SHA_LENGTH
23070                        + MAX_RELATIVE_TIMESTAMP.len()
23071                        + SPACING_WIDTH;
23072
23073                    ch_advance * max_char_count
23074                });
23075
23076        let is_singleton = self.buffer_snapshot.is_singleton();
23077
23078        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23079        left_padding += if !is_singleton {
23080            ch_width * 4.0
23081        } else if show_runnables || show_breakpoints {
23082            ch_width * 3.0
23083        } else if show_git_gutter && show_line_numbers {
23084            ch_width * 2.0
23085        } else if show_git_gutter || show_line_numbers {
23086            ch_width
23087        } else {
23088            px(0.)
23089        };
23090
23091        let shows_folds = is_singleton && gutter_settings.folds;
23092
23093        let right_padding = if shows_folds && show_line_numbers {
23094            ch_width * 4.0
23095        } else if shows_folds || (!is_singleton && show_line_numbers) {
23096            ch_width * 3.0
23097        } else if show_line_numbers {
23098            ch_width
23099        } else {
23100            px(0.)
23101        };
23102
23103        Some(GutterDimensions {
23104            left_padding,
23105            right_padding,
23106            width: line_gutter_width + left_padding + right_padding,
23107            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23108            git_blame_entries_width,
23109        })
23110    }
23111
23112    pub fn render_crease_toggle(
23113        &self,
23114        buffer_row: MultiBufferRow,
23115        row_contains_cursor: bool,
23116        editor: Entity<Editor>,
23117        window: &mut Window,
23118        cx: &mut App,
23119    ) -> Option<AnyElement> {
23120        let folded = self.is_line_folded(buffer_row);
23121        let mut is_foldable = false;
23122
23123        if let Some(crease) = self
23124            .crease_snapshot
23125            .query_row(buffer_row, &self.buffer_snapshot)
23126        {
23127            is_foldable = true;
23128            match crease {
23129                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23130                    if let Some(render_toggle) = render_toggle {
23131                        let toggle_callback =
23132                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23133                                if folded {
23134                                    editor.update(cx, |editor, cx| {
23135                                        editor.fold_at(buffer_row, window, cx)
23136                                    });
23137                                } else {
23138                                    editor.update(cx, |editor, cx| {
23139                                        editor.unfold_at(buffer_row, window, cx)
23140                                    });
23141                                }
23142                            });
23143                        return Some((render_toggle)(
23144                            buffer_row,
23145                            folded,
23146                            toggle_callback,
23147                            window,
23148                            cx,
23149                        ));
23150                    }
23151                }
23152            }
23153        }
23154
23155        is_foldable |= self.starts_indent(buffer_row);
23156
23157        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23158            Some(
23159                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23160                    .toggle_state(folded)
23161                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23162                        if folded {
23163                            this.unfold_at(buffer_row, window, cx);
23164                        } else {
23165                            this.fold_at(buffer_row, window, cx);
23166                        }
23167                    }))
23168                    .into_any_element(),
23169            )
23170        } else {
23171            None
23172        }
23173    }
23174
23175    pub fn render_crease_trailer(
23176        &self,
23177        buffer_row: MultiBufferRow,
23178        window: &mut Window,
23179        cx: &mut App,
23180    ) -> Option<AnyElement> {
23181        let folded = self.is_line_folded(buffer_row);
23182        if let Crease::Inline { render_trailer, .. } = self
23183            .crease_snapshot
23184            .query_row(buffer_row, &self.buffer_snapshot)?
23185        {
23186            let render_trailer = render_trailer.as_ref()?;
23187            Some(render_trailer(buffer_row, folded, window, cx))
23188        } else {
23189            None
23190        }
23191    }
23192}
23193
23194impl Deref for EditorSnapshot {
23195    type Target = DisplaySnapshot;
23196
23197    fn deref(&self) -> &Self::Target {
23198        &self.display_snapshot
23199    }
23200}
23201
23202#[derive(Clone, Debug, PartialEq, Eq)]
23203pub enum EditorEvent {
23204    InputIgnored {
23205        text: Arc<str>,
23206    },
23207    InputHandled {
23208        utf16_range_to_replace: Option<Range<isize>>,
23209        text: Arc<str>,
23210    },
23211    ExcerptsAdded {
23212        buffer: Entity<Buffer>,
23213        predecessor: ExcerptId,
23214        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23215    },
23216    ExcerptsRemoved {
23217        ids: Vec<ExcerptId>,
23218        removed_buffer_ids: Vec<BufferId>,
23219    },
23220    BufferFoldToggled {
23221        ids: Vec<ExcerptId>,
23222        folded: bool,
23223    },
23224    ExcerptsEdited {
23225        ids: Vec<ExcerptId>,
23226    },
23227    ExcerptsExpanded {
23228        ids: Vec<ExcerptId>,
23229    },
23230    BufferEdited,
23231    Edited {
23232        transaction_id: clock::Lamport,
23233    },
23234    Reparsed(BufferId),
23235    Focused,
23236    FocusedIn,
23237    Blurred,
23238    DirtyChanged,
23239    Saved,
23240    TitleChanged,
23241    SelectionsChanged {
23242        local: bool,
23243    },
23244    ScrollPositionChanged {
23245        local: bool,
23246        autoscroll: bool,
23247    },
23248    TransactionUndone {
23249        transaction_id: clock::Lamport,
23250    },
23251    TransactionBegun {
23252        transaction_id: clock::Lamport,
23253    },
23254    CursorShapeChanged,
23255    BreadcrumbsChanged,
23256    PushedToNavHistory {
23257        anchor: Anchor,
23258        is_deactivate: bool,
23259    },
23260}
23261
23262impl EventEmitter<EditorEvent> for Editor {}
23263
23264impl Focusable for Editor {
23265    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23266        self.focus_handle.clone()
23267    }
23268}
23269
23270impl Render for Editor {
23271    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23272        let settings = ThemeSettings::get_global(cx);
23273
23274        let mut text_style = match self.mode {
23275            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23276                color: cx.theme().colors().editor_foreground,
23277                font_family: settings.ui_font.family.clone(),
23278                font_features: settings.ui_font.features.clone(),
23279                font_fallbacks: settings.ui_font.fallbacks.clone(),
23280                font_size: rems(0.875).into(),
23281                font_weight: settings.ui_font.weight,
23282                line_height: relative(settings.buffer_line_height.value()),
23283                ..Default::default()
23284            },
23285            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23286                color: cx.theme().colors().editor_foreground,
23287                font_family: settings.buffer_font.family.clone(),
23288                font_features: settings.buffer_font.features.clone(),
23289                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23290                font_size: settings.buffer_font_size(cx).into(),
23291                font_weight: settings.buffer_font.weight,
23292                line_height: relative(settings.buffer_line_height.value()),
23293                ..Default::default()
23294            },
23295        };
23296        if let Some(text_style_refinement) = &self.text_style_refinement {
23297            text_style.refine(text_style_refinement)
23298        }
23299
23300        let background = match self.mode {
23301            EditorMode::SingleLine => cx.theme().system().transparent,
23302            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23303            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23304            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23305        };
23306
23307        EditorElement::new(
23308            &cx.entity(),
23309            EditorStyle {
23310                background,
23311                border: cx.theme().colors().border,
23312                local_player: cx.theme().players().local(),
23313                text: text_style,
23314                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23315                syntax: cx.theme().syntax().clone(),
23316                status: cx.theme().status().clone(),
23317                inlay_hints_style: make_inlay_hints_style(cx),
23318                edit_prediction_styles: make_suggestion_styles(cx),
23319                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23320                show_underlines: self.diagnostics_enabled(),
23321            },
23322        )
23323    }
23324}
23325
23326impl EntityInputHandler for Editor {
23327    fn text_for_range(
23328        &mut self,
23329        range_utf16: Range<usize>,
23330        adjusted_range: &mut Option<Range<usize>>,
23331        _: &mut Window,
23332        cx: &mut Context<Self>,
23333    ) -> Option<String> {
23334        let snapshot = self.buffer.read(cx).read(cx);
23335        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23336        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23337        if (start.0..end.0) != range_utf16 {
23338            adjusted_range.replace(start.0..end.0);
23339        }
23340        Some(snapshot.text_for_range(start..end).collect())
23341    }
23342
23343    fn selected_text_range(
23344        &mut self,
23345        ignore_disabled_input: bool,
23346        _: &mut Window,
23347        cx: &mut Context<Self>,
23348    ) -> Option<UTF16Selection> {
23349        // Prevent the IME menu from appearing when holding down an alphabetic key
23350        // while input is disabled.
23351        if !ignore_disabled_input && !self.input_enabled {
23352            return None;
23353        }
23354
23355        let selection = self.selections.newest::<OffsetUtf16>(cx);
23356        let range = selection.range();
23357
23358        Some(UTF16Selection {
23359            range: range.start.0..range.end.0,
23360            reversed: selection.reversed,
23361        })
23362    }
23363
23364    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23365        let snapshot = self.buffer.read(cx).read(cx);
23366        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23367        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23368    }
23369
23370    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23371        self.clear_highlights::<InputComposition>(cx);
23372        self.ime_transaction.take();
23373    }
23374
23375    fn replace_text_in_range(
23376        &mut self,
23377        range_utf16: Option<Range<usize>>,
23378        text: &str,
23379        window: &mut Window,
23380        cx: &mut Context<Self>,
23381    ) {
23382        if !self.input_enabled {
23383            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23384            return;
23385        }
23386
23387        self.transact(window, cx, |this, window, cx| {
23388            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23389                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23390                Some(this.selection_replacement_ranges(range_utf16, cx))
23391            } else {
23392                this.marked_text_ranges(cx)
23393            };
23394
23395            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23396                let newest_selection_id = this.selections.newest_anchor().id;
23397                this.selections
23398                    .all::<OffsetUtf16>(cx)
23399                    .iter()
23400                    .zip(ranges_to_replace.iter())
23401                    .find_map(|(selection, range)| {
23402                        if selection.id == newest_selection_id {
23403                            Some(
23404                                (range.start.0 as isize - selection.head().0 as isize)
23405                                    ..(range.end.0 as isize - selection.head().0 as isize),
23406                            )
23407                        } else {
23408                            None
23409                        }
23410                    })
23411            });
23412
23413            cx.emit(EditorEvent::InputHandled {
23414                utf16_range_to_replace: range_to_replace,
23415                text: text.into(),
23416            });
23417
23418            if let Some(new_selected_ranges) = new_selected_ranges {
23419                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23420                    selections.select_ranges(new_selected_ranges)
23421                });
23422                this.backspace(&Default::default(), window, cx);
23423            }
23424
23425            this.handle_input(text, window, cx);
23426        });
23427
23428        if let Some(transaction) = self.ime_transaction {
23429            self.buffer.update(cx, |buffer, cx| {
23430                buffer.group_until_transaction(transaction, cx);
23431            });
23432        }
23433
23434        self.unmark_text(window, cx);
23435    }
23436
23437    fn replace_and_mark_text_in_range(
23438        &mut self,
23439        range_utf16: Option<Range<usize>>,
23440        text: &str,
23441        new_selected_range_utf16: Option<Range<usize>>,
23442        window: &mut Window,
23443        cx: &mut Context<Self>,
23444    ) {
23445        if !self.input_enabled {
23446            return;
23447        }
23448
23449        let transaction = self.transact(window, cx, |this, window, cx| {
23450            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23451                let snapshot = this.buffer.read(cx).read(cx);
23452                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23453                    for marked_range in &mut marked_ranges {
23454                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23455                        marked_range.start.0 += relative_range_utf16.start;
23456                        marked_range.start =
23457                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23458                        marked_range.end =
23459                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23460                    }
23461                }
23462                Some(marked_ranges)
23463            } else if let Some(range_utf16) = range_utf16 {
23464                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23465                Some(this.selection_replacement_ranges(range_utf16, cx))
23466            } else {
23467                None
23468            };
23469
23470            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23471                let newest_selection_id = this.selections.newest_anchor().id;
23472                this.selections
23473                    .all::<OffsetUtf16>(cx)
23474                    .iter()
23475                    .zip(ranges_to_replace.iter())
23476                    .find_map(|(selection, range)| {
23477                        if selection.id == newest_selection_id {
23478                            Some(
23479                                (range.start.0 as isize - selection.head().0 as isize)
23480                                    ..(range.end.0 as isize - selection.head().0 as isize),
23481                            )
23482                        } else {
23483                            None
23484                        }
23485                    })
23486            });
23487
23488            cx.emit(EditorEvent::InputHandled {
23489                utf16_range_to_replace: range_to_replace,
23490                text: text.into(),
23491            });
23492
23493            if let Some(ranges) = ranges_to_replace {
23494                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23495                    s.select_ranges(ranges)
23496                });
23497            }
23498
23499            let marked_ranges = {
23500                let snapshot = this.buffer.read(cx).read(cx);
23501                this.selections
23502                    .disjoint_anchors()
23503                    .iter()
23504                    .map(|selection| {
23505                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23506                    })
23507                    .collect::<Vec<_>>()
23508            };
23509
23510            if text.is_empty() {
23511                this.unmark_text(window, cx);
23512            } else {
23513                this.highlight_text::<InputComposition>(
23514                    marked_ranges.clone(),
23515                    HighlightStyle {
23516                        underline: Some(UnderlineStyle {
23517                            thickness: px(1.),
23518                            color: None,
23519                            wavy: false,
23520                        }),
23521                        ..Default::default()
23522                    },
23523                    cx,
23524                );
23525            }
23526
23527            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23528            let use_autoclose = this.use_autoclose;
23529            let use_auto_surround = this.use_auto_surround;
23530            this.set_use_autoclose(false);
23531            this.set_use_auto_surround(false);
23532            this.handle_input(text, window, cx);
23533            this.set_use_autoclose(use_autoclose);
23534            this.set_use_auto_surround(use_auto_surround);
23535
23536            if let Some(new_selected_range) = new_selected_range_utf16 {
23537                let snapshot = this.buffer.read(cx).read(cx);
23538                let new_selected_ranges = marked_ranges
23539                    .into_iter()
23540                    .map(|marked_range| {
23541                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23542                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23543                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23544                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23545                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23546                    })
23547                    .collect::<Vec<_>>();
23548
23549                drop(snapshot);
23550                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23551                    selections.select_ranges(new_selected_ranges)
23552                });
23553            }
23554        });
23555
23556        self.ime_transaction = self.ime_transaction.or(transaction);
23557        if let Some(transaction) = self.ime_transaction {
23558            self.buffer.update(cx, |buffer, cx| {
23559                buffer.group_until_transaction(transaction, cx);
23560            });
23561        }
23562
23563        if self.text_highlights::<InputComposition>(cx).is_none() {
23564            self.ime_transaction.take();
23565        }
23566    }
23567
23568    fn bounds_for_range(
23569        &mut self,
23570        range_utf16: Range<usize>,
23571        element_bounds: gpui::Bounds<Pixels>,
23572        window: &mut Window,
23573        cx: &mut Context<Self>,
23574    ) -> Option<gpui::Bounds<Pixels>> {
23575        let text_layout_details = self.text_layout_details(window);
23576        let CharacterDimensions {
23577            em_width,
23578            em_advance,
23579            line_height,
23580        } = self.character_dimensions(window);
23581
23582        let snapshot = self.snapshot(window, cx);
23583        let scroll_position = snapshot.scroll_position();
23584        let scroll_left = scroll_position.x * em_advance;
23585
23586        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23587        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23588            + self.gutter_dimensions.full_width();
23589        let y = line_height * (start.row().as_f32() - scroll_position.y);
23590
23591        Some(Bounds {
23592            origin: element_bounds.origin + point(x, y),
23593            size: size(em_width, line_height),
23594        })
23595    }
23596
23597    fn character_index_for_point(
23598        &mut self,
23599        point: gpui::Point<Pixels>,
23600        _window: &mut Window,
23601        _cx: &mut Context<Self>,
23602    ) -> Option<usize> {
23603        let position_map = self.last_position_map.as_ref()?;
23604        if !position_map.text_hitbox.contains(&point) {
23605            return None;
23606        }
23607        let display_point = position_map.point_for_position(point).previous_valid;
23608        let anchor = position_map
23609            .snapshot
23610            .display_point_to_anchor(display_point, Bias::Left);
23611        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23612        Some(utf16_offset.0)
23613    }
23614}
23615
23616trait SelectionExt {
23617    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23618    fn spanned_rows(
23619        &self,
23620        include_end_if_at_line_start: bool,
23621        map: &DisplaySnapshot,
23622    ) -> Range<MultiBufferRow>;
23623}
23624
23625impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23626    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23627        let start = self
23628            .start
23629            .to_point(&map.buffer_snapshot)
23630            .to_display_point(map);
23631        let end = self
23632            .end
23633            .to_point(&map.buffer_snapshot)
23634            .to_display_point(map);
23635        if self.reversed {
23636            end..start
23637        } else {
23638            start..end
23639        }
23640    }
23641
23642    fn spanned_rows(
23643        &self,
23644        include_end_if_at_line_start: bool,
23645        map: &DisplaySnapshot,
23646    ) -> Range<MultiBufferRow> {
23647        let start = self.start.to_point(&map.buffer_snapshot);
23648        let mut end = self.end.to_point(&map.buffer_snapshot);
23649        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23650            end.row -= 1;
23651        }
23652
23653        let buffer_start = map.prev_line_boundary(start).0;
23654        let buffer_end = map.next_line_boundary(end).0;
23655        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23656    }
23657}
23658
23659impl<T: InvalidationRegion> InvalidationStack<T> {
23660    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23661    where
23662        S: Clone + ToOffset,
23663    {
23664        while let Some(region) = self.last() {
23665            let all_selections_inside_invalidation_ranges =
23666                if selections.len() == region.ranges().len() {
23667                    selections
23668                        .iter()
23669                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23670                        .all(|(selection, invalidation_range)| {
23671                            let head = selection.head().to_offset(buffer);
23672                            invalidation_range.start <= head && invalidation_range.end >= head
23673                        })
23674                } else {
23675                    false
23676                };
23677
23678            if all_selections_inside_invalidation_ranges {
23679                break;
23680            } else {
23681                self.pop();
23682            }
23683        }
23684    }
23685}
23686
23687impl<T> Default for InvalidationStack<T> {
23688    fn default() -> Self {
23689        Self(Default::default())
23690    }
23691}
23692
23693impl<T> Deref for InvalidationStack<T> {
23694    type Target = Vec<T>;
23695
23696    fn deref(&self) -> &Self::Target {
23697        &self.0
23698    }
23699}
23700
23701impl<T> DerefMut for InvalidationStack<T> {
23702    fn deref_mut(&mut self) -> &mut Self::Target {
23703        &mut self.0
23704    }
23705}
23706
23707impl InvalidationRegion for SnippetState {
23708    fn ranges(&self) -> &[Range<Anchor>] {
23709        &self.ranges[self.active_index]
23710    }
23711}
23712
23713fn edit_prediction_edit_text(
23714    current_snapshot: &BufferSnapshot,
23715    edits: &[(Range<Anchor>, String)],
23716    edit_preview: &EditPreview,
23717    include_deletions: bool,
23718    cx: &App,
23719) -> HighlightedText {
23720    let edits = edits
23721        .iter()
23722        .map(|(anchor, text)| {
23723            (
23724                anchor.start.text_anchor..anchor.end.text_anchor,
23725                text.clone(),
23726            )
23727        })
23728        .collect::<Vec<_>>();
23729
23730    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23731}
23732
23733fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23734    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23735    // Just show the raw edit text with basic styling
23736    let mut text = String::new();
23737    let mut highlights = Vec::new();
23738
23739    let insertion_highlight_style = HighlightStyle {
23740        color: Some(cx.theme().colors().text),
23741        ..Default::default()
23742    };
23743
23744    for (_, edit_text) in edits {
23745        let start_offset = text.len();
23746        text.push_str(edit_text);
23747        let end_offset = text.len();
23748
23749        if start_offset < end_offset {
23750            highlights.push((start_offset..end_offset, insertion_highlight_style));
23751        }
23752    }
23753
23754    HighlightedText {
23755        text: text.into(),
23756        highlights,
23757    }
23758}
23759
23760pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23761    match severity {
23762        lsp::DiagnosticSeverity::ERROR => colors.error,
23763        lsp::DiagnosticSeverity::WARNING => colors.warning,
23764        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23765        lsp::DiagnosticSeverity::HINT => colors.info,
23766        _ => colors.ignored,
23767    }
23768}
23769
23770pub fn styled_runs_for_code_label<'a>(
23771    label: &'a CodeLabel,
23772    syntax_theme: &'a theme::SyntaxTheme,
23773) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23774    let fade_out = HighlightStyle {
23775        fade_out: Some(0.35),
23776        ..Default::default()
23777    };
23778
23779    let mut prev_end = label.filter_range.end;
23780    label
23781        .runs
23782        .iter()
23783        .enumerate()
23784        .flat_map(move |(ix, (range, highlight_id))| {
23785            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23786                style
23787            } else {
23788                return Default::default();
23789            };
23790            let mut muted_style = style;
23791            muted_style.highlight(fade_out);
23792
23793            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23794            if range.start >= label.filter_range.end {
23795                if range.start > prev_end {
23796                    runs.push((prev_end..range.start, fade_out));
23797                }
23798                runs.push((range.clone(), muted_style));
23799            } else if range.end <= label.filter_range.end {
23800                runs.push((range.clone(), style));
23801            } else {
23802                runs.push((range.start..label.filter_range.end, style));
23803                runs.push((label.filter_range.end..range.end, muted_style));
23804            }
23805            prev_end = cmp::max(prev_end, range.end);
23806
23807            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23808                runs.push((prev_end..label.text.len(), fade_out));
23809            }
23810
23811            runs
23812        })
23813}
23814
23815pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23816    let mut prev_index = 0;
23817    let mut prev_codepoint: Option<char> = None;
23818    text.char_indices()
23819        .chain([(text.len(), '\0')])
23820        .filter_map(move |(index, codepoint)| {
23821            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23822            let is_boundary = index == text.len()
23823                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23824                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23825            if is_boundary {
23826                let chunk = &text[prev_index..index];
23827                prev_index = index;
23828                Some(chunk)
23829            } else {
23830                None
23831            }
23832        })
23833}
23834
23835pub trait RangeToAnchorExt: Sized {
23836    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23837
23838    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23839        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23840        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23841    }
23842}
23843
23844impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23845    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23846        let start_offset = self.start.to_offset(snapshot);
23847        let end_offset = self.end.to_offset(snapshot);
23848        if start_offset == end_offset {
23849            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23850        } else {
23851            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23852        }
23853    }
23854}
23855
23856pub trait RowExt {
23857    fn as_f32(&self) -> f32;
23858
23859    fn next_row(&self) -> Self;
23860
23861    fn previous_row(&self) -> Self;
23862
23863    fn minus(&self, other: Self) -> u32;
23864}
23865
23866impl RowExt for DisplayRow {
23867    fn as_f32(&self) -> f32 {
23868        self.0 as f32
23869    }
23870
23871    fn next_row(&self) -> Self {
23872        Self(self.0 + 1)
23873    }
23874
23875    fn previous_row(&self) -> Self {
23876        Self(self.0.saturating_sub(1))
23877    }
23878
23879    fn minus(&self, other: Self) -> u32 {
23880        self.0 - other.0
23881    }
23882}
23883
23884impl RowExt for MultiBufferRow {
23885    fn as_f32(&self) -> f32 {
23886        self.0 as f32
23887    }
23888
23889    fn next_row(&self) -> Self {
23890        Self(self.0 + 1)
23891    }
23892
23893    fn previous_row(&self) -> Self {
23894        Self(self.0.saturating_sub(1))
23895    }
23896
23897    fn minus(&self, other: Self) -> u32 {
23898        self.0 - other.0
23899    }
23900}
23901
23902trait RowRangeExt {
23903    type Row;
23904
23905    fn len(&self) -> usize;
23906
23907    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23908}
23909
23910impl RowRangeExt for Range<MultiBufferRow> {
23911    type Row = MultiBufferRow;
23912
23913    fn len(&self) -> usize {
23914        (self.end.0 - self.start.0) as usize
23915    }
23916
23917    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23918        (self.start.0..self.end.0).map(MultiBufferRow)
23919    }
23920}
23921
23922impl RowRangeExt for Range<DisplayRow> {
23923    type Row = DisplayRow;
23924
23925    fn len(&self) -> usize {
23926        (self.end.0 - self.start.0) as usize
23927    }
23928
23929    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23930        (self.start.0..self.end.0).map(DisplayRow)
23931    }
23932}
23933
23934/// If select range has more than one line, we
23935/// just point the cursor to range.start.
23936fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23937    if range.start.row == range.end.row {
23938        range
23939    } else {
23940        range.start..range.start
23941    }
23942}
23943pub struct KillRing(ClipboardItem);
23944impl Global for KillRing {}
23945
23946const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23947
23948enum BreakpointPromptEditAction {
23949    Log,
23950    Condition,
23951    HitCondition,
23952}
23953
23954struct BreakpointPromptEditor {
23955    pub(crate) prompt: Entity<Editor>,
23956    editor: WeakEntity<Editor>,
23957    breakpoint_anchor: Anchor,
23958    breakpoint: Breakpoint,
23959    edit_action: BreakpointPromptEditAction,
23960    block_ids: HashSet<CustomBlockId>,
23961    editor_margins: Arc<Mutex<EditorMargins>>,
23962    _subscriptions: Vec<Subscription>,
23963}
23964
23965impl BreakpointPromptEditor {
23966    const MAX_LINES: u8 = 4;
23967
23968    fn new(
23969        editor: WeakEntity<Editor>,
23970        breakpoint_anchor: Anchor,
23971        breakpoint: Breakpoint,
23972        edit_action: BreakpointPromptEditAction,
23973        window: &mut Window,
23974        cx: &mut Context<Self>,
23975    ) -> Self {
23976        let base_text = match edit_action {
23977            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23978            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23979            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23980        }
23981        .map(|msg| msg.to_string())
23982        .unwrap_or_default();
23983
23984        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23985        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23986
23987        let prompt = cx.new(|cx| {
23988            let mut prompt = Editor::new(
23989                EditorMode::AutoHeight {
23990                    min_lines: 1,
23991                    max_lines: Some(Self::MAX_LINES as usize),
23992                },
23993                buffer,
23994                None,
23995                window,
23996                cx,
23997            );
23998            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23999            prompt.set_show_cursor_when_unfocused(false, cx);
24000            prompt.set_placeholder_text(
24001                match edit_action {
24002                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24003                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24004                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24005                },
24006                cx,
24007            );
24008
24009            prompt
24010        });
24011
24012        Self {
24013            prompt,
24014            editor,
24015            breakpoint_anchor,
24016            breakpoint,
24017            edit_action,
24018            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24019            block_ids: Default::default(),
24020            _subscriptions: vec![],
24021        }
24022    }
24023
24024    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24025        self.block_ids.extend(block_ids)
24026    }
24027
24028    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24029        if let Some(editor) = self.editor.upgrade() {
24030            let message = self
24031                .prompt
24032                .read(cx)
24033                .buffer
24034                .read(cx)
24035                .as_singleton()
24036                .expect("A multi buffer in breakpoint prompt isn't possible")
24037                .read(cx)
24038                .as_rope()
24039                .to_string();
24040
24041            editor.update(cx, |editor, cx| {
24042                editor.edit_breakpoint_at_anchor(
24043                    self.breakpoint_anchor,
24044                    self.breakpoint.clone(),
24045                    match self.edit_action {
24046                        BreakpointPromptEditAction::Log => {
24047                            BreakpointEditAction::EditLogMessage(message.into())
24048                        }
24049                        BreakpointPromptEditAction::Condition => {
24050                            BreakpointEditAction::EditCondition(message.into())
24051                        }
24052                        BreakpointPromptEditAction::HitCondition => {
24053                            BreakpointEditAction::EditHitCondition(message.into())
24054                        }
24055                    },
24056                    cx,
24057                );
24058
24059                editor.remove_blocks(self.block_ids.clone(), None, cx);
24060                cx.focus_self(window);
24061            });
24062        }
24063    }
24064
24065    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24066        self.editor
24067            .update(cx, |editor, cx| {
24068                editor.remove_blocks(self.block_ids.clone(), None, cx);
24069                window.focus(&editor.focus_handle);
24070            })
24071            .log_err();
24072    }
24073
24074    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24075        let settings = ThemeSettings::get_global(cx);
24076        let text_style = TextStyle {
24077            color: if self.prompt.read(cx).read_only(cx) {
24078                cx.theme().colors().text_disabled
24079            } else {
24080                cx.theme().colors().text
24081            },
24082            font_family: settings.buffer_font.family.clone(),
24083            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24084            font_size: settings.buffer_font_size(cx).into(),
24085            font_weight: settings.buffer_font.weight,
24086            line_height: relative(settings.buffer_line_height.value()),
24087            ..Default::default()
24088        };
24089        EditorElement::new(
24090            &self.prompt,
24091            EditorStyle {
24092                background: cx.theme().colors().editor_background,
24093                local_player: cx.theme().players().local(),
24094                text: text_style,
24095                ..Default::default()
24096            },
24097        )
24098    }
24099}
24100
24101impl Render for BreakpointPromptEditor {
24102    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24103        let editor_margins = *self.editor_margins.lock();
24104        let gutter_dimensions = editor_margins.gutter;
24105        h_flex()
24106            .key_context("Editor")
24107            .bg(cx.theme().colors().editor_background)
24108            .border_y_1()
24109            .border_color(cx.theme().status().info_border)
24110            .size_full()
24111            .py(window.line_height() / 2.5)
24112            .on_action(cx.listener(Self::confirm))
24113            .on_action(cx.listener(Self::cancel))
24114            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24115            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24116    }
24117}
24118
24119impl Focusable for BreakpointPromptEditor {
24120    fn focus_handle(&self, cx: &App) -> FocusHandle {
24121        self.prompt.focus_handle(cx)
24122    }
24123}
24124
24125fn all_edits_insertions_or_deletions(
24126    edits: &Vec<(Range<Anchor>, String)>,
24127    snapshot: &MultiBufferSnapshot,
24128) -> bool {
24129    let mut all_insertions = true;
24130    let mut all_deletions = true;
24131
24132    for (range, new_text) in edits.iter() {
24133        let range_is_empty = range.to_offset(snapshot).is_empty();
24134        let text_is_empty = new_text.is_empty();
24135
24136        if range_is_empty != text_is_empty {
24137            if range_is_empty {
24138                all_deletions = false;
24139            } else {
24140                all_insertions = false;
24141            }
24142        } else {
24143            return false;
24144        }
24145
24146        if !all_insertions && !all_deletions {
24147            return false;
24148        }
24149    }
24150    all_insertions || all_deletions
24151}
24152
24153struct MissingEditPredictionKeybindingTooltip;
24154
24155impl Render for MissingEditPredictionKeybindingTooltip {
24156    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24157        ui::tooltip_container(window, cx, |container, _, cx| {
24158            container
24159                .flex_shrink_0()
24160                .max_w_80()
24161                .min_h(rems_from_px(124.))
24162                .justify_between()
24163                .child(
24164                    v_flex()
24165                        .flex_1()
24166                        .text_ui_sm(cx)
24167                        .child(Label::new("Conflict with Accept Keybinding"))
24168                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24169                )
24170                .child(
24171                    h_flex()
24172                        .pb_1()
24173                        .gap_1()
24174                        .items_end()
24175                        .w_full()
24176                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24177                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24178                        }))
24179                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24180                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24181                        })),
24182                )
24183        })
24184    }
24185}
24186
24187#[derive(Debug, Clone, Copy, PartialEq)]
24188pub struct LineHighlight {
24189    pub background: Background,
24190    pub border: Option<gpui::Hsla>,
24191    pub include_gutter: bool,
24192    pub type_id: Option<TypeId>,
24193}
24194
24195struct LineManipulationResult {
24196    pub new_text: String,
24197    pub line_count_before: usize,
24198    pub line_count_after: usize,
24199}
24200
24201fn render_diff_hunk_controls(
24202    row: u32,
24203    status: &DiffHunkStatus,
24204    hunk_range: Range<Anchor>,
24205    is_created_file: bool,
24206    line_height: Pixels,
24207    editor: &Entity<Editor>,
24208    _window: &mut Window,
24209    cx: &mut App,
24210) -> AnyElement {
24211    h_flex()
24212        .h(line_height)
24213        .mr_1()
24214        .gap_1()
24215        .px_0p5()
24216        .pb_1()
24217        .border_x_1()
24218        .border_b_1()
24219        .border_color(cx.theme().colors().border_variant)
24220        .rounded_b_lg()
24221        .bg(cx.theme().colors().editor_background)
24222        .gap_1()
24223        .block_mouse_except_scroll()
24224        .shadow_md()
24225        .child(if status.has_secondary_hunk() {
24226            Button::new(("stage", row as u64), "Stage")
24227                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24228                .tooltip({
24229                    let focus_handle = editor.focus_handle(cx);
24230                    move |window, cx| {
24231                        Tooltip::for_action_in(
24232                            "Stage Hunk",
24233                            &::git::ToggleStaged,
24234                            &focus_handle,
24235                            window,
24236                            cx,
24237                        )
24238                    }
24239                })
24240                .on_click({
24241                    let editor = editor.clone();
24242                    move |_event, _window, cx| {
24243                        editor.update(cx, |editor, cx| {
24244                            editor.stage_or_unstage_diff_hunks(
24245                                true,
24246                                vec![hunk_range.start..hunk_range.start],
24247                                cx,
24248                            );
24249                        });
24250                    }
24251                })
24252        } else {
24253            Button::new(("unstage", row as u64), "Unstage")
24254                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24255                .tooltip({
24256                    let focus_handle = editor.focus_handle(cx);
24257                    move |window, cx| {
24258                        Tooltip::for_action_in(
24259                            "Unstage Hunk",
24260                            &::git::ToggleStaged,
24261                            &focus_handle,
24262                            window,
24263                            cx,
24264                        )
24265                    }
24266                })
24267                .on_click({
24268                    let editor = editor.clone();
24269                    move |_event, _window, cx| {
24270                        editor.update(cx, |editor, cx| {
24271                            editor.stage_or_unstage_diff_hunks(
24272                                false,
24273                                vec![hunk_range.start..hunk_range.start],
24274                                cx,
24275                            );
24276                        });
24277                    }
24278                })
24279        })
24280        .child(
24281            Button::new(("restore", row as u64), "Restore")
24282                .tooltip({
24283                    let focus_handle = editor.focus_handle(cx);
24284                    move |window, cx| {
24285                        Tooltip::for_action_in(
24286                            "Restore Hunk",
24287                            &::git::Restore,
24288                            &focus_handle,
24289                            window,
24290                            cx,
24291                        )
24292                    }
24293                })
24294                .on_click({
24295                    let editor = editor.clone();
24296                    move |_event, window, cx| {
24297                        editor.update(cx, |editor, cx| {
24298                            let snapshot = editor.snapshot(window, cx);
24299                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24300                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24301                        });
24302                    }
24303                })
24304                .disabled(is_created_file),
24305        )
24306        .when(
24307            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24308            |el| {
24309                el.child(
24310                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24311                        .shape(IconButtonShape::Square)
24312                        .icon_size(IconSize::Small)
24313                        // .disabled(!has_multiple_hunks)
24314                        .tooltip({
24315                            let focus_handle = editor.focus_handle(cx);
24316                            move |window, cx| {
24317                                Tooltip::for_action_in(
24318                                    "Next Hunk",
24319                                    &GoToHunk,
24320                                    &focus_handle,
24321                                    window,
24322                                    cx,
24323                                )
24324                            }
24325                        })
24326                        .on_click({
24327                            let editor = editor.clone();
24328                            move |_event, window, cx| {
24329                                editor.update(cx, |editor, cx| {
24330                                    let snapshot = editor.snapshot(window, cx);
24331                                    let position =
24332                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24333                                    editor.go_to_hunk_before_or_after_position(
24334                                        &snapshot,
24335                                        position,
24336                                        Direction::Next,
24337                                        window,
24338                                        cx,
24339                                    );
24340                                    editor.expand_selected_diff_hunks(cx);
24341                                });
24342                            }
24343                        }),
24344                )
24345                .child(
24346                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24347                        .shape(IconButtonShape::Square)
24348                        .icon_size(IconSize::Small)
24349                        // .disabled(!has_multiple_hunks)
24350                        .tooltip({
24351                            let focus_handle = editor.focus_handle(cx);
24352                            move |window, cx| {
24353                                Tooltip::for_action_in(
24354                                    "Previous Hunk",
24355                                    &GoToPreviousHunk,
24356                                    &focus_handle,
24357                                    window,
24358                                    cx,
24359                                )
24360                            }
24361                        })
24362                        .on_click({
24363                            let editor = editor.clone();
24364                            move |_event, window, cx| {
24365                                editor.update(cx, |editor, cx| {
24366                                    let snapshot = editor.snapshot(window, cx);
24367                                    let point =
24368                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24369                                    editor.go_to_hunk_before_or_after_position(
24370                                        &snapshot,
24371                                        point,
24372                                        Direction::Prev,
24373                                        window,
24374                                        cx,
24375                                    );
24376                                    editor.expand_selected_diff_hunks(cx);
24377                                });
24378                            }
24379                        }),
24380                )
24381            },
24382        )
24383        .into_any_element()
24384}
24385
24386pub fn multibuffer_context_lines(cx: &App) -> u32 {
24387    EditorSettings::try_get(cx)
24388        .map(|settings| settings.excerpt_context_lines)
24389        .unwrap_or(2)
24390        .clamp(1, 32)
24391}