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_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes,
   67    SearchSettings, ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82
   83use ::git::blame::BlameEntry;
   84use ::git::{Restore, blame::ParsedCommitMessage};
   85use code_context_menus::{
   86    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   87    CompletionsMenu, ContextMenuOrigin,
   88};
   89use git::blame::{GitBlame, GlobalBlameRenderer};
   90use gpui::{
   91    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   92    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   93    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   94    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   95    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   96    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   97    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   98    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   99};
  100use highlight_matching_bracket::refresh_matching_bracket_highlights;
  101use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  102pub use hover_popover::hover_markdown_style;
  103use hover_popover::{HoverState, hide_hover};
  104use indent_guides::ActiveIndentGuidesState;
  105use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  106pub use inline_completion::Direction;
  107use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  108pub use items::MAX_TAB_TITLE_LEN;
  109use itertools::Itertools;
  110use language::{
  111    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  112    CursorShape, DiagnosticEntry, DiagnosticSourceKind, DiffOptions, DocumentationConfig,
  113    EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize, Language,
  114    OffsetRangeExt, Point, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
  115    WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, LspPullDiagnostics, ProjectPath, PulledDiagnostics,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    project_settings::DiagnosticSeverity,
  137};
  138
  139pub use git::blame::BlameRenderer;
  140pub use proposed_changes_editor::{
  141    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  142};
  143use std::{cell::OnceCell, iter::Peekable, ops::Not};
  144use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  145
  146pub use lsp::CompletionContext;
  147use lsp::{
  148    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  149    LanguageServerId, LanguageServerName,
  150};
  151
  152use language::BufferSnapshot;
  153pub use lsp_ext::lsp_tasks;
  154use movement::TextLayoutDetails;
  155pub use multi_buffer::{
  156    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  157    RowInfo, ToOffset, ToPoint,
  158};
  159use multi_buffer::{
  160    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  161    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  162};
  163use parking_lot::Mutex;
  164use project::{
  165    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  166    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  167    TaskSourceKind,
  168    debugger::breakpoint_store::Breakpoint,
  169    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  170    project_settings::{GitGutterSetting, ProjectSettings},
  171};
  172use rand::prelude::*;
  173use rpc::{ErrorExt, proto::*};
  174use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  175use selections_collection::{
  176    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  177};
  178use serde::{Deserialize, Serialize};
  179use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  180use smallvec::{SmallVec, smallvec};
  181use snippet::Snippet;
  182use std::sync::Arc;
  183use std::{
  184    any::TypeId,
  185    borrow::Cow,
  186    cell::RefCell,
  187    cmp::{self, Ordering, Reverse},
  188    mem,
  189    num::NonZeroU32,
  190    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  191    path::{Path, PathBuf},
  192    rc::Rc,
  193    time::{Duration, Instant},
  194};
  195pub use sum_tree::Bias;
  196use sum_tree::TreeMap;
  197use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  198use theme::{
  199    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  200    observe_buffer_font_size_adjustment,
  201};
  202use ui::{
  203    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  204    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  205};
  206use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  207use workspace::{
  208    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  209    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  210    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  211    item::{ItemHandle, PreviewTabsSettings},
  212    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  213    searchable::SearchEvent,
  214};
  215
  216use crate::{
  217    code_context_menus::CompletionsMenuSource,
  218    hover_links::{find_url, find_url_from_range},
  219};
  220use crate::{
  221    editor_settings::MultiCursorModifier,
  222    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  223};
  224
  225pub const FILE_HEADER_HEIGHT: u32 = 2;
  226pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  227pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  228const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  229const MAX_LINE_LEN: usize = 1024;
  230const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  231const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  232pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  233#[doc(hidden)]
  234pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  235const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  236
  237pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  238pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  240
  241pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  242pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  243pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  244
  245pub type RenderDiffHunkControlsFn = Arc<
  246    dyn Fn(
  247        u32,
  248        &DiffHunkStatus,
  249        Range<Anchor>,
  250        bool,
  251        Pixels,
  252        &Entity<Editor>,
  253        &mut Window,
  254        &mut App,
  255    ) -> AnyElement,
  256>;
  257
  258struct InlineValueCache {
  259    enabled: bool,
  260    inlays: Vec<InlayId>,
  261    refresh_task: Task<Option<()>>,
  262}
  263
  264impl InlineValueCache {
  265    fn new(enabled: bool) -> Self {
  266        Self {
  267            enabled,
  268            inlays: Vec::new(),
  269            refresh_task: Task::ready(None),
  270        }
  271    }
  272}
  273
  274#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  275pub enum InlayId {
  276    InlineCompletion(usize),
  277    Hint(usize),
  278    DebuggerValue(usize),
  279}
  280
  281impl InlayId {
  282    fn id(&self) -> usize {
  283        match self {
  284            Self::InlineCompletion(id) => *id,
  285            Self::Hint(id) => *id,
  286            Self::DebuggerValue(id) => *id,
  287        }
  288    }
  289}
  290
  291pub enum ActiveDebugLine {}
  292pub enum DebugStackFrameLine {}
  293enum DocumentHighlightRead {}
  294enum DocumentHighlightWrite {}
  295enum InputComposition {}
  296pub enum PendingInput {}
  297enum SelectedTextHighlight {}
  298
  299pub enum ConflictsOuter {}
  300pub enum ConflictsOurs {}
  301pub enum ConflictsTheirs {}
  302pub enum ConflictsOursMarker {}
  303pub enum ConflictsTheirsMarker {}
  304
  305#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  306pub enum Navigated {
  307    Yes,
  308    No,
  309}
  310
  311impl Navigated {
  312    pub fn from_bool(yes: bool) -> Navigated {
  313        if yes { Navigated::Yes } else { Navigated::No }
  314    }
  315}
  316
  317#[derive(Debug, Clone, PartialEq, Eq)]
  318enum DisplayDiffHunk {
  319    Folded {
  320        display_row: DisplayRow,
  321    },
  322    Unfolded {
  323        is_created_file: bool,
  324        diff_base_byte_range: Range<usize>,
  325        display_row_range: Range<DisplayRow>,
  326        multi_buffer_range: Range<Anchor>,
  327        status: DiffHunkStatus,
  328    },
  329}
  330
  331pub enum HideMouseCursorOrigin {
  332    TypingAction,
  333    MovementAction,
  334}
  335
  336pub fn init_settings(cx: &mut App) {
  337    EditorSettings::register(cx);
  338}
  339
  340pub fn init(cx: &mut App) {
  341    init_settings(cx);
  342
  343    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  344
  345    workspace::register_project_item::<Editor>(cx);
  346    workspace::FollowableViewRegistry::register::<Editor>(cx);
  347    workspace::register_serializable_item::<Editor>(cx);
  348
  349    cx.observe_new(
  350        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  351            workspace.register_action(Editor::new_file);
  352            workspace.register_action(Editor::new_file_vertical);
  353            workspace.register_action(Editor::new_file_horizontal);
  354            workspace.register_action(Editor::cancel_language_server_work);
  355        },
  356    )
  357    .detach();
  358
  359    cx.on_action(move |_: &workspace::NewFile, cx| {
  360        let app_state = workspace::AppState::global(cx);
  361        if let Some(app_state) = app_state.upgrade() {
  362            workspace::open_new(
  363                Default::default(),
  364                app_state,
  365                cx,
  366                |workspace, window, cx| {
  367                    Editor::new_file(workspace, &Default::default(), window, cx)
  368                },
  369            )
  370            .detach();
  371        }
  372    });
  373    cx.on_action(move |_: &workspace::NewWindow, 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                    cx.activate(true);
  382                    Editor::new_file(workspace, &Default::default(), window, cx)
  383                },
  384            )
  385            .detach();
  386        }
  387    });
  388}
  389
  390pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  391    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  392}
  393
  394pub trait DiagnosticRenderer {
  395    fn render_group(
  396        &self,
  397        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  398        buffer_id: BufferId,
  399        snapshot: EditorSnapshot,
  400        editor: WeakEntity<Editor>,
  401        cx: &mut App,
  402    ) -> Vec<BlockProperties<Anchor>>;
  403
  404    fn render_hover(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  407        range: Range<Point>,
  408        buffer_id: BufferId,
  409        cx: &mut App,
  410    ) -> Option<Entity<markdown::Markdown>>;
  411
  412    fn open_link(
  413        &self,
  414        editor: &mut Editor,
  415        link: SharedString,
  416        window: &mut Window,
  417        cx: &mut Context<Editor>,
  418    );
  419}
  420
  421pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  422
  423impl GlobalDiagnosticRenderer {
  424    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  425        cx.try_global::<Self>().map(|g| g.0.clone())
  426    }
  427}
  428
  429impl gpui::Global for GlobalDiagnosticRenderer {}
  430pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  431    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  432}
  433
  434pub struct SearchWithinRange;
  435
  436trait InvalidationRegion {
  437    fn ranges(&self) -> &[Range<Anchor>];
  438}
  439
  440#[derive(Clone, Debug, PartialEq)]
  441pub enum SelectPhase {
  442    Begin {
  443        position: DisplayPoint,
  444        add: bool,
  445        click_count: usize,
  446    },
  447    BeginColumnar {
  448        position: DisplayPoint,
  449        reset: bool,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug)]
  465pub enum SelectMode {
  466    Character,
  467    Word(Range<Anchor>),
  468    Line(Range<Anchor>),
  469    All,
  470}
  471
  472#[derive(Clone, PartialEq, Eq, Debug)]
  473pub enum EditorMode {
  474    SingleLine {
  475        auto_width: bool,
  476    },
  477    AutoHeight {
  478        max_lines: usize,
  479    },
  480    Full {
  481        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  482        scale_ui_elements_with_buffer_font_size: bool,
  483        /// When set to `true`, the editor will render a background for the active line.
  484        show_active_line_background: bool,
  485        /// When set to `true`, the editor's height will be determined by its content.
  486        sized_by_content: bool,
  487    },
  488    Minimap {
  489        parent: WeakEntity<Editor>,
  490    },
  491}
  492
  493impl EditorMode {
  494    pub fn full() -> Self {
  495        Self::Full {
  496            scale_ui_elements_with_buffer_font_size: true,
  497            show_active_line_background: true,
  498            sized_by_content: false,
  499        }
  500    }
  501
  502    pub fn is_full(&self) -> bool {
  503        matches!(self, Self::Full { .. })
  504    }
  505
  506    fn is_minimap(&self) -> bool {
  507        matches!(self, Self::Minimap { .. })
  508    }
  509}
  510
  511#[derive(Copy, Clone, Debug)]
  512pub enum SoftWrap {
  513    /// Prefer not to wrap at all.
  514    ///
  515    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  516    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  517    GitDiff,
  518    /// Prefer a single line generally, unless an overly long line is encountered.
  519    None,
  520    /// Soft wrap lines that exceed the editor width.
  521    EditorWidth,
  522    /// Soft wrap lines at the preferred line length.
  523    Column(u32),
  524    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  525    Bounded(u32),
  526}
  527
  528#[derive(Clone)]
  529pub struct EditorStyle {
  530    pub background: Hsla,
  531    pub local_player: PlayerColor,
  532    pub text: TextStyle,
  533    pub scrollbar_width: Pixels,
  534    pub syntax: Arc<SyntaxTheme>,
  535    pub status: StatusColors,
  536    pub inlay_hints_style: HighlightStyle,
  537    pub inline_completion_styles: InlineCompletionStyles,
  538    pub unnecessary_code_fade: f32,
  539    pub show_underlines: bool,
  540}
  541
  542impl Default for EditorStyle {
  543    fn default() -> Self {
  544        Self {
  545            background: Hsla::default(),
  546            local_player: PlayerColor::default(),
  547            text: TextStyle::default(),
  548            scrollbar_width: Pixels::default(),
  549            syntax: Default::default(),
  550            // HACK: Status colors don't have a real default.
  551            // We should look into removing the status colors from the editor
  552            // style and retrieve them directly from the theme.
  553            status: StatusColors::dark(),
  554            inlay_hints_style: HighlightStyle::default(),
  555            inline_completion_styles: InlineCompletionStyles {
  556                insertion: HighlightStyle::default(),
  557                whitespace: HighlightStyle::default(),
  558            },
  559            unnecessary_code_fade: Default::default(),
  560            show_underlines: true,
  561        }
  562    }
  563}
  564
  565pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  566    let show_background = language_settings::language_settings(None, None, cx)
  567        .inlay_hints
  568        .show_background;
  569
  570    HighlightStyle {
  571        color: Some(cx.theme().status().hint),
  572        background_color: show_background.then(|| cx.theme().status().hint_background),
  573        ..HighlightStyle::default()
  574    }
  575}
  576
  577pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  578    InlineCompletionStyles {
  579        insertion: HighlightStyle {
  580            color: Some(cx.theme().status().predictive),
  581            ..HighlightStyle::default()
  582        },
  583        whitespace: HighlightStyle {
  584            background_color: Some(cx.theme().status().created_background),
  585            ..HighlightStyle::default()
  586        },
  587    }
  588}
  589
  590type CompletionId = usize;
  591
  592pub(crate) enum EditDisplayMode {
  593    TabAccept,
  594    DiffPopover,
  595    Inline,
  596}
  597
  598enum InlineCompletion {
  599    Edit {
  600        edits: Vec<(Range<Anchor>, String)>,
  601        edit_preview: Option<EditPreview>,
  602        display_mode: EditDisplayMode,
  603        snapshot: BufferSnapshot,
  604    },
  605    Move {
  606        target: Anchor,
  607        snapshot: BufferSnapshot,
  608    },
  609}
  610
  611struct InlineCompletionState {
  612    inlay_ids: Vec<InlayId>,
  613    completion: InlineCompletion,
  614    completion_id: Option<SharedString>,
  615    invalidation_range: Range<Anchor>,
  616}
  617
  618enum EditPredictionSettings {
  619    Disabled,
  620    Enabled {
  621        show_in_menu: bool,
  622        preview_requires_modifier: bool,
  623    },
  624}
  625
  626enum InlineCompletionHighlight {}
  627
  628#[derive(Debug, Clone)]
  629struct InlineDiagnostic {
  630    message: SharedString,
  631    group_id: usize,
  632    is_primary: bool,
  633    start: Point,
  634    severity: lsp::DiagnosticSeverity,
  635}
  636
  637pub enum MenuInlineCompletionsPolicy {
  638    Never,
  639    ByProvider,
  640}
  641
  642pub enum EditPredictionPreview {
  643    /// Modifier is not pressed
  644    Inactive { released_too_fast: bool },
  645    /// Modifier pressed
  646    Active {
  647        since: Instant,
  648        previous_scroll_position: Option<ScrollAnchor>,
  649    },
  650}
  651
  652impl EditPredictionPreview {
  653    pub fn released_too_fast(&self) -> bool {
  654        match self {
  655            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  656            EditPredictionPreview::Active { .. } => false,
  657        }
  658    }
  659
  660    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  661        if let EditPredictionPreview::Active {
  662            previous_scroll_position,
  663            ..
  664        } = self
  665        {
  666            *previous_scroll_position = scroll_position;
  667        }
  668    }
  669}
  670
  671pub struct ContextMenuOptions {
  672    pub min_entries_visible: usize,
  673    pub max_entries_visible: usize,
  674    pub placement: Option<ContextMenuPlacement>,
  675}
  676
  677#[derive(Debug, Clone, PartialEq, Eq)]
  678pub enum ContextMenuPlacement {
  679    Above,
  680    Below,
  681}
  682
  683#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  684struct EditorActionId(usize);
  685
  686impl EditorActionId {
  687    pub fn post_inc(&mut self) -> Self {
  688        let answer = self.0;
  689
  690        *self = Self(answer + 1);
  691
  692        Self(answer)
  693    }
  694}
  695
  696// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  697// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  698
  699type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  700type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  701
  702#[derive(Default)]
  703struct ScrollbarMarkerState {
  704    scrollbar_size: Size<Pixels>,
  705    dirty: bool,
  706    markers: Arc<[PaintQuad]>,
  707    pending_refresh: Option<Task<Result<()>>>,
  708}
  709
  710impl ScrollbarMarkerState {
  711    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  712        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  713    }
  714}
  715
  716#[derive(Clone, Copy, PartialEq, Eq)]
  717pub enum MinimapVisibility {
  718    Disabled,
  719    Enabled {
  720        /// The configuration currently present in the users settings.
  721        setting_configuration: bool,
  722        /// Whether to override the currently set visibility from the users setting.
  723        toggle_override: bool,
  724    },
  725}
  726
  727impl MinimapVisibility {
  728    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  729        if mode.is_full() {
  730            Self::Enabled {
  731                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  732                toggle_override: false,
  733            }
  734        } else {
  735            Self::Disabled
  736        }
  737    }
  738
  739    fn hidden(&self) -> Self {
  740        match *self {
  741            Self::Enabled {
  742                setting_configuration,
  743                ..
  744            } => Self::Enabled {
  745                setting_configuration,
  746                toggle_override: setting_configuration,
  747            },
  748            Self::Disabled => Self::Disabled,
  749        }
  750    }
  751
  752    fn disabled(&self) -> bool {
  753        match *self {
  754            Self::Disabled => true,
  755            _ => false,
  756        }
  757    }
  758
  759    fn settings_visibility(&self) -> bool {
  760        match *self {
  761            Self::Enabled {
  762                setting_configuration,
  763                ..
  764            } => setting_configuration,
  765            _ => false,
  766        }
  767    }
  768
  769    fn visible(&self) -> bool {
  770        match *self {
  771            Self::Enabled {
  772                setting_configuration,
  773                toggle_override,
  774            } => setting_configuration ^ toggle_override,
  775            _ => false,
  776        }
  777    }
  778
  779    fn toggle_visibility(&self) -> Self {
  780        match *self {
  781            Self::Enabled {
  782                toggle_override,
  783                setting_configuration,
  784            } => Self::Enabled {
  785                setting_configuration,
  786                toggle_override: !toggle_override,
  787            },
  788            Self::Disabled => Self::Disabled,
  789        }
  790    }
  791}
  792
  793#[derive(Clone, Debug)]
  794struct RunnableTasks {
  795    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  796    offset: multi_buffer::Anchor,
  797    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  798    column: u32,
  799    // Values of all named captures, including those starting with '_'
  800    extra_variables: HashMap<String, String>,
  801    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  802    context_range: Range<BufferOffset>,
  803}
  804
  805impl RunnableTasks {
  806    fn resolve<'a>(
  807        &'a self,
  808        cx: &'a task::TaskContext,
  809    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  810        self.templates.iter().filter_map(|(kind, template)| {
  811            template
  812                .resolve_task(&kind.to_id_base(), cx)
  813                .map(|task| (kind.clone(), task))
  814        })
  815    }
  816}
  817
  818#[derive(Clone)]
  819pub struct ResolvedTasks {
  820    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  821    position: Anchor,
  822}
  823
  824#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  825struct BufferOffset(usize);
  826
  827// Addons allow storing per-editor state in other crates (e.g. Vim)
  828pub trait Addon: 'static {
  829    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  830
  831    fn render_buffer_header_controls(
  832        &self,
  833        _: &ExcerptInfo,
  834        _: &Window,
  835        _: &App,
  836    ) -> Option<AnyElement> {
  837        None
  838    }
  839
  840    fn to_any(&self) -> &dyn std::any::Any;
  841
  842    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  843        None
  844    }
  845}
  846
  847/// A set of caret positions, registered when the editor was edited.
  848pub struct ChangeList {
  849    changes: Vec<Vec<Anchor>>,
  850    /// Currently "selected" change.
  851    position: Option<usize>,
  852}
  853
  854impl ChangeList {
  855    pub fn new() -> Self {
  856        Self {
  857            changes: Vec::new(),
  858            position: None,
  859        }
  860    }
  861
  862    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  863    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  864    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  865        if self.changes.is_empty() {
  866            return None;
  867        }
  868
  869        let prev = self.position.unwrap_or(self.changes.len());
  870        let next = if direction == Direction::Prev {
  871            prev.saturating_sub(count)
  872        } else {
  873            (prev + count).min(self.changes.len() - 1)
  874        };
  875        self.position = Some(next);
  876        self.changes.get(next).map(|anchors| anchors.as_slice())
  877    }
  878
  879    /// Adds a new change to the list, resetting the change list position.
  880    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  881        self.position.take();
  882        if pop_state {
  883            self.changes.pop();
  884        }
  885        self.changes.push(new_positions.clone());
  886    }
  887
  888    pub fn last(&self) -> Option<&[Anchor]> {
  889        self.changes.last().map(|anchors| anchors.as_slice())
  890    }
  891}
  892
  893#[derive(Clone)]
  894struct InlineBlamePopoverState {
  895    scroll_handle: ScrollHandle,
  896    commit_message: Option<ParsedCommitMessage>,
  897    markdown: Entity<Markdown>,
  898}
  899
  900struct InlineBlamePopover {
  901    position: gpui::Point<Pixels>,
  902    show_task: Option<Task<()>>,
  903    hide_task: Option<Task<()>>,
  904    popover_bounds: Option<Bounds<Pixels>>,
  905    popover_state: InlineBlamePopoverState,
  906}
  907
  908enum SelectionDragState {
  909    /// State when no drag related activity is detected.
  910    None,
  911    /// State when the mouse is down on a selection that is about to be dragged.
  912    ReadyToDrag {
  913        selection: Selection<Anchor>,
  914        click_position: gpui::Point<Pixels>,
  915    },
  916    /// State when the mouse is dragging the selection in the editor.
  917    Dragging {
  918        selection: Selection<Anchor>,
  919        drop_cursor: Selection<Anchor>,
  920        hide_drop_cursor: bool,
  921    },
  922}
  923
  924/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  925/// a breakpoint on them.
  926#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  927struct PhantomBreakpointIndicator {
  928    display_row: DisplayRow,
  929    /// There's a small debounce between hovering over the line and showing the indicator.
  930    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  931    is_active: bool,
  932    collides_with_existing_breakpoint: bool,
  933}
  934
  935/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  936///
  937/// See the [module level documentation](self) for more information.
  938pub struct Editor {
  939    focus_handle: FocusHandle,
  940    last_focused_descendant: Option<WeakFocusHandle>,
  941    /// The text buffer being edited
  942    buffer: Entity<MultiBuffer>,
  943    /// Map of how text in the buffer should be displayed.
  944    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  945    pub display_map: Entity<DisplayMap>,
  946    pub selections: SelectionsCollection,
  947    pub scroll_manager: ScrollManager,
  948    /// When inline assist editors are linked, they all render cursors because
  949    /// typing enters text into each of them, even the ones that aren't focused.
  950    pub(crate) show_cursor_when_unfocused: bool,
  951    columnar_selection_tail: Option<Anchor>,
  952    columnar_display_point: Option<DisplayPoint>,
  953    add_selections_state: Option<AddSelectionsState>,
  954    select_next_state: Option<SelectNextState>,
  955    select_prev_state: Option<SelectNextState>,
  956    selection_history: SelectionHistory,
  957    defer_selection_effects: bool,
  958    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  959    autoclose_regions: Vec<AutocloseRegion>,
  960    snippet_stack: InvalidationStack<SnippetState>,
  961    select_syntax_node_history: SelectSyntaxNodeHistory,
  962    ime_transaction: Option<TransactionId>,
  963    pub diagnostics_max_severity: DiagnosticSeverity,
  964    active_diagnostics: ActiveDiagnostic,
  965    show_inline_diagnostics: bool,
  966    inline_diagnostics_update: Task<()>,
  967    inline_diagnostics_enabled: bool,
  968    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  969    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  970    hard_wrap: Option<usize>,
  971
  972    // TODO: make this a access method
  973    pub project: Option<Entity<Project>>,
  974    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  975    completion_provider: Option<Rc<dyn CompletionProvider>>,
  976    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  977    blink_manager: Entity<BlinkManager>,
  978    show_cursor_names: bool,
  979    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  980    pub show_local_selections: bool,
  981    mode: EditorMode,
  982    show_breadcrumbs: bool,
  983    show_gutter: bool,
  984    show_scrollbars: ScrollbarAxes,
  985    minimap_visibility: MinimapVisibility,
  986    offset_content: bool,
  987    disable_expand_excerpt_buttons: bool,
  988    show_line_numbers: Option<bool>,
  989    use_relative_line_numbers: Option<bool>,
  990    show_git_diff_gutter: Option<bool>,
  991    show_code_actions: Option<bool>,
  992    show_runnables: Option<bool>,
  993    show_breakpoints: Option<bool>,
  994    show_wrap_guides: Option<bool>,
  995    show_indent_guides: Option<bool>,
  996    placeholder_text: Option<Arc<str>>,
  997    highlight_order: usize,
  998    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  999    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
 1000    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1001    scrollbar_marker_state: ScrollbarMarkerState,
 1002    active_indent_guides_state: ActiveIndentGuidesState,
 1003    nav_history: Option<ItemNavHistory>,
 1004    context_menu: RefCell<Option<CodeContextMenu>>,
 1005    context_menu_options: Option<ContextMenuOptions>,
 1006    mouse_context_menu: Option<MouseContextMenu>,
 1007    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1008    inline_blame_popover: Option<InlineBlamePopover>,
 1009    signature_help_state: SignatureHelpState,
 1010    auto_signature_help: Option<bool>,
 1011    find_all_references_task_sources: Vec<Anchor>,
 1012    next_completion_id: CompletionId,
 1013    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1014    code_actions_task: Option<Task<Result<()>>>,
 1015    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1016    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1017    document_highlights_task: Option<Task<()>>,
 1018    linked_editing_range_task: Option<Task<Option<()>>>,
 1019    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1020    pending_rename: Option<RenameState>,
 1021    searchable: bool,
 1022    cursor_shape: CursorShape,
 1023    current_line_highlight: Option<CurrentLineHighlight>,
 1024    collapse_matches: bool,
 1025    autoindent_mode: Option<AutoindentMode>,
 1026    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1027    input_enabled: bool,
 1028    use_modal_editing: bool,
 1029    read_only: bool,
 1030    leader_id: Option<CollaboratorId>,
 1031    remote_id: Option<ViewId>,
 1032    pub hover_state: HoverState,
 1033    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1034    gutter_hovered: bool,
 1035    hovered_link_state: Option<HoveredLinkState>,
 1036    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1037    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1038    active_inline_completion: Option<InlineCompletionState>,
 1039    /// Used to prevent flickering as the user types while the menu is open
 1040    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1041    edit_prediction_settings: EditPredictionSettings,
 1042    inline_completions_hidden_for_vim_mode: bool,
 1043    show_inline_completions_override: Option<bool>,
 1044    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1045    edit_prediction_preview: EditPredictionPreview,
 1046    edit_prediction_indent_conflict: bool,
 1047    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1048    inlay_hint_cache: InlayHintCache,
 1049    next_inlay_id: usize,
 1050    _subscriptions: Vec<Subscription>,
 1051    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1052    gutter_dimensions: GutterDimensions,
 1053    style: Option<EditorStyle>,
 1054    text_style_refinement: Option<TextStyleRefinement>,
 1055    next_editor_action_id: EditorActionId,
 1056    editor_actions: Rc<
 1057        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1058    >,
 1059    use_autoclose: bool,
 1060    use_auto_surround: bool,
 1061    auto_replace_emoji_shortcode: bool,
 1062    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1063    show_git_blame_gutter: bool,
 1064    show_git_blame_inline: bool,
 1065    show_git_blame_inline_delay_task: Option<Task<()>>,
 1066    git_blame_inline_enabled: bool,
 1067    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1068    serialize_dirty_buffers: bool,
 1069    show_selection_menu: Option<bool>,
 1070    blame: Option<Entity<GitBlame>>,
 1071    blame_subscription: Option<Subscription>,
 1072    custom_context_menu: Option<
 1073        Box<
 1074            dyn 'static
 1075                + Fn(
 1076                    &mut Self,
 1077                    DisplayPoint,
 1078                    &mut Window,
 1079                    &mut Context<Self>,
 1080                ) -> Option<Entity<ui::ContextMenu>>,
 1081        >,
 1082    >,
 1083    last_bounds: Option<Bounds<Pixels>>,
 1084    last_position_map: Option<Rc<PositionMap>>,
 1085    expect_bounds_change: Option<Bounds<Pixels>>,
 1086    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1087    tasks_update_task: Option<Task<()>>,
 1088    breakpoint_store: Option<Entity<BreakpointStore>>,
 1089    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1090    pull_diagnostics_task: Task<()>,
 1091    in_project_search: bool,
 1092    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1093    breadcrumb_header: Option<String>,
 1094    focused_block: Option<FocusedBlock>,
 1095    next_scroll_position: NextScrollCursorCenterTopBottom,
 1096    addons: HashMap<TypeId, Box<dyn Addon>>,
 1097    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1098    load_diff_task: Option<Shared<Task<()>>>,
 1099    /// Whether we are temporarily displaying a diff other than git's
 1100    temporary_diff_override: bool,
 1101    selection_mark_mode: bool,
 1102    toggle_fold_multiple_buffers: Task<()>,
 1103    _scroll_cursor_center_top_bottom_task: Task<()>,
 1104    serialize_selections: Task<()>,
 1105    serialize_folds: Task<()>,
 1106    mouse_cursor_hidden: bool,
 1107    minimap: Option<Entity<Self>>,
 1108    hide_mouse_mode: HideMouseMode,
 1109    pub change_list: ChangeList,
 1110    inline_value_cache: InlineValueCache,
 1111    selection_drag_state: SelectionDragState,
 1112    drag_and_drop_selection_enabled: bool,
 1113}
 1114
 1115#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1116enum NextScrollCursorCenterTopBottom {
 1117    #[default]
 1118    Center,
 1119    Top,
 1120    Bottom,
 1121}
 1122
 1123impl NextScrollCursorCenterTopBottom {
 1124    fn next(&self) -> Self {
 1125        match self {
 1126            Self::Center => Self::Top,
 1127            Self::Top => Self::Bottom,
 1128            Self::Bottom => Self::Center,
 1129        }
 1130    }
 1131}
 1132
 1133#[derive(Clone)]
 1134pub struct EditorSnapshot {
 1135    pub mode: EditorMode,
 1136    show_gutter: bool,
 1137    show_line_numbers: Option<bool>,
 1138    show_git_diff_gutter: Option<bool>,
 1139    show_code_actions: Option<bool>,
 1140    show_runnables: Option<bool>,
 1141    show_breakpoints: Option<bool>,
 1142    git_blame_gutter_max_author_length: Option<usize>,
 1143    pub display_snapshot: DisplaySnapshot,
 1144    pub placeholder_text: Option<Arc<str>>,
 1145    is_focused: bool,
 1146    scroll_anchor: ScrollAnchor,
 1147    ongoing_scroll: OngoingScroll,
 1148    current_line_highlight: CurrentLineHighlight,
 1149    gutter_hovered: bool,
 1150}
 1151
 1152#[derive(Default, Debug, Clone, Copy)]
 1153pub struct GutterDimensions {
 1154    pub left_padding: Pixels,
 1155    pub right_padding: Pixels,
 1156    pub width: Pixels,
 1157    pub margin: Pixels,
 1158    pub git_blame_entries_width: Option<Pixels>,
 1159}
 1160
 1161impl GutterDimensions {
 1162    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1163        Self {
 1164            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1165            ..Default::default()
 1166        }
 1167    }
 1168
 1169    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1170        -cx.text_system().descent(font_id, font_size)
 1171    }
 1172    /// The full width of the space taken up by the gutter.
 1173    pub fn full_width(&self) -> Pixels {
 1174        self.margin + self.width
 1175    }
 1176
 1177    /// The width of the space reserved for the fold indicators,
 1178    /// use alongside 'justify_end' and `gutter_width` to
 1179    /// right align content with the line numbers
 1180    pub fn fold_area_width(&self) -> Pixels {
 1181        self.margin + self.right_padding
 1182    }
 1183}
 1184
 1185#[derive(Debug)]
 1186pub struct RemoteSelection {
 1187    pub replica_id: ReplicaId,
 1188    pub selection: Selection<Anchor>,
 1189    pub cursor_shape: CursorShape,
 1190    pub collaborator_id: CollaboratorId,
 1191    pub line_mode: bool,
 1192    pub user_name: Option<SharedString>,
 1193    pub color: PlayerColor,
 1194}
 1195
 1196#[derive(Clone, Debug)]
 1197struct SelectionHistoryEntry {
 1198    selections: Arc<[Selection<Anchor>]>,
 1199    select_next_state: Option<SelectNextState>,
 1200    select_prev_state: Option<SelectNextState>,
 1201    add_selections_state: Option<AddSelectionsState>,
 1202}
 1203
 1204#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1205enum SelectionHistoryMode {
 1206    Normal,
 1207    Undoing,
 1208    Redoing,
 1209    Skipping,
 1210}
 1211
 1212#[derive(Clone, PartialEq, Eq, Hash)]
 1213struct HoveredCursor {
 1214    replica_id: u16,
 1215    selection_id: usize,
 1216}
 1217
 1218impl Default for SelectionHistoryMode {
 1219    fn default() -> Self {
 1220        Self::Normal
 1221    }
 1222}
 1223
 1224struct DeferredSelectionEffectsState {
 1225    changed: bool,
 1226    should_update_completions: bool,
 1227    autoscroll: Option<Autoscroll>,
 1228    old_cursor_position: Anchor,
 1229    history_entry: SelectionHistoryEntry,
 1230}
 1231
 1232#[derive(Default)]
 1233struct SelectionHistory {
 1234    #[allow(clippy::type_complexity)]
 1235    selections_by_transaction:
 1236        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1237    mode: SelectionHistoryMode,
 1238    undo_stack: VecDeque<SelectionHistoryEntry>,
 1239    redo_stack: VecDeque<SelectionHistoryEntry>,
 1240}
 1241
 1242impl SelectionHistory {
 1243    #[track_caller]
 1244    fn insert_transaction(
 1245        &mut self,
 1246        transaction_id: TransactionId,
 1247        selections: Arc<[Selection<Anchor>]>,
 1248    ) {
 1249        if selections.is_empty() {
 1250            log::error!(
 1251                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1252                std::panic::Location::caller()
 1253            );
 1254            return;
 1255        }
 1256        self.selections_by_transaction
 1257            .insert(transaction_id, (selections, None));
 1258    }
 1259
 1260    #[allow(clippy::type_complexity)]
 1261    fn transaction(
 1262        &self,
 1263        transaction_id: TransactionId,
 1264    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1265        self.selections_by_transaction.get(&transaction_id)
 1266    }
 1267
 1268    #[allow(clippy::type_complexity)]
 1269    fn transaction_mut(
 1270        &mut self,
 1271        transaction_id: TransactionId,
 1272    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1273        self.selections_by_transaction.get_mut(&transaction_id)
 1274    }
 1275
 1276    fn push(&mut self, entry: SelectionHistoryEntry) {
 1277        if !entry.selections.is_empty() {
 1278            match self.mode {
 1279                SelectionHistoryMode::Normal => {
 1280                    self.push_undo(entry);
 1281                    self.redo_stack.clear();
 1282                }
 1283                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1284                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1285                SelectionHistoryMode::Skipping => {}
 1286            }
 1287        }
 1288    }
 1289
 1290    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1291        if self
 1292            .undo_stack
 1293            .back()
 1294            .map_or(true, |e| e.selections != entry.selections)
 1295        {
 1296            self.undo_stack.push_back(entry);
 1297            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1298                self.undo_stack.pop_front();
 1299            }
 1300        }
 1301    }
 1302
 1303    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1304        if self
 1305            .redo_stack
 1306            .back()
 1307            .map_or(true, |e| e.selections != entry.selections)
 1308        {
 1309            self.redo_stack.push_back(entry);
 1310            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1311                self.redo_stack.pop_front();
 1312            }
 1313        }
 1314    }
 1315}
 1316
 1317#[derive(Clone, Copy)]
 1318pub struct RowHighlightOptions {
 1319    pub autoscroll: bool,
 1320    pub include_gutter: bool,
 1321}
 1322
 1323impl Default for RowHighlightOptions {
 1324    fn default() -> Self {
 1325        Self {
 1326            autoscroll: Default::default(),
 1327            include_gutter: true,
 1328        }
 1329    }
 1330}
 1331
 1332struct RowHighlight {
 1333    index: usize,
 1334    range: Range<Anchor>,
 1335    color: Hsla,
 1336    options: RowHighlightOptions,
 1337    type_id: TypeId,
 1338}
 1339
 1340#[derive(Clone, Debug)]
 1341struct AddSelectionsState {
 1342    groups: Vec<AddSelectionsGroup>,
 1343}
 1344
 1345#[derive(Clone, Debug)]
 1346struct AddSelectionsGroup {
 1347    above: bool,
 1348    stack: Vec<usize>,
 1349}
 1350
 1351#[derive(Clone)]
 1352struct SelectNextState {
 1353    query: AhoCorasick,
 1354    wordwise: bool,
 1355    done: bool,
 1356}
 1357
 1358impl std::fmt::Debug for SelectNextState {
 1359    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1360        f.debug_struct(std::any::type_name::<Self>())
 1361            .field("wordwise", &self.wordwise)
 1362            .field("done", &self.done)
 1363            .finish()
 1364    }
 1365}
 1366
 1367#[derive(Debug)]
 1368struct AutocloseRegion {
 1369    selection_id: usize,
 1370    range: Range<Anchor>,
 1371    pair: BracketPair,
 1372}
 1373
 1374#[derive(Debug)]
 1375struct SnippetState {
 1376    ranges: Vec<Vec<Range<Anchor>>>,
 1377    active_index: usize,
 1378    choices: Vec<Option<Vec<String>>>,
 1379}
 1380
 1381#[doc(hidden)]
 1382pub struct RenameState {
 1383    pub range: Range<Anchor>,
 1384    pub old_name: Arc<str>,
 1385    pub editor: Entity<Editor>,
 1386    block_id: CustomBlockId,
 1387}
 1388
 1389struct InvalidationStack<T>(Vec<T>);
 1390
 1391struct RegisteredInlineCompletionProvider {
 1392    provider: Arc<dyn InlineCompletionProviderHandle>,
 1393    _subscription: Subscription,
 1394}
 1395
 1396#[derive(Debug, PartialEq, Eq)]
 1397pub struct ActiveDiagnosticGroup {
 1398    pub active_range: Range<Anchor>,
 1399    pub active_message: String,
 1400    pub group_id: usize,
 1401    pub blocks: HashSet<CustomBlockId>,
 1402}
 1403
 1404#[derive(Debug, PartialEq, Eq)]
 1405
 1406pub(crate) enum ActiveDiagnostic {
 1407    None,
 1408    All,
 1409    Group(ActiveDiagnosticGroup),
 1410}
 1411
 1412#[derive(Serialize, Deserialize, Clone, Debug)]
 1413pub struct ClipboardSelection {
 1414    /// The number of bytes in this selection.
 1415    pub len: usize,
 1416    /// Whether this was a full-line selection.
 1417    pub is_entire_line: bool,
 1418    /// The indentation of the first line when this content was originally copied.
 1419    pub first_line_indent: u32,
 1420}
 1421
 1422// selections, scroll behavior, was newest selection reversed
 1423type SelectSyntaxNodeHistoryState = (
 1424    Box<[Selection<usize>]>,
 1425    SelectSyntaxNodeScrollBehavior,
 1426    bool,
 1427);
 1428
 1429#[derive(Default)]
 1430struct SelectSyntaxNodeHistory {
 1431    stack: Vec<SelectSyntaxNodeHistoryState>,
 1432    // disable temporarily to allow changing selections without losing the stack
 1433    pub disable_clearing: bool,
 1434}
 1435
 1436impl SelectSyntaxNodeHistory {
 1437    pub fn try_clear(&mut self) {
 1438        if !self.disable_clearing {
 1439            self.stack.clear();
 1440        }
 1441    }
 1442
 1443    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1444        self.stack.push(selection);
 1445    }
 1446
 1447    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1448        self.stack.pop()
 1449    }
 1450}
 1451
 1452enum SelectSyntaxNodeScrollBehavior {
 1453    CursorTop,
 1454    FitSelection,
 1455    CursorBottom,
 1456}
 1457
 1458#[derive(Debug)]
 1459pub(crate) struct NavigationData {
 1460    cursor_anchor: Anchor,
 1461    cursor_position: Point,
 1462    scroll_anchor: ScrollAnchor,
 1463    scroll_top_row: u32,
 1464}
 1465
 1466#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1467pub enum GotoDefinitionKind {
 1468    Symbol,
 1469    Declaration,
 1470    Type,
 1471    Implementation,
 1472}
 1473
 1474#[derive(Debug, Clone)]
 1475enum InlayHintRefreshReason {
 1476    ModifiersChanged(bool),
 1477    Toggle(bool),
 1478    SettingsChange(InlayHintSettings),
 1479    NewLinesShown,
 1480    BufferEdited(HashSet<Arc<Language>>),
 1481    RefreshRequested,
 1482    ExcerptsRemoved(Vec<ExcerptId>),
 1483}
 1484
 1485impl InlayHintRefreshReason {
 1486    fn description(&self) -> &'static str {
 1487        match self {
 1488            Self::ModifiersChanged(_) => "modifiers changed",
 1489            Self::Toggle(_) => "toggle",
 1490            Self::SettingsChange(_) => "settings change",
 1491            Self::NewLinesShown => "new lines shown",
 1492            Self::BufferEdited(_) => "buffer edited",
 1493            Self::RefreshRequested => "refresh requested",
 1494            Self::ExcerptsRemoved(_) => "excerpts removed",
 1495        }
 1496    }
 1497}
 1498
 1499pub enum FormatTarget {
 1500    Buffers,
 1501    Ranges(Vec<Range<MultiBufferPoint>>),
 1502}
 1503
 1504pub(crate) struct FocusedBlock {
 1505    id: BlockId,
 1506    focus_handle: WeakFocusHandle,
 1507}
 1508
 1509#[derive(Clone)]
 1510enum JumpData {
 1511    MultiBufferRow {
 1512        row: MultiBufferRow,
 1513        line_offset_from_top: u32,
 1514    },
 1515    MultiBufferPoint {
 1516        excerpt_id: ExcerptId,
 1517        position: Point,
 1518        anchor: text::Anchor,
 1519        line_offset_from_top: u32,
 1520    },
 1521}
 1522
 1523pub enum MultibufferSelectionMode {
 1524    First,
 1525    All,
 1526}
 1527
 1528#[derive(Clone, Copy, Debug, Default)]
 1529pub struct RewrapOptions {
 1530    pub override_language_settings: bool,
 1531    pub preserve_existing_whitespace: bool,
 1532}
 1533
 1534impl Editor {
 1535    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1536        let buffer = cx.new(|cx| Buffer::local("", cx));
 1537        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1538        Self::new(
 1539            EditorMode::SingleLine { auto_width: false },
 1540            buffer,
 1541            None,
 1542            window,
 1543            cx,
 1544        )
 1545    }
 1546
 1547    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1548        let buffer = cx.new(|cx| Buffer::local("", cx));
 1549        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1550        Self::new(EditorMode::full(), buffer, None, window, cx)
 1551    }
 1552
 1553    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1554        let buffer = cx.new(|cx| Buffer::local("", cx));
 1555        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1556        Self::new(
 1557            EditorMode::SingleLine { auto_width: true },
 1558            buffer,
 1559            None,
 1560            window,
 1561            cx,
 1562        )
 1563    }
 1564
 1565    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1566        let buffer = cx.new(|cx| Buffer::local("", cx));
 1567        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1568        Self::new(
 1569            EditorMode::AutoHeight { max_lines },
 1570            buffer,
 1571            None,
 1572            window,
 1573            cx,
 1574        )
 1575    }
 1576
 1577    pub fn for_buffer(
 1578        buffer: Entity<Buffer>,
 1579        project: Option<Entity<Project>>,
 1580        window: &mut Window,
 1581        cx: &mut Context<Self>,
 1582    ) -> Self {
 1583        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1584        Self::new(EditorMode::full(), buffer, project, window, cx)
 1585    }
 1586
 1587    pub fn for_multibuffer(
 1588        buffer: Entity<MultiBuffer>,
 1589        project: Option<Entity<Project>>,
 1590        window: &mut Window,
 1591        cx: &mut Context<Self>,
 1592    ) -> Self {
 1593        Self::new(EditorMode::full(), buffer, project, window, cx)
 1594    }
 1595
 1596    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1597        let mut clone = Self::new(
 1598            self.mode.clone(),
 1599            self.buffer.clone(),
 1600            self.project.clone(),
 1601            window,
 1602            cx,
 1603        );
 1604        self.display_map.update(cx, |display_map, cx| {
 1605            let snapshot = display_map.snapshot(cx);
 1606            clone.display_map.update(cx, |display_map, cx| {
 1607                display_map.set_state(&snapshot, cx);
 1608            });
 1609        });
 1610        clone.folds_did_change(cx);
 1611        clone.selections.clone_state(&self.selections);
 1612        clone.scroll_manager.clone_state(&self.scroll_manager);
 1613        clone.searchable = self.searchable;
 1614        clone.read_only = self.read_only;
 1615        clone
 1616    }
 1617
 1618    pub fn new(
 1619        mode: EditorMode,
 1620        buffer: Entity<MultiBuffer>,
 1621        project: Option<Entity<Project>>,
 1622        window: &mut Window,
 1623        cx: &mut Context<Self>,
 1624    ) -> Self {
 1625        Editor::new_internal(mode, buffer, project, None, window, cx)
 1626    }
 1627
 1628    fn new_internal(
 1629        mode: EditorMode,
 1630        buffer: Entity<MultiBuffer>,
 1631        project: Option<Entity<Project>>,
 1632        display_map: Option<Entity<DisplayMap>>,
 1633        window: &mut Window,
 1634        cx: &mut Context<Self>,
 1635    ) -> Self {
 1636        debug_assert!(
 1637            display_map.is_none() || mode.is_minimap(),
 1638            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1639        );
 1640
 1641        let full_mode = mode.is_full();
 1642        let diagnostics_max_severity = if full_mode {
 1643            EditorSettings::get_global(cx)
 1644                .diagnostics_max_severity
 1645                .unwrap_or(DiagnosticSeverity::Hint)
 1646        } else {
 1647            DiagnosticSeverity::Off
 1648        };
 1649        let style = window.text_style();
 1650        let font_size = style.font_size.to_pixels(window.rem_size());
 1651        let editor = cx.entity().downgrade();
 1652        let fold_placeholder = FoldPlaceholder {
 1653            constrain_width: true,
 1654            render: Arc::new(move |fold_id, fold_range, cx| {
 1655                let editor = editor.clone();
 1656                div()
 1657                    .id(fold_id)
 1658                    .bg(cx.theme().colors().ghost_element_background)
 1659                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1660                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1661                    .rounded_xs()
 1662                    .size_full()
 1663                    .cursor_pointer()
 1664                    .child("")
 1665                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1666                    .on_click(move |_, _window, cx| {
 1667                        editor
 1668                            .update(cx, |editor, cx| {
 1669                                editor.unfold_ranges(
 1670                                    &[fold_range.start..fold_range.end],
 1671                                    true,
 1672                                    false,
 1673                                    cx,
 1674                                );
 1675                                cx.stop_propagation();
 1676                            })
 1677                            .ok();
 1678                    })
 1679                    .into_any()
 1680            }),
 1681            merge_adjacent: true,
 1682            ..FoldPlaceholder::default()
 1683        };
 1684        let display_map = display_map.unwrap_or_else(|| {
 1685            cx.new(|cx| {
 1686                DisplayMap::new(
 1687                    buffer.clone(),
 1688                    style.font(),
 1689                    font_size,
 1690                    None,
 1691                    FILE_HEADER_HEIGHT,
 1692                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1693                    fold_placeholder,
 1694                    diagnostics_max_severity,
 1695                    cx,
 1696                )
 1697            })
 1698        });
 1699
 1700        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1701
 1702        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1703
 1704        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1705            .then(|| language_settings::SoftWrap::None);
 1706
 1707        let mut project_subscriptions = Vec::new();
 1708        if mode.is_full() {
 1709            if let Some(project) = project.as_ref() {
 1710                project_subscriptions.push(cx.subscribe_in(
 1711                    project,
 1712                    window,
 1713                    |editor, _, event, window, cx| match event {
 1714                        project::Event::RefreshCodeLens => {
 1715                            // we always query lens with actions, without storing them, always refreshing them
 1716                        }
 1717                        project::Event::RefreshInlayHints => {
 1718                            editor
 1719                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1720                        }
 1721                        project::Event::LanguageServerAdded(..)
 1722                        | project::Event::LanguageServerRemoved(..) => {
 1723                            if editor.tasks_update_task.is_none() {
 1724                                editor.tasks_update_task =
 1725                                    Some(editor.refresh_runnables(window, cx));
 1726                            }
 1727                            editor.pull_diagnostics(None, window, cx);
 1728                        }
 1729                        project::Event::SnippetEdit(id, snippet_edits) => {
 1730                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1731                                let focus_handle = editor.focus_handle(cx);
 1732                                if focus_handle.is_focused(window) {
 1733                                    let snapshot = buffer.read(cx).snapshot();
 1734                                    for (range, snippet) in snippet_edits {
 1735                                        let editor_range =
 1736                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1737                                        editor
 1738                                            .insert_snippet(
 1739                                                &[editor_range],
 1740                                                snippet.clone(),
 1741                                                window,
 1742                                                cx,
 1743                                            )
 1744                                            .ok();
 1745                                    }
 1746                                }
 1747                            }
 1748                        }
 1749                        _ => {}
 1750                    },
 1751                ));
 1752                if let Some(task_inventory) = project
 1753                    .read(cx)
 1754                    .task_store()
 1755                    .read(cx)
 1756                    .task_inventory()
 1757                    .cloned()
 1758                {
 1759                    project_subscriptions.push(cx.observe_in(
 1760                        &task_inventory,
 1761                        window,
 1762                        |editor, _, window, cx| {
 1763                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1764                        },
 1765                    ));
 1766                };
 1767
 1768                project_subscriptions.push(cx.subscribe_in(
 1769                    &project.read(cx).breakpoint_store(),
 1770                    window,
 1771                    |editor, _, event, window, cx| match event {
 1772                        BreakpointStoreEvent::ClearDebugLines => {
 1773                            editor.clear_row_highlights::<ActiveDebugLine>();
 1774                            editor.refresh_inline_values(cx);
 1775                        }
 1776                        BreakpointStoreEvent::SetDebugLine => {
 1777                            if editor.go_to_active_debug_line(window, cx) {
 1778                                cx.stop_propagation();
 1779                            }
 1780
 1781                            editor.refresh_inline_values(cx);
 1782                        }
 1783                        _ => {}
 1784                    },
 1785                ));
 1786            }
 1787        }
 1788
 1789        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1790
 1791        let inlay_hint_settings =
 1792            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1793        let focus_handle = cx.focus_handle();
 1794        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1795            .detach();
 1796        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1797            .detach();
 1798        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1799            .detach();
 1800        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1801            .detach();
 1802        cx.observe_pending_input(window, Self::observe_pending_input)
 1803            .detach();
 1804
 1805        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1806            Some(false)
 1807        } else {
 1808            None
 1809        };
 1810
 1811        let breakpoint_store = match (&mode, project.as_ref()) {
 1812            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1813            _ => None,
 1814        };
 1815
 1816        let mut code_action_providers = Vec::new();
 1817        let mut load_uncommitted_diff = None;
 1818        if let Some(project) = project.clone() {
 1819            load_uncommitted_diff = Some(
 1820                update_uncommitted_diff_for_buffer(
 1821                    cx.entity(),
 1822                    &project,
 1823                    buffer.read(cx).all_buffers(),
 1824                    buffer.clone(),
 1825                    cx,
 1826                )
 1827                .shared(),
 1828            );
 1829            code_action_providers.push(Rc::new(project) as Rc<_>);
 1830        }
 1831
 1832        let mut editor = Self {
 1833            focus_handle,
 1834            show_cursor_when_unfocused: false,
 1835            last_focused_descendant: None,
 1836            buffer: buffer.clone(),
 1837            display_map: display_map.clone(),
 1838            selections,
 1839            scroll_manager: ScrollManager::new(cx),
 1840            columnar_selection_tail: None,
 1841            columnar_display_point: None,
 1842            add_selections_state: None,
 1843            select_next_state: None,
 1844            select_prev_state: None,
 1845            selection_history: SelectionHistory::default(),
 1846            defer_selection_effects: false,
 1847            deferred_selection_effects_state: None,
 1848            autoclose_regions: Vec::new(),
 1849            snippet_stack: InvalidationStack::default(),
 1850            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1851            ime_transaction: None,
 1852            active_diagnostics: ActiveDiagnostic::None,
 1853            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1854            inline_diagnostics_update: Task::ready(()),
 1855            inline_diagnostics: Vec::new(),
 1856            soft_wrap_mode_override,
 1857            diagnostics_max_severity,
 1858            hard_wrap: None,
 1859            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1860            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1861            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1862            project,
 1863            blink_manager: blink_manager.clone(),
 1864            show_local_selections: true,
 1865            show_scrollbars: ScrollbarAxes {
 1866                horizontal: full_mode,
 1867                vertical: full_mode,
 1868            },
 1869            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1870            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1871            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1872            show_gutter: mode.is_full(),
 1873            show_line_numbers: None,
 1874            use_relative_line_numbers: None,
 1875            disable_expand_excerpt_buttons: false,
 1876            show_git_diff_gutter: None,
 1877            show_code_actions: None,
 1878            show_runnables: None,
 1879            show_breakpoints: None,
 1880            show_wrap_guides: None,
 1881            show_indent_guides,
 1882            placeholder_text: None,
 1883            highlight_order: 0,
 1884            highlighted_rows: HashMap::default(),
 1885            background_highlights: TreeMap::default(),
 1886            gutter_highlights: TreeMap::default(),
 1887            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1888            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1889            nav_history: None,
 1890            context_menu: RefCell::new(None),
 1891            context_menu_options: None,
 1892            mouse_context_menu: None,
 1893            completion_tasks: Vec::new(),
 1894            inline_blame_popover: None,
 1895            signature_help_state: SignatureHelpState::default(),
 1896            auto_signature_help: None,
 1897            find_all_references_task_sources: Vec::new(),
 1898            next_completion_id: 0,
 1899            next_inlay_id: 0,
 1900            code_action_providers,
 1901            available_code_actions: None,
 1902            code_actions_task: None,
 1903            quick_selection_highlight_task: None,
 1904            debounced_selection_highlight_task: None,
 1905            document_highlights_task: None,
 1906            linked_editing_range_task: None,
 1907            pending_rename: None,
 1908            searchable: true,
 1909            cursor_shape: EditorSettings::get_global(cx)
 1910                .cursor_shape
 1911                .unwrap_or_default(),
 1912            current_line_highlight: None,
 1913            autoindent_mode: Some(AutoindentMode::EachLine),
 1914            collapse_matches: false,
 1915            workspace: None,
 1916            input_enabled: true,
 1917            use_modal_editing: mode.is_full(),
 1918            read_only: mode.is_minimap(),
 1919            use_autoclose: true,
 1920            use_auto_surround: true,
 1921            auto_replace_emoji_shortcode: false,
 1922            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1923            leader_id: None,
 1924            remote_id: None,
 1925            hover_state: HoverState::default(),
 1926            pending_mouse_down: None,
 1927            hovered_link_state: None,
 1928            edit_prediction_provider: None,
 1929            active_inline_completion: None,
 1930            stale_inline_completion_in_menu: None,
 1931            edit_prediction_preview: EditPredictionPreview::Inactive {
 1932                released_too_fast: false,
 1933            },
 1934            inline_diagnostics_enabled: mode.is_full(),
 1935            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1936            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1937
 1938            gutter_hovered: false,
 1939            pixel_position_of_newest_cursor: None,
 1940            last_bounds: None,
 1941            last_position_map: None,
 1942            expect_bounds_change: None,
 1943            gutter_dimensions: GutterDimensions::default(),
 1944            style: None,
 1945            show_cursor_names: false,
 1946            hovered_cursors: HashMap::default(),
 1947            next_editor_action_id: EditorActionId::default(),
 1948            editor_actions: Rc::default(),
 1949            inline_completions_hidden_for_vim_mode: false,
 1950            show_inline_completions_override: None,
 1951            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1952            edit_prediction_settings: EditPredictionSettings::Disabled,
 1953            edit_prediction_indent_conflict: false,
 1954            edit_prediction_requires_modifier_in_indent_conflict: true,
 1955            custom_context_menu: None,
 1956            show_git_blame_gutter: false,
 1957            show_git_blame_inline: false,
 1958            show_selection_menu: None,
 1959            show_git_blame_inline_delay_task: None,
 1960            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1961            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1962            serialize_dirty_buffers: !mode.is_minimap()
 1963                && ProjectSettings::get_global(cx)
 1964                    .session
 1965                    .restore_unsaved_buffers,
 1966            blame: None,
 1967            blame_subscription: None,
 1968            tasks: BTreeMap::default(),
 1969
 1970            breakpoint_store,
 1971            gutter_breakpoint_indicator: (None, None),
 1972            _subscriptions: vec![
 1973                cx.observe(&buffer, Self::on_buffer_changed),
 1974                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1975                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1976                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1977                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1978                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1979                cx.observe_window_activation(window, |editor, window, cx| {
 1980                    let active = window.is_window_active();
 1981                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1982                        if active {
 1983                            blink_manager.enable(cx);
 1984                        } else {
 1985                            blink_manager.disable(cx);
 1986                        }
 1987                    });
 1988                    if active {
 1989                        editor.show_mouse_cursor();
 1990                    }
 1991                }),
 1992            ],
 1993            tasks_update_task: None,
 1994            pull_diagnostics_task: Task::ready(()),
 1995            linked_edit_ranges: Default::default(),
 1996            in_project_search: false,
 1997            previous_search_ranges: None,
 1998            breadcrumb_header: None,
 1999            focused_block: None,
 2000            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2001            addons: HashMap::default(),
 2002            registered_buffers: HashMap::default(),
 2003            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2004            selection_mark_mode: false,
 2005            toggle_fold_multiple_buffers: Task::ready(()),
 2006            serialize_selections: Task::ready(()),
 2007            serialize_folds: Task::ready(()),
 2008            text_style_refinement: None,
 2009            load_diff_task: load_uncommitted_diff,
 2010            temporary_diff_override: false,
 2011            mouse_cursor_hidden: false,
 2012            minimap: None,
 2013            hide_mouse_mode: EditorSettings::get_global(cx)
 2014                .hide_mouse
 2015                .unwrap_or_default(),
 2016            change_list: ChangeList::new(),
 2017            mode,
 2018            selection_drag_state: SelectionDragState::None,
 2019            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2020        };
 2021        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2022            editor
 2023                ._subscriptions
 2024                .push(cx.observe(breakpoints, |_, _, cx| {
 2025                    cx.notify();
 2026                }));
 2027        }
 2028        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2029        editor._subscriptions.extend(project_subscriptions);
 2030
 2031        editor._subscriptions.push(cx.subscribe_in(
 2032            &cx.entity(),
 2033            window,
 2034            |editor, _, e: &EditorEvent, window, cx| match e {
 2035                EditorEvent::ScrollPositionChanged { local, .. } => {
 2036                    if *local {
 2037                        let new_anchor = editor.scroll_manager.anchor();
 2038                        let snapshot = editor.snapshot(window, cx);
 2039                        editor.update_restoration_data(cx, move |data| {
 2040                            data.scroll_position = (
 2041                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2042                                new_anchor.offset,
 2043                            );
 2044                        });
 2045                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2046                        editor.inline_blame_popover.take();
 2047                    }
 2048                }
 2049                EditorEvent::Edited { .. } => {
 2050                    if !vim_enabled(cx) {
 2051                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2052                        let pop_state = editor
 2053                            .change_list
 2054                            .last()
 2055                            .map(|previous| {
 2056                                previous.len() == selections.len()
 2057                                    && previous.iter().enumerate().all(|(ix, p)| {
 2058                                        p.to_display_point(&map).row()
 2059                                            == selections[ix].head().row()
 2060                                    })
 2061                            })
 2062                            .unwrap_or(false);
 2063                        let new_positions = selections
 2064                            .into_iter()
 2065                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2066                            .collect();
 2067                        editor
 2068                            .change_list
 2069                            .push_to_change_list(pop_state, new_positions);
 2070                    }
 2071                }
 2072                _ => (),
 2073            },
 2074        ));
 2075
 2076        if let Some(dap_store) = editor
 2077            .project
 2078            .as_ref()
 2079            .map(|project| project.read(cx).dap_store())
 2080        {
 2081            let weak_editor = cx.weak_entity();
 2082
 2083            editor
 2084                ._subscriptions
 2085                .push(
 2086                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2087                        let session_entity = cx.entity();
 2088                        weak_editor
 2089                            .update(cx, |editor, cx| {
 2090                                editor._subscriptions.push(
 2091                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2092                                );
 2093                            })
 2094                            .ok();
 2095                    }),
 2096                );
 2097
 2098            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2099                editor
 2100                    ._subscriptions
 2101                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2102            }
 2103        }
 2104
 2105        // skip adding the initial selection to selection history
 2106        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2107        editor.end_selection(window, cx);
 2108        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2109
 2110        editor.scroll_manager.show_scrollbars(window, cx);
 2111        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2112
 2113        if full_mode {
 2114            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2115            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2116
 2117            if editor.git_blame_inline_enabled {
 2118                editor.start_git_blame_inline(false, window, cx);
 2119            }
 2120
 2121            editor.go_to_active_debug_line(window, cx);
 2122
 2123            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2124                if let Some(project) = editor.project.as_ref() {
 2125                    let handle = project.update(cx, |project, cx| {
 2126                        project.register_buffer_with_language_servers(&buffer, cx)
 2127                    });
 2128                    editor
 2129                        .registered_buffers
 2130                        .insert(buffer.read(cx).remote_id(), handle);
 2131                }
 2132            }
 2133
 2134            editor.minimap =
 2135                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2136            editor.pull_diagnostics(None, window, cx);
 2137        }
 2138
 2139        editor.report_editor_event("Editor Opened", None, cx);
 2140        editor
 2141    }
 2142
 2143    pub fn deploy_mouse_context_menu(
 2144        &mut self,
 2145        position: gpui::Point<Pixels>,
 2146        context_menu: Entity<ContextMenu>,
 2147        window: &mut Window,
 2148        cx: &mut Context<Self>,
 2149    ) {
 2150        self.mouse_context_menu = Some(MouseContextMenu::new(
 2151            self,
 2152            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2153            context_menu,
 2154            window,
 2155            cx,
 2156        ));
 2157    }
 2158
 2159    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2160        self.mouse_context_menu
 2161            .as_ref()
 2162            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2163    }
 2164
 2165    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2166        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2167    }
 2168
 2169    fn key_context_internal(
 2170        &self,
 2171        has_active_edit_prediction: bool,
 2172        window: &Window,
 2173        cx: &App,
 2174    ) -> KeyContext {
 2175        let mut key_context = KeyContext::new_with_defaults();
 2176        key_context.add("Editor");
 2177        let mode = match self.mode {
 2178            EditorMode::SingleLine { .. } => "single_line",
 2179            EditorMode::AutoHeight { .. } => "auto_height",
 2180            EditorMode::Minimap { .. } => "minimap",
 2181            EditorMode::Full { .. } => "full",
 2182        };
 2183
 2184        if EditorSettings::jupyter_enabled(cx) {
 2185            key_context.add("jupyter");
 2186        }
 2187
 2188        key_context.set("mode", mode);
 2189        if self.pending_rename.is_some() {
 2190            key_context.add("renaming");
 2191        }
 2192
 2193        match self.context_menu.borrow().as_ref() {
 2194            Some(CodeContextMenu::Completions(_)) => {
 2195                key_context.add("menu");
 2196                key_context.add("showing_completions");
 2197            }
 2198            Some(CodeContextMenu::CodeActions(_)) => {
 2199                key_context.add("menu");
 2200                key_context.add("showing_code_actions")
 2201            }
 2202            None => {}
 2203        }
 2204
 2205        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2206        if !self.focus_handle(cx).contains_focused(window, cx)
 2207            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2208        {
 2209            for addon in self.addons.values() {
 2210                addon.extend_key_context(&mut key_context, cx)
 2211            }
 2212        }
 2213
 2214        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2215            if let Some(extension) = singleton_buffer
 2216                .read(cx)
 2217                .file()
 2218                .and_then(|file| file.path().extension()?.to_str())
 2219            {
 2220                key_context.set("extension", extension.to_string());
 2221            }
 2222        } else {
 2223            key_context.add("multibuffer");
 2224        }
 2225
 2226        if has_active_edit_prediction {
 2227            if self.edit_prediction_in_conflict() {
 2228                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2229            } else {
 2230                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2231                key_context.add("copilot_suggestion");
 2232            }
 2233        }
 2234
 2235        if self.selection_mark_mode {
 2236            key_context.add("selection_mode");
 2237        }
 2238
 2239        key_context
 2240    }
 2241
 2242    fn show_mouse_cursor(&mut self) {
 2243        self.mouse_cursor_hidden = false;
 2244    }
 2245
 2246    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2247        self.mouse_cursor_hidden = match origin {
 2248            HideMouseCursorOrigin::TypingAction => {
 2249                matches!(
 2250                    self.hide_mouse_mode,
 2251                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2252                )
 2253            }
 2254            HideMouseCursorOrigin::MovementAction => {
 2255                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2256            }
 2257        };
 2258    }
 2259
 2260    pub fn edit_prediction_in_conflict(&self) -> bool {
 2261        if !self.show_edit_predictions_in_menu() {
 2262            return false;
 2263        }
 2264
 2265        let showing_completions = self
 2266            .context_menu
 2267            .borrow()
 2268            .as_ref()
 2269            .map_or(false, |context| {
 2270                matches!(context, CodeContextMenu::Completions(_))
 2271            });
 2272
 2273        showing_completions
 2274            || self.edit_prediction_requires_modifier()
 2275            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2276            // bindings to insert tab characters.
 2277            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2278    }
 2279
 2280    pub fn accept_edit_prediction_keybind(
 2281        &self,
 2282        accept_partial: bool,
 2283        window: &Window,
 2284        cx: &App,
 2285    ) -> AcceptEditPredictionBinding {
 2286        let key_context = self.key_context_internal(true, window, cx);
 2287        let in_conflict = self.edit_prediction_in_conflict();
 2288
 2289        let bindings = if accept_partial {
 2290            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2291        } else {
 2292            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2293        };
 2294
 2295        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2296        // just the first one.
 2297        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2298            !in_conflict
 2299                || binding
 2300                    .keystrokes()
 2301                    .first()
 2302                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2303        }))
 2304    }
 2305
 2306    pub fn new_file(
 2307        workspace: &mut Workspace,
 2308        _: &workspace::NewFile,
 2309        window: &mut Window,
 2310        cx: &mut Context<Workspace>,
 2311    ) {
 2312        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2313            "Failed to create buffer",
 2314            window,
 2315            cx,
 2316            |e, _, _| match e.error_code() {
 2317                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2318                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2319                e.error_tag("required").unwrap_or("the latest version")
 2320            )),
 2321                _ => None,
 2322            },
 2323        );
 2324    }
 2325
 2326    pub fn new_in_workspace(
 2327        workspace: &mut Workspace,
 2328        window: &mut Window,
 2329        cx: &mut Context<Workspace>,
 2330    ) -> Task<Result<Entity<Editor>>> {
 2331        let project = workspace.project().clone();
 2332        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2333
 2334        cx.spawn_in(window, async move |workspace, cx| {
 2335            let buffer = create.await?;
 2336            workspace.update_in(cx, |workspace, window, cx| {
 2337                let editor =
 2338                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2339                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2340                editor
 2341            })
 2342        })
 2343    }
 2344
 2345    fn new_file_vertical(
 2346        workspace: &mut Workspace,
 2347        _: &workspace::NewFileSplitVertical,
 2348        window: &mut Window,
 2349        cx: &mut Context<Workspace>,
 2350    ) {
 2351        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2352    }
 2353
 2354    fn new_file_horizontal(
 2355        workspace: &mut Workspace,
 2356        _: &workspace::NewFileSplitHorizontal,
 2357        window: &mut Window,
 2358        cx: &mut Context<Workspace>,
 2359    ) {
 2360        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2361    }
 2362
 2363    fn new_file_in_direction(
 2364        workspace: &mut Workspace,
 2365        direction: SplitDirection,
 2366        window: &mut Window,
 2367        cx: &mut Context<Workspace>,
 2368    ) {
 2369        let project = workspace.project().clone();
 2370        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2371
 2372        cx.spawn_in(window, async move |workspace, cx| {
 2373            let buffer = create.await?;
 2374            workspace.update_in(cx, move |workspace, window, cx| {
 2375                workspace.split_item(
 2376                    direction,
 2377                    Box::new(
 2378                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2379                    ),
 2380                    window,
 2381                    cx,
 2382                )
 2383            })?;
 2384            anyhow::Ok(())
 2385        })
 2386        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2387            match e.error_code() {
 2388                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2389                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2390                e.error_tag("required").unwrap_or("the latest version")
 2391            )),
 2392                _ => None,
 2393            }
 2394        });
 2395    }
 2396
 2397    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2398        self.leader_id
 2399    }
 2400
 2401    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2402        &self.buffer
 2403    }
 2404
 2405    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2406        self.workspace.as_ref()?.0.upgrade()
 2407    }
 2408
 2409    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2410        self.buffer().read(cx).title(cx)
 2411    }
 2412
 2413    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2414        let git_blame_gutter_max_author_length = self
 2415            .render_git_blame_gutter(cx)
 2416            .then(|| {
 2417                if let Some(blame) = self.blame.as_ref() {
 2418                    let max_author_length =
 2419                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2420                    Some(max_author_length)
 2421                } else {
 2422                    None
 2423                }
 2424            })
 2425            .flatten();
 2426
 2427        EditorSnapshot {
 2428            mode: self.mode.clone(),
 2429            show_gutter: self.show_gutter,
 2430            show_line_numbers: self.show_line_numbers,
 2431            show_git_diff_gutter: self.show_git_diff_gutter,
 2432            show_code_actions: self.show_code_actions,
 2433            show_runnables: self.show_runnables,
 2434            show_breakpoints: self.show_breakpoints,
 2435            git_blame_gutter_max_author_length,
 2436            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2437            scroll_anchor: self.scroll_manager.anchor(),
 2438            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2439            placeholder_text: self.placeholder_text.clone(),
 2440            is_focused: self.focus_handle.is_focused(window),
 2441            current_line_highlight: self
 2442                .current_line_highlight
 2443                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2444            gutter_hovered: self.gutter_hovered,
 2445        }
 2446    }
 2447
 2448    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2449        self.buffer.read(cx).language_at(point, cx)
 2450    }
 2451
 2452    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2453        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2454    }
 2455
 2456    pub fn active_excerpt(
 2457        &self,
 2458        cx: &App,
 2459    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2460        self.buffer
 2461            .read(cx)
 2462            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2463    }
 2464
 2465    pub fn mode(&self) -> &EditorMode {
 2466        &self.mode
 2467    }
 2468
 2469    pub fn set_mode(&mut self, mode: EditorMode) {
 2470        self.mode = mode;
 2471    }
 2472
 2473    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2474        self.collaboration_hub.as_deref()
 2475    }
 2476
 2477    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2478        self.collaboration_hub = Some(hub);
 2479    }
 2480
 2481    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2482        self.in_project_search = in_project_search;
 2483    }
 2484
 2485    pub fn set_custom_context_menu(
 2486        &mut self,
 2487        f: impl 'static
 2488        + Fn(
 2489            &mut Self,
 2490            DisplayPoint,
 2491            &mut Window,
 2492            &mut Context<Self>,
 2493        ) -> Option<Entity<ui::ContextMenu>>,
 2494    ) {
 2495        self.custom_context_menu = Some(Box::new(f))
 2496    }
 2497
 2498    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2499        self.completion_provider = provider;
 2500    }
 2501
 2502    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2503        self.semantics_provider.clone()
 2504    }
 2505
 2506    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2507        self.semantics_provider = provider;
 2508    }
 2509
 2510    pub fn set_edit_prediction_provider<T>(
 2511        &mut self,
 2512        provider: Option<Entity<T>>,
 2513        window: &mut Window,
 2514        cx: &mut Context<Self>,
 2515    ) where
 2516        T: EditPredictionProvider,
 2517    {
 2518        self.edit_prediction_provider =
 2519            provider.map(|provider| RegisteredInlineCompletionProvider {
 2520                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2521                    if this.focus_handle.is_focused(window) {
 2522                        this.update_visible_inline_completion(window, cx);
 2523                    }
 2524                }),
 2525                provider: Arc::new(provider),
 2526            });
 2527        self.update_edit_prediction_settings(cx);
 2528        self.refresh_inline_completion(false, false, window, cx);
 2529    }
 2530
 2531    pub fn placeholder_text(&self) -> Option<&str> {
 2532        self.placeholder_text.as_deref()
 2533    }
 2534
 2535    pub fn set_placeholder_text(
 2536        &mut self,
 2537        placeholder_text: impl Into<Arc<str>>,
 2538        cx: &mut Context<Self>,
 2539    ) {
 2540        let placeholder_text = Some(placeholder_text.into());
 2541        if self.placeholder_text != placeholder_text {
 2542            self.placeholder_text = placeholder_text;
 2543            cx.notify();
 2544        }
 2545    }
 2546
 2547    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2548        self.cursor_shape = cursor_shape;
 2549
 2550        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2551        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2552
 2553        cx.notify();
 2554    }
 2555
 2556    pub fn set_current_line_highlight(
 2557        &mut self,
 2558        current_line_highlight: Option<CurrentLineHighlight>,
 2559    ) {
 2560        self.current_line_highlight = current_line_highlight;
 2561    }
 2562
 2563    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2564        self.collapse_matches = collapse_matches;
 2565    }
 2566
 2567    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2568        let buffers = self.buffer.read(cx).all_buffers();
 2569        let Some(project) = self.project.as_ref() else {
 2570            return;
 2571        };
 2572        project.update(cx, |project, cx| {
 2573            for buffer in buffers {
 2574                self.registered_buffers
 2575                    .entry(buffer.read(cx).remote_id())
 2576                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2577            }
 2578        })
 2579    }
 2580
 2581    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2582        if self.collapse_matches {
 2583            return range.start..range.start;
 2584        }
 2585        range.clone()
 2586    }
 2587
 2588    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2589        if self.display_map.read(cx).clip_at_line_ends != clip {
 2590            self.display_map
 2591                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2592        }
 2593    }
 2594
 2595    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2596        self.input_enabled = input_enabled;
 2597    }
 2598
 2599    pub fn set_inline_completions_hidden_for_vim_mode(
 2600        &mut self,
 2601        hidden: bool,
 2602        window: &mut Window,
 2603        cx: &mut Context<Self>,
 2604    ) {
 2605        if hidden != self.inline_completions_hidden_for_vim_mode {
 2606            self.inline_completions_hidden_for_vim_mode = hidden;
 2607            if hidden {
 2608                self.update_visible_inline_completion(window, cx);
 2609            } else {
 2610                self.refresh_inline_completion(true, false, window, cx);
 2611            }
 2612        }
 2613    }
 2614
 2615    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2616        self.menu_inline_completions_policy = value;
 2617    }
 2618
 2619    pub fn set_autoindent(&mut self, autoindent: bool) {
 2620        if autoindent {
 2621            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2622        } else {
 2623            self.autoindent_mode = None;
 2624        }
 2625    }
 2626
 2627    pub fn read_only(&self, cx: &App) -> bool {
 2628        self.read_only || self.buffer.read(cx).read_only()
 2629    }
 2630
 2631    pub fn set_read_only(&mut self, read_only: bool) {
 2632        self.read_only = read_only;
 2633    }
 2634
 2635    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2636        self.use_autoclose = autoclose;
 2637    }
 2638
 2639    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2640        self.use_auto_surround = auto_surround;
 2641    }
 2642
 2643    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2644        self.auto_replace_emoji_shortcode = auto_replace;
 2645    }
 2646
 2647    pub fn toggle_edit_predictions(
 2648        &mut self,
 2649        _: &ToggleEditPrediction,
 2650        window: &mut Window,
 2651        cx: &mut Context<Self>,
 2652    ) {
 2653        if self.show_inline_completions_override.is_some() {
 2654            self.set_show_edit_predictions(None, window, cx);
 2655        } else {
 2656            let show_edit_predictions = !self.edit_predictions_enabled();
 2657            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2658        }
 2659    }
 2660
 2661    pub fn set_show_edit_predictions(
 2662        &mut self,
 2663        show_edit_predictions: Option<bool>,
 2664        window: &mut Window,
 2665        cx: &mut Context<Self>,
 2666    ) {
 2667        self.show_inline_completions_override = show_edit_predictions;
 2668        self.update_edit_prediction_settings(cx);
 2669
 2670        if let Some(false) = show_edit_predictions {
 2671            self.discard_inline_completion(false, cx);
 2672        } else {
 2673            self.refresh_inline_completion(false, true, window, cx);
 2674        }
 2675    }
 2676
 2677    fn inline_completions_disabled_in_scope(
 2678        &self,
 2679        buffer: &Entity<Buffer>,
 2680        buffer_position: language::Anchor,
 2681        cx: &App,
 2682    ) -> bool {
 2683        let snapshot = buffer.read(cx).snapshot();
 2684        let settings = snapshot.settings_at(buffer_position, cx);
 2685
 2686        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2687            return false;
 2688        };
 2689
 2690        scope.override_name().map_or(false, |scope_name| {
 2691            settings
 2692                .edit_predictions_disabled_in
 2693                .iter()
 2694                .any(|s| s == scope_name)
 2695        })
 2696    }
 2697
 2698    pub fn set_use_modal_editing(&mut self, to: bool) {
 2699        self.use_modal_editing = to;
 2700    }
 2701
 2702    pub fn use_modal_editing(&self) -> bool {
 2703        self.use_modal_editing
 2704    }
 2705
 2706    fn selections_did_change(
 2707        &mut self,
 2708        local: bool,
 2709        old_cursor_position: &Anchor,
 2710        should_update_completions: bool,
 2711        window: &mut Window,
 2712        cx: &mut Context<Self>,
 2713    ) {
 2714        window.invalidate_character_coordinates();
 2715
 2716        // Copy selections to primary selection buffer
 2717        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2718        if local {
 2719            let selections = self.selections.all::<usize>(cx);
 2720            let buffer_handle = self.buffer.read(cx).read(cx);
 2721
 2722            let mut text = String::new();
 2723            for (index, selection) in selections.iter().enumerate() {
 2724                let text_for_selection = buffer_handle
 2725                    .text_for_range(selection.start..selection.end)
 2726                    .collect::<String>();
 2727
 2728                text.push_str(&text_for_selection);
 2729                if index != selections.len() - 1 {
 2730                    text.push('\n');
 2731                }
 2732            }
 2733
 2734            if !text.is_empty() {
 2735                cx.write_to_primary(ClipboardItem::new_string(text));
 2736            }
 2737        }
 2738
 2739        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2740            self.buffer.update(cx, |buffer, cx| {
 2741                buffer.set_active_selections(
 2742                    &self.selections.disjoint_anchors(),
 2743                    self.selections.line_mode,
 2744                    self.cursor_shape,
 2745                    cx,
 2746                )
 2747            });
 2748        }
 2749        let display_map = self
 2750            .display_map
 2751            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2752        let buffer = &display_map.buffer_snapshot;
 2753        if self.selections.count() == 1 {
 2754            self.add_selections_state = None;
 2755        }
 2756        self.select_next_state = None;
 2757        self.select_prev_state = None;
 2758        self.select_syntax_node_history.try_clear();
 2759        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2760        self.snippet_stack
 2761            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2762        self.take_rename(false, window, cx);
 2763
 2764        let newest_selection = self.selections.newest_anchor();
 2765        let new_cursor_position = newest_selection.head();
 2766        let selection_start = newest_selection.start;
 2767
 2768        self.push_to_nav_history(
 2769            *old_cursor_position,
 2770            Some(new_cursor_position.to_point(buffer)),
 2771            false,
 2772            cx,
 2773        );
 2774
 2775        if local {
 2776            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2777                if !self.registered_buffers.contains_key(&buffer_id) {
 2778                    if let Some(project) = self.project.as_ref() {
 2779                        project.update(cx, |project, cx| {
 2780                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2781                                return;
 2782                            };
 2783                            self.registered_buffers.insert(
 2784                                buffer_id,
 2785                                project.register_buffer_with_language_servers(&buffer, cx),
 2786                            );
 2787                        })
 2788                    }
 2789                }
 2790            }
 2791
 2792            let mut context_menu = self.context_menu.borrow_mut();
 2793            let completion_menu = match context_menu.as_ref() {
 2794                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2795                Some(CodeContextMenu::CodeActions(_)) => {
 2796                    *context_menu = None;
 2797                    None
 2798                }
 2799                None => None,
 2800            };
 2801            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2802            drop(context_menu);
 2803
 2804            if should_update_completions {
 2805                if let Some(completion_position) = completion_position {
 2806                    let start_offset = selection_start.to_offset(buffer);
 2807                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2808                    let continue_showing = if position_matches {
 2809                        if self.snippet_stack.is_empty() {
 2810                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2811                        } else {
 2812                            // Snippet choices can be shown even when the cursor is in whitespace.
 2813                            // Dismissing the menu when actions like backspace
 2814                            true
 2815                        }
 2816                    } else {
 2817                        false
 2818                    };
 2819
 2820                    if continue_showing {
 2821                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2822                    } else {
 2823                        self.hide_context_menu(window, cx);
 2824                    }
 2825                }
 2826            }
 2827
 2828            hide_hover(self, cx);
 2829
 2830            if old_cursor_position.to_display_point(&display_map).row()
 2831                != new_cursor_position.to_display_point(&display_map).row()
 2832            {
 2833                self.available_code_actions.take();
 2834            }
 2835            self.refresh_code_actions(window, cx);
 2836            self.refresh_document_highlights(cx);
 2837            self.refresh_selected_text_highlights(false, window, cx);
 2838            refresh_matching_bracket_highlights(self, window, cx);
 2839            self.update_visible_inline_completion(window, cx);
 2840            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2841            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2842            self.inline_blame_popover.take();
 2843            if self.git_blame_inline_enabled {
 2844                self.start_inline_blame_timer(window, cx);
 2845            }
 2846        }
 2847
 2848        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2849        cx.emit(EditorEvent::SelectionsChanged { local });
 2850
 2851        let selections = &self.selections.disjoint;
 2852        if selections.len() == 1 {
 2853            cx.emit(SearchEvent::ActiveMatchChanged)
 2854        }
 2855        if local {
 2856            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2857                let inmemory_selections = selections
 2858                    .iter()
 2859                    .map(|s| {
 2860                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2861                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2862                    })
 2863                    .collect();
 2864                self.update_restoration_data(cx, |data| {
 2865                    data.selections = inmemory_selections;
 2866                });
 2867
 2868                if WorkspaceSettings::get(None, cx).restore_on_startup
 2869                    != RestoreOnStartupBehavior::None
 2870                {
 2871                    if let Some(workspace_id) =
 2872                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2873                    {
 2874                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2875                        let selections = selections.clone();
 2876                        let background_executor = cx.background_executor().clone();
 2877                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2878                        self.serialize_selections = cx.background_spawn(async move {
 2879                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2880                    let db_selections = selections
 2881                        .iter()
 2882                        .map(|selection| {
 2883                            (
 2884                                selection.start.to_offset(&snapshot),
 2885                                selection.end.to_offset(&snapshot),
 2886                            )
 2887                        })
 2888                        .collect();
 2889
 2890                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2891                        .await
 2892                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2893                        .log_err();
 2894                });
 2895                    }
 2896                }
 2897            }
 2898        }
 2899
 2900        cx.notify();
 2901    }
 2902
 2903    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2904        use text::ToOffset as _;
 2905        use text::ToPoint as _;
 2906
 2907        if self.mode.is_minimap()
 2908            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2909        {
 2910            return;
 2911        }
 2912
 2913        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2914            return;
 2915        };
 2916
 2917        let snapshot = singleton.read(cx).snapshot();
 2918        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2919            let display_snapshot = display_map.snapshot(cx);
 2920
 2921            display_snapshot
 2922                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2923                .map(|fold| {
 2924                    fold.range.start.text_anchor.to_point(&snapshot)
 2925                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2926                })
 2927                .collect()
 2928        });
 2929        self.update_restoration_data(cx, |data| {
 2930            data.folds = inmemory_folds;
 2931        });
 2932
 2933        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2934            return;
 2935        };
 2936        let background_executor = cx.background_executor().clone();
 2937        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2938        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2939            display_map
 2940                .snapshot(cx)
 2941                .folds_in_range(0..snapshot.len())
 2942                .map(|fold| {
 2943                    (
 2944                        fold.range.start.text_anchor.to_offset(&snapshot),
 2945                        fold.range.end.text_anchor.to_offset(&snapshot),
 2946                    )
 2947                })
 2948                .collect()
 2949        });
 2950        self.serialize_folds = cx.background_spawn(async move {
 2951            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2952            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2953                .await
 2954                .with_context(|| {
 2955                    format!(
 2956                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2957                    )
 2958                })
 2959                .log_err();
 2960        });
 2961    }
 2962
 2963    pub fn sync_selections(
 2964        &mut self,
 2965        other: Entity<Editor>,
 2966        cx: &mut Context<Self>,
 2967    ) -> gpui::Subscription {
 2968        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2969        self.selections.change_with(cx, |selections| {
 2970            selections.select_anchors(other_selections);
 2971        });
 2972
 2973        let other_subscription =
 2974            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2975                EditorEvent::SelectionsChanged { local: true } => {
 2976                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2977                    if other_selections.is_empty() {
 2978                        return;
 2979                    }
 2980                    this.selections.change_with(cx, |selections| {
 2981                        selections.select_anchors(other_selections);
 2982                    });
 2983                }
 2984                _ => {}
 2985            });
 2986
 2987        let this_subscription =
 2988            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2989                EditorEvent::SelectionsChanged { local: true } => {
 2990                    let these_selections = this.selections.disjoint.to_vec();
 2991                    if these_selections.is_empty() {
 2992                        return;
 2993                    }
 2994                    other.update(cx, |other_editor, cx| {
 2995                        other_editor.selections.change_with(cx, |selections| {
 2996                            selections.select_anchors(these_selections);
 2997                        })
 2998                    });
 2999                }
 3000                _ => {}
 3001            });
 3002
 3003        Subscription::join(other_subscription, this_subscription)
 3004    }
 3005
 3006    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3007    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3008    /// effects of selection change occur at the end of the transaction.
 3009    pub fn change_selections<R>(
 3010        &mut self,
 3011        autoscroll: Option<Autoscroll>,
 3012        window: &mut Window,
 3013        cx: &mut Context<Self>,
 3014        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3015    ) -> R {
 3016        self.change_selections_inner(true, autoscroll, window, cx, change)
 3017    }
 3018
 3019    pub(crate) fn change_selections_without_updating_completions<R>(
 3020        &mut self,
 3021        autoscroll: Option<Autoscroll>,
 3022        window: &mut Window,
 3023        cx: &mut Context<Self>,
 3024        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3025    ) -> R {
 3026        self.change_selections_inner(false, autoscroll, window, cx, change)
 3027    }
 3028
 3029    fn change_selections_inner<R>(
 3030        &mut self,
 3031        should_update_completions: bool,
 3032        autoscroll: Option<Autoscroll>,
 3033        window: &mut Window,
 3034        cx: &mut Context<Self>,
 3035        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3036    ) -> R {
 3037        if let Some(state) = &mut self.deferred_selection_effects_state {
 3038            state.autoscroll = autoscroll.or(state.autoscroll);
 3039            state.should_update_completions = should_update_completions;
 3040            let (changed, result) = self.selections.change_with(cx, change);
 3041            state.changed |= changed;
 3042            return result;
 3043        }
 3044        let mut state = DeferredSelectionEffectsState {
 3045            changed: false,
 3046            should_update_completions,
 3047            autoscroll,
 3048            old_cursor_position: self.selections.newest_anchor().head(),
 3049            history_entry: SelectionHistoryEntry {
 3050                selections: self.selections.disjoint_anchors(),
 3051                select_next_state: self.select_next_state.clone(),
 3052                select_prev_state: self.select_prev_state.clone(),
 3053                add_selections_state: self.add_selections_state.clone(),
 3054            },
 3055        };
 3056        let (changed, result) = self.selections.change_with(cx, change);
 3057        state.changed = state.changed || changed;
 3058        if self.defer_selection_effects {
 3059            self.deferred_selection_effects_state = Some(state);
 3060        } else {
 3061            self.apply_selection_effects(state, window, cx);
 3062        }
 3063        result
 3064    }
 3065
 3066    /// Defers the effects of selection change, so that the effects of multiple calls to
 3067    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3068    /// to selection history and the state of popovers based on selection position aren't
 3069    /// erroneously updated.
 3070    pub fn with_selection_effects_deferred<R>(
 3071        &mut self,
 3072        window: &mut Window,
 3073        cx: &mut Context<Self>,
 3074        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3075    ) -> R {
 3076        let already_deferred = self.defer_selection_effects;
 3077        self.defer_selection_effects = true;
 3078        let result = update(self, window, cx);
 3079        if !already_deferred {
 3080            self.defer_selection_effects = false;
 3081            if let Some(state) = self.deferred_selection_effects_state.take() {
 3082                self.apply_selection_effects(state, window, cx);
 3083            }
 3084        }
 3085        result
 3086    }
 3087
 3088    fn apply_selection_effects(
 3089        &mut self,
 3090        state: DeferredSelectionEffectsState,
 3091        window: &mut Window,
 3092        cx: &mut Context<Self>,
 3093    ) {
 3094        if state.changed {
 3095            self.selection_history.push(state.history_entry);
 3096
 3097            if let Some(autoscroll) = state.autoscroll {
 3098                self.request_autoscroll(autoscroll, cx);
 3099            }
 3100
 3101            let old_cursor_position = &state.old_cursor_position;
 3102
 3103            self.selections_did_change(
 3104                true,
 3105                &old_cursor_position,
 3106                state.should_update_completions,
 3107                window,
 3108                cx,
 3109            );
 3110
 3111            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3112                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3113            }
 3114        }
 3115    }
 3116
 3117    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3118    where
 3119        I: IntoIterator<Item = (Range<S>, T)>,
 3120        S: ToOffset,
 3121        T: Into<Arc<str>>,
 3122    {
 3123        if self.read_only(cx) {
 3124            return;
 3125        }
 3126
 3127        self.buffer
 3128            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3129    }
 3130
 3131    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3132    where
 3133        I: IntoIterator<Item = (Range<S>, T)>,
 3134        S: ToOffset,
 3135        T: Into<Arc<str>>,
 3136    {
 3137        if self.read_only(cx) {
 3138            return;
 3139        }
 3140
 3141        self.buffer.update(cx, |buffer, cx| {
 3142            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3143        });
 3144    }
 3145
 3146    pub fn edit_with_block_indent<I, S, T>(
 3147        &mut self,
 3148        edits: I,
 3149        original_indent_columns: Vec<Option<u32>>,
 3150        cx: &mut Context<Self>,
 3151    ) where
 3152        I: IntoIterator<Item = (Range<S>, T)>,
 3153        S: ToOffset,
 3154        T: Into<Arc<str>>,
 3155    {
 3156        if self.read_only(cx) {
 3157            return;
 3158        }
 3159
 3160        self.buffer.update(cx, |buffer, cx| {
 3161            buffer.edit(
 3162                edits,
 3163                Some(AutoindentMode::Block {
 3164                    original_indent_columns,
 3165                }),
 3166                cx,
 3167            )
 3168        });
 3169    }
 3170
 3171    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3172        self.hide_context_menu(window, cx);
 3173
 3174        match phase {
 3175            SelectPhase::Begin {
 3176                position,
 3177                add,
 3178                click_count,
 3179            } => self.begin_selection(position, add, click_count, window, cx),
 3180            SelectPhase::BeginColumnar {
 3181                position,
 3182                goal_column,
 3183                reset,
 3184            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3185            SelectPhase::Extend {
 3186                position,
 3187                click_count,
 3188            } => self.extend_selection(position, click_count, window, cx),
 3189            SelectPhase::Update {
 3190                position,
 3191                goal_column,
 3192                scroll_delta,
 3193            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3194            SelectPhase::End => self.end_selection(window, cx),
 3195        }
 3196    }
 3197
 3198    fn extend_selection(
 3199        &mut self,
 3200        position: DisplayPoint,
 3201        click_count: usize,
 3202        window: &mut Window,
 3203        cx: &mut Context<Self>,
 3204    ) {
 3205        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3206        let tail = self.selections.newest::<usize>(cx).tail();
 3207        self.begin_selection(position, false, click_count, window, cx);
 3208
 3209        let position = position.to_offset(&display_map, Bias::Left);
 3210        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3211
 3212        let mut pending_selection = self
 3213            .selections
 3214            .pending_anchor()
 3215            .expect("extend_selection not called with pending selection");
 3216        if position >= tail {
 3217            pending_selection.start = tail_anchor;
 3218        } else {
 3219            pending_selection.end = tail_anchor;
 3220            pending_selection.reversed = true;
 3221        }
 3222
 3223        let mut pending_mode = self.selections.pending_mode().unwrap();
 3224        match &mut pending_mode {
 3225            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3226            _ => {}
 3227        }
 3228
 3229        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3230
 3231        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3232            s.set_pending(pending_selection, pending_mode)
 3233        });
 3234    }
 3235
 3236    fn begin_selection(
 3237        &mut self,
 3238        position: DisplayPoint,
 3239        add: bool,
 3240        click_count: usize,
 3241        window: &mut Window,
 3242        cx: &mut Context<Self>,
 3243    ) {
 3244        if !self.focus_handle.is_focused(window) {
 3245            self.last_focused_descendant = None;
 3246            window.focus(&self.focus_handle);
 3247        }
 3248
 3249        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3250        let buffer = &display_map.buffer_snapshot;
 3251        let position = display_map.clip_point(position, Bias::Left);
 3252
 3253        let start;
 3254        let end;
 3255        let mode;
 3256        let mut auto_scroll;
 3257        match click_count {
 3258            1 => {
 3259                start = buffer.anchor_before(position.to_point(&display_map));
 3260                end = start;
 3261                mode = SelectMode::Character;
 3262                auto_scroll = true;
 3263            }
 3264            2 => {
 3265                let range = movement::surrounding_word(&display_map, position);
 3266                start = buffer.anchor_before(range.start.to_point(&display_map));
 3267                end = buffer.anchor_before(range.end.to_point(&display_map));
 3268                mode = SelectMode::Word(start..end);
 3269                auto_scroll = true;
 3270            }
 3271            3 => {
 3272                let position = display_map
 3273                    .clip_point(position, Bias::Left)
 3274                    .to_point(&display_map);
 3275                let line_start = display_map.prev_line_boundary(position).0;
 3276                let next_line_start = buffer.clip_point(
 3277                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3278                    Bias::Left,
 3279                );
 3280                start = buffer.anchor_before(line_start);
 3281                end = buffer.anchor_before(next_line_start);
 3282                mode = SelectMode::Line(start..end);
 3283                auto_scroll = true;
 3284            }
 3285            _ => {
 3286                start = buffer.anchor_before(0);
 3287                end = buffer.anchor_before(buffer.len());
 3288                mode = SelectMode::All;
 3289                auto_scroll = false;
 3290            }
 3291        }
 3292        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3293
 3294        let point_to_delete: Option<usize> = {
 3295            let selected_points: Vec<Selection<Point>> =
 3296                self.selections.disjoint_in_range(start..end, cx);
 3297
 3298            if !add || click_count > 1 {
 3299                None
 3300            } else if !selected_points.is_empty() {
 3301                Some(selected_points[0].id)
 3302            } else {
 3303                let clicked_point_already_selected =
 3304                    self.selections.disjoint.iter().find(|selection| {
 3305                        selection.start.to_point(buffer) == start.to_point(buffer)
 3306                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3307                    });
 3308
 3309                clicked_point_already_selected.map(|selection| selection.id)
 3310            }
 3311        };
 3312
 3313        let selections_count = self.selections.count();
 3314
 3315        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3316            if let Some(point_to_delete) = point_to_delete {
 3317                s.delete(point_to_delete);
 3318
 3319                if selections_count == 1 {
 3320                    s.set_pending_anchor_range(start..end, mode);
 3321                }
 3322            } else {
 3323                if !add {
 3324                    s.clear_disjoint();
 3325                }
 3326
 3327                s.set_pending_anchor_range(start..end, mode);
 3328            }
 3329        });
 3330    }
 3331
 3332    fn begin_columnar_selection(
 3333        &mut self,
 3334        position: DisplayPoint,
 3335        goal_column: u32,
 3336        reset: bool,
 3337        window: &mut Window,
 3338        cx: &mut Context<Self>,
 3339    ) {
 3340        if !self.focus_handle.is_focused(window) {
 3341            self.last_focused_descendant = None;
 3342            window.focus(&self.focus_handle);
 3343        }
 3344
 3345        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3346
 3347        if reset {
 3348            let pointer_position = display_map
 3349                .buffer_snapshot
 3350                .anchor_before(position.to_point(&display_map));
 3351
 3352            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3353                s.clear_disjoint();
 3354                s.set_pending_anchor_range(
 3355                    pointer_position..pointer_position,
 3356                    SelectMode::Character,
 3357                );
 3358            });
 3359            if position.column() != goal_column {
 3360                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3361            } else {
 3362                self.columnar_display_point = None;
 3363            }
 3364        }
 3365
 3366        let tail = self.selections.newest::<Point>(cx).tail();
 3367        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3368
 3369        if !reset {
 3370            self.columnar_display_point = None;
 3371            self.select_columns(
 3372                tail.to_display_point(&display_map),
 3373                position,
 3374                goal_column,
 3375                &display_map,
 3376                window,
 3377                cx,
 3378            );
 3379        }
 3380    }
 3381
 3382    fn update_selection(
 3383        &mut self,
 3384        position: DisplayPoint,
 3385        goal_column: u32,
 3386        scroll_delta: gpui::Point<f32>,
 3387        window: &mut Window,
 3388        cx: &mut Context<Self>,
 3389    ) {
 3390        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3391
 3392        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3393            let tail = self
 3394                .columnar_display_point
 3395                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3396            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3397        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3398            let buffer = self.buffer.read(cx).snapshot(cx);
 3399            let head;
 3400            let tail;
 3401            let mode = self.selections.pending_mode().unwrap();
 3402            match &mode {
 3403                SelectMode::Character => {
 3404                    head = position.to_point(&display_map);
 3405                    tail = pending.tail().to_point(&buffer);
 3406                }
 3407                SelectMode::Word(original_range) => {
 3408                    let original_display_range = original_range.start.to_display_point(&display_map)
 3409                        ..original_range.end.to_display_point(&display_map);
 3410                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3411                        ..original_display_range.end.to_point(&display_map);
 3412                    if movement::is_inside_word(&display_map, position)
 3413                        || original_display_range.contains(&position)
 3414                    {
 3415                        let word_range = movement::surrounding_word(&display_map, position);
 3416                        if word_range.start < original_display_range.start {
 3417                            head = word_range.start.to_point(&display_map);
 3418                        } else {
 3419                            head = word_range.end.to_point(&display_map);
 3420                        }
 3421                    } else {
 3422                        head = position.to_point(&display_map);
 3423                    }
 3424
 3425                    if head <= original_buffer_range.start {
 3426                        tail = original_buffer_range.end;
 3427                    } else {
 3428                        tail = original_buffer_range.start;
 3429                    }
 3430                }
 3431                SelectMode::Line(original_range) => {
 3432                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3433
 3434                    let position = display_map
 3435                        .clip_point(position, Bias::Left)
 3436                        .to_point(&display_map);
 3437                    let line_start = display_map.prev_line_boundary(position).0;
 3438                    let next_line_start = buffer.clip_point(
 3439                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3440                        Bias::Left,
 3441                    );
 3442
 3443                    if line_start < original_range.start {
 3444                        head = line_start
 3445                    } else {
 3446                        head = next_line_start
 3447                    }
 3448
 3449                    if head <= original_range.start {
 3450                        tail = original_range.end;
 3451                    } else {
 3452                        tail = original_range.start;
 3453                    }
 3454                }
 3455                SelectMode::All => {
 3456                    return;
 3457                }
 3458            };
 3459
 3460            if head < tail {
 3461                pending.start = buffer.anchor_before(head);
 3462                pending.end = buffer.anchor_before(tail);
 3463                pending.reversed = true;
 3464            } else {
 3465                pending.start = buffer.anchor_before(tail);
 3466                pending.end = buffer.anchor_before(head);
 3467                pending.reversed = false;
 3468            }
 3469
 3470            self.change_selections(None, window, cx, |s| {
 3471                s.set_pending(pending, mode);
 3472            });
 3473        } else {
 3474            log::error!("update_selection dispatched with no pending selection");
 3475            return;
 3476        }
 3477
 3478        self.apply_scroll_delta(scroll_delta, window, cx);
 3479        cx.notify();
 3480    }
 3481
 3482    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3483        self.columnar_selection_tail.take();
 3484        if self.selections.pending_anchor().is_some() {
 3485            let selections = self.selections.all::<usize>(cx);
 3486            self.change_selections(None, window, cx, |s| {
 3487                s.select(selections);
 3488                s.clear_pending();
 3489            });
 3490        }
 3491    }
 3492
 3493    fn select_columns(
 3494        &mut self,
 3495        tail: DisplayPoint,
 3496        head: DisplayPoint,
 3497        goal_column: u32,
 3498        display_map: &DisplaySnapshot,
 3499        window: &mut Window,
 3500        cx: &mut Context<Self>,
 3501    ) {
 3502        let start_row = cmp::min(tail.row(), head.row());
 3503        let end_row = cmp::max(tail.row(), head.row());
 3504        let start_column = cmp::min(tail.column(), goal_column);
 3505        let end_column = cmp::max(tail.column(), goal_column);
 3506        let reversed = start_column < tail.column();
 3507
 3508        let selection_ranges = (start_row.0..=end_row.0)
 3509            .map(DisplayRow)
 3510            .filter_map(|row| {
 3511                if !display_map.is_block_line(row) {
 3512                    let start = display_map
 3513                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3514                        .to_point(display_map);
 3515                    let end = display_map
 3516                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3517                        .to_point(display_map);
 3518                    if reversed {
 3519                        Some(end..start)
 3520                    } else {
 3521                        Some(start..end)
 3522                    }
 3523                } else {
 3524                    None
 3525                }
 3526            })
 3527            .collect::<Vec<_>>();
 3528
 3529        let mut non_empty_ranges = selection_ranges
 3530            .iter()
 3531            .filter(|selection_range| selection_range.start != selection_range.end)
 3532            .peekable();
 3533
 3534        let ranges = if non_empty_ranges.peek().is_some() {
 3535            non_empty_ranges.cloned().collect()
 3536        } else {
 3537            selection_ranges
 3538        };
 3539
 3540        self.change_selections(None, window, cx, |s| {
 3541            s.select_ranges(ranges);
 3542        });
 3543        cx.notify();
 3544    }
 3545
 3546    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3547        self.selections
 3548            .all_adjusted(cx)
 3549            .iter()
 3550            .any(|selection| !selection.is_empty())
 3551    }
 3552
 3553    pub fn has_pending_nonempty_selection(&self) -> bool {
 3554        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3555            Some(Selection { start, end, .. }) => start != end,
 3556            None => false,
 3557        };
 3558
 3559        pending_nonempty_selection
 3560            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3561    }
 3562
 3563    pub fn has_pending_selection(&self) -> bool {
 3564        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3565    }
 3566
 3567    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3568        self.selection_mark_mode = false;
 3569        self.selection_drag_state = SelectionDragState::None;
 3570
 3571        if self.clear_expanded_diff_hunks(cx) {
 3572            cx.notify();
 3573            return;
 3574        }
 3575        if self.dismiss_menus_and_popups(true, window, cx) {
 3576            return;
 3577        }
 3578
 3579        if self.mode.is_full()
 3580            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3581        {
 3582            return;
 3583        }
 3584
 3585        cx.propagate();
 3586    }
 3587
 3588    pub fn dismiss_menus_and_popups(
 3589        &mut self,
 3590        is_user_requested: bool,
 3591        window: &mut Window,
 3592        cx: &mut Context<Self>,
 3593    ) -> bool {
 3594        if self.take_rename(false, window, cx).is_some() {
 3595            return true;
 3596        }
 3597
 3598        if hide_hover(self, cx) {
 3599            return true;
 3600        }
 3601
 3602        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3603            return true;
 3604        }
 3605
 3606        if self.hide_context_menu(window, cx).is_some() {
 3607            return true;
 3608        }
 3609
 3610        if self.mouse_context_menu.take().is_some() {
 3611            return true;
 3612        }
 3613
 3614        if is_user_requested && self.discard_inline_completion(true, cx) {
 3615            return true;
 3616        }
 3617
 3618        if self.snippet_stack.pop().is_some() {
 3619            return true;
 3620        }
 3621
 3622        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3623            self.dismiss_diagnostics(cx);
 3624            return true;
 3625        }
 3626
 3627        false
 3628    }
 3629
 3630    fn linked_editing_ranges_for(
 3631        &self,
 3632        selection: Range<text::Anchor>,
 3633        cx: &App,
 3634    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3635        if self.linked_edit_ranges.is_empty() {
 3636            return None;
 3637        }
 3638        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3639            selection.end.buffer_id.and_then(|end_buffer_id| {
 3640                if selection.start.buffer_id != Some(end_buffer_id) {
 3641                    return None;
 3642                }
 3643                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3644                let snapshot = buffer.read(cx).snapshot();
 3645                self.linked_edit_ranges
 3646                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3647                    .map(|ranges| (ranges, snapshot, buffer))
 3648            })?;
 3649        use text::ToOffset as TO;
 3650        // find offset from the start of current range to current cursor position
 3651        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3652
 3653        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3654        let start_difference = start_offset - start_byte_offset;
 3655        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3656        let end_difference = end_offset - start_byte_offset;
 3657        // Current range has associated linked ranges.
 3658        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3659        for range in linked_ranges.iter() {
 3660            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3661            let end_offset = start_offset + end_difference;
 3662            let start_offset = start_offset + start_difference;
 3663            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3664                continue;
 3665            }
 3666            if self.selections.disjoint_anchor_ranges().any(|s| {
 3667                if s.start.buffer_id != selection.start.buffer_id
 3668                    || s.end.buffer_id != selection.end.buffer_id
 3669                {
 3670                    return false;
 3671                }
 3672                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3673                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3674            }) {
 3675                continue;
 3676            }
 3677            let start = buffer_snapshot.anchor_after(start_offset);
 3678            let end = buffer_snapshot.anchor_after(end_offset);
 3679            linked_edits
 3680                .entry(buffer.clone())
 3681                .or_default()
 3682                .push(start..end);
 3683        }
 3684        Some(linked_edits)
 3685    }
 3686
 3687    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3688        let text: Arc<str> = text.into();
 3689
 3690        if self.read_only(cx) {
 3691            return;
 3692        }
 3693
 3694        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3695
 3696        let selections = self.selections.all_adjusted(cx);
 3697        let mut bracket_inserted = false;
 3698        let mut edits = Vec::new();
 3699        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3700        let mut new_selections = Vec::with_capacity(selections.len());
 3701        let mut new_autoclose_regions = Vec::new();
 3702        let snapshot = self.buffer.read(cx).read(cx);
 3703        let mut clear_linked_edit_ranges = false;
 3704
 3705        for (selection, autoclose_region) in
 3706            self.selections_with_autoclose_regions(selections, &snapshot)
 3707        {
 3708            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3709                // Determine if the inserted text matches the opening or closing
 3710                // bracket of any of this language's bracket pairs.
 3711                let mut bracket_pair = None;
 3712                let mut is_bracket_pair_start = false;
 3713                let mut is_bracket_pair_end = false;
 3714                if !text.is_empty() {
 3715                    let mut bracket_pair_matching_end = None;
 3716                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3717                    //  and they are removing the character that triggered IME popup.
 3718                    for (pair, enabled) in scope.brackets() {
 3719                        if !pair.close && !pair.surround {
 3720                            continue;
 3721                        }
 3722
 3723                        if enabled && pair.start.ends_with(text.as_ref()) {
 3724                            let prefix_len = pair.start.len() - text.len();
 3725                            let preceding_text_matches_prefix = prefix_len == 0
 3726                                || (selection.start.column >= (prefix_len as u32)
 3727                                    && snapshot.contains_str_at(
 3728                                        Point::new(
 3729                                            selection.start.row,
 3730                                            selection.start.column - (prefix_len as u32),
 3731                                        ),
 3732                                        &pair.start[..prefix_len],
 3733                                    ));
 3734                            if preceding_text_matches_prefix {
 3735                                bracket_pair = Some(pair.clone());
 3736                                is_bracket_pair_start = true;
 3737                                break;
 3738                            }
 3739                        }
 3740                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3741                        {
 3742                            // take first bracket pair matching end, but don't break in case a later bracket
 3743                            // pair matches start
 3744                            bracket_pair_matching_end = Some(pair.clone());
 3745                        }
 3746                    }
 3747                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3748                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3749                        is_bracket_pair_end = true;
 3750                    }
 3751                }
 3752
 3753                if let Some(bracket_pair) = bracket_pair {
 3754                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3755                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3756                    let auto_surround =
 3757                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3758                    if selection.is_empty() {
 3759                        if is_bracket_pair_start {
 3760                            // If the inserted text is a suffix of an opening bracket and the
 3761                            // selection is preceded by the rest of the opening bracket, then
 3762                            // insert the closing bracket.
 3763                            let following_text_allows_autoclose = snapshot
 3764                                .chars_at(selection.start)
 3765                                .next()
 3766                                .map_or(true, |c| scope.should_autoclose_before(c));
 3767
 3768                            let preceding_text_allows_autoclose = selection.start.column == 0
 3769                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3770                                    true,
 3771                                    |c| {
 3772                                        bracket_pair.start != bracket_pair.end
 3773                                            || !snapshot
 3774                                                .char_classifier_at(selection.start)
 3775                                                .is_word(c)
 3776                                    },
 3777                                );
 3778
 3779                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3780                                && bracket_pair.start.len() == 1
 3781                            {
 3782                                let target = bracket_pair.start.chars().next().unwrap();
 3783                                let current_line_count = snapshot
 3784                                    .reversed_chars_at(selection.start)
 3785                                    .take_while(|&c| c != '\n')
 3786                                    .filter(|&c| c == target)
 3787                                    .count();
 3788                                current_line_count % 2 == 1
 3789                            } else {
 3790                                false
 3791                            };
 3792
 3793                            if autoclose
 3794                                && bracket_pair.close
 3795                                && following_text_allows_autoclose
 3796                                && preceding_text_allows_autoclose
 3797                                && !is_closing_quote
 3798                            {
 3799                                let anchor = snapshot.anchor_before(selection.end);
 3800                                new_selections.push((selection.map(|_| anchor), text.len()));
 3801                                new_autoclose_regions.push((
 3802                                    anchor,
 3803                                    text.len(),
 3804                                    selection.id,
 3805                                    bracket_pair.clone(),
 3806                                ));
 3807                                edits.push((
 3808                                    selection.range(),
 3809                                    format!("{}{}", text, bracket_pair.end).into(),
 3810                                ));
 3811                                bracket_inserted = true;
 3812                                continue;
 3813                            }
 3814                        }
 3815
 3816                        if let Some(region) = autoclose_region {
 3817                            // If the selection is followed by an auto-inserted closing bracket,
 3818                            // then don't insert that closing bracket again; just move the selection
 3819                            // past the closing bracket.
 3820                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3821                                && text.as_ref() == region.pair.end.as_str();
 3822                            if should_skip {
 3823                                let anchor = snapshot.anchor_after(selection.end);
 3824                                new_selections
 3825                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3826                                continue;
 3827                            }
 3828                        }
 3829
 3830                        let always_treat_brackets_as_autoclosed = snapshot
 3831                            .language_settings_at(selection.start, cx)
 3832                            .always_treat_brackets_as_autoclosed;
 3833                        if always_treat_brackets_as_autoclosed
 3834                            && is_bracket_pair_end
 3835                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3836                        {
 3837                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3838                            // and the inserted text is a closing bracket and the selection is followed
 3839                            // by the closing bracket then move the selection past the closing bracket.
 3840                            let anchor = snapshot.anchor_after(selection.end);
 3841                            new_selections.push((selection.map(|_| anchor), text.len()));
 3842                            continue;
 3843                        }
 3844                    }
 3845                    // If an opening bracket is 1 character long and is typed while
 3846                    // text is selected, then surround that text with the bracket pair.
 3847                    else if auto_surround
 3848                        && bracket_pair.surround
 3849                        && is_bracket_pair_start
 3850                        && bracket_pair.start.chars().count() == 1
 3851                    {
 3852                        edits.push((selection.start..selection.start, text.clone()));
 3853                        edits.push((
 3854                            selection.end..selection.end,
 3855                            bracket_pair.end.as_str().into(),
 3856                        ));
 3857                        bracket_inserted = true;
 3858                        new_selections.push((
 3859                            Selection {
 3860                                id: selection.id,
 3861                                start: snapshot.anchor_after(selection.start),
 3862                                end: snapshot.anchor_before(selection.end),
 3863                                reversed: selection.reversed,
 3864                                goal: selection.goal,
 3865                            },
 3866                            0,
 3867                        ));
 3868                        continue;
 3869                    }
 3870                }
 3871            }
 3872
 3873            if self.auto_replace_emoji_shortcode
 3874                && selection.is_empty()
 3875                && text.as_ref().ends_with(':')
 3876            {
 3877                if let Some(possible_emoji_short_code) =
 3878                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3879                {
 3880                    if !possible_emoji_short_code.is_empty() {
 3881                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3882                            let emoji_shortcode_start = Point::new(
 3883                                selection.start.row,
 3884                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3885                            );
 3886
 3887                            // Remove shortcode from buffer
 3888                            edits.push((
 3889                                emoji_shortcode_start..selection.start,
 3890                                "".to_string().into(),
 3891                            ));
 3892                            new_selections.push((
 3893                                Selection {
 3894                                    id: selection.id,
 3895                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3896                                    end: snapshot.anchor_before(selection.start),
 3897                                    reversed: selection.reversed,
 3898                                    goal: selection.goal,
 3899                                },
 3900                                0,
 3901                            ));
 3902
 3903                            // Insert emoji
 3904                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3905                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3906                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3907
 3908                            continue;
 3909                        }
 3910                    }
 3911                }
 3912            }
 3913
 3914            // If not handling any auto-close operation, then just replace the selected
 3915            // text with the given input and move the selection to the end of the
 3916            // newly inserted text.
 3917            let anchor = snapshot.anchor_after(selection.end);
 3918            if !self.linked_edit_ranges.is_empty() {
 3919                let start_anchor = snapshot.anchor_before(selection.start);
 3920
 3921                let is_word_char = text.chars().next().map_or(true, |char| {
 3922                    let classifier = snapshot
 3923                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3924                        .ignore_punctuation(true);
 3925                    classifier.is_word(char)
 3926                });
 3927
 3928                if is_word_char {
 3929                    if let Some(ranges) = self
 3930                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3931                    {
 3932                        for (buffer, edits) in ranges {
 3933                            linked_edits
 3934                                .entry(buffer.clone())
 3935                                .or_default()
 3936                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3937                        }
 3938                    }
 3939                } else {
 3940                    clear_linked_edit_ranges = true;
 3941                }
 3942            }
 3943
 3944            new_selections.push((selection.map(|_| anchor), 0));
 3945            edits.push((selection.start..selection.end, text.clone()));
 3946        }
 3947
 3948        drop(snapshot);
 3949
 3950        self.transact(window, cx, |this, window, cx| {
 3951            if clear_linked_edit_ranges {
 3952                this.linked_edit_ranges.clear();
 3953            }
 3954            let initial_buffer_versions =
 3955                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3956
 3957            this.buffer.update(cx, |buffer, cx| {
 3958                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3959            });
 3960            for (buffer, edits) in linked_edits {
 3961                buffer.update(cx, |buffer, cx| {
 3962                    let snapshot = buffer.snapshot();
 3963                    let edits = edits
 3964                        .into_iter()
 3965                        .map(|(range, text)| {
 3966                            use text::ToPoint as TP;
 3967                            let end_point = TP::to_point(&range.end, &snapshot);
 3968                            let start_point = TP::to_point(&range.start, &snapshot);
 3969                            (start_point..end_point, text)
 3970                        })
 3971                        .sorted_by_key(|(range, _)| range.start);
 3972                    buffer.edit(edits, None, cx);
 3973                })
 3974            }
 3975            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3976            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3977            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3978            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3979                .zip(new_selection_deltas)
 3980                .map(|(selection, delta)| Selection {
 3981                    id: selection.id,
 3982                    start: selection.start + delta,
 3983                    end: selection.end + delta,
 3984                    reversed: selection.reversed,
 3985                    goal: SelectionGoal::None,
 3986                })
 3987                .collect::<Vec<_>>();
 3988
 3989            let mut i = 0;
 3990            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3991                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3992                let start = map.buffer_snapshot.anchor_before(position);
 3993                let end = map.buffer_snapshot.anchor_after(position);
 3994                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3995                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3996                        Ordering::Less => i += 1,
 3997                        Ordering::Greater => break,
 3998                        Ordering::Equal => {
 3999                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4000                                Ordering::Less => i += 1,
 4001                                Ordering::Equal => break,
 4002                                Ordering::Greater => break,
 4003                            }
 4004                        }
 4005                    }
 4006                }
 4007                this.autoclose_regions.insert(
 4008                    i,
 4009                    AutocloseRegion {
 4010                        selection_id,
 4011                        range: start..end,
 4012                        pair,
 4013                    },
 4014                );
 4015            }
 4016
 4017            let had_active_inline_completion = this.has_active_inline_completion();
 4018            this.change_selections_without_updating_completions(
 4019                Some(Autoscroll::fit()),
 4020                window,
 4021                cx,
 4022                |s| s.select(new_selections),
 4023            );
 4024
 4025            if !bracket_inserted {
 4026                if let Some(on_type_format_task) =
 4027                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4028                {
 4029                    on_type_format_task.detach_and_log_err(cx);
 4030                }
 4031            }
 4032
 4033            let editor_settings = EditorSettings::get_global(cx);
 4034            if bracket_inserted
 4035                && (editor_settings.auto_signature_help
 4036                    || editor_settings.show_signature_help_after_edits)
 4037            {
 4038                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4039            }
 4040
 4041            let trigger_in_words =
 4042                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4043            if this.hard_wrap.is_some() {
 4044                let latest: Range<Point> = this.selections.newest(cx).range();
 4045                if latest.is_empty()
 4046                    && this
 4047                        .buffer()
 4048                        .read(cx)
 4049                        .snapshot(cx)
 4050                        .line_len(MultiBufferRow(latest.start.row))
 4051                        == latest.start.column
 4052                {
 4053                    this.rewrap_impl(
 4054                        RewrapOptions {
 4055                            override_language_settings: true,
 4056                            preserve_existing_whitespace: true,
 4057                        },
 4058                        cx,
 4059                    )
 4060                }
 4061            }
 4062            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4063            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4064            this.refresh_inline_completion(true, false, window, cx);
 4065            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4066        });
 4067    }
 4068
 4069    fn find_possible_emoji_shortcode_at_position(
 4070        snapshot: &MultiBufferSnapshot,
 4071        position: Point,
 4072    ) -> Option<String> {
 4073        let mut chars = Vec::new();
 4074        let mut found_colon = false;
 4075        for char in snapshot.reversed_chars_at(position).take(100) {
 4076            // Found a possible emoji shortcode in the middle of the buffer
 4077            if found_colon {
 4078                if char.is_whitespace() {
 4079                    chars.reverse();
 4080                    return Some(chars.iter().collect());
 4081                }
 4082                // If the previous character is not a whitespace, we are in the middle of a word
 4083                // and we only want to complete the shortcode if the word is made up of other emojis
 4084                let mut containing_word = String::new();
 4085                for ch in snapshot
 4086                    .reversed_chars_at(position)
 4087                    .skip(chars.len() + 1)
 4088                    .take(100)
 4089                {
 4090                    if ch.is_whitespace() {
 4091                        break;
 4092                    }
 4093                    containing_word.push(ch);
 4094                }
 4095                let containing_word = containing_word.chars().rev().collect::<String>();
 4096                if util::word_consists_of_emojis(containing_word.as_str()) {
 4097                    chars.reverse();
 4098                    return Some(chars.iter().collect());
 4099                }
 4100            }
 4101
 4102            if char.is_whitespace() || !char.is_ascii() {
 4103                return None;
 4104            }
 4105            if char == ':' {
 4106                found_colon = true;
 4107            } else {
 4108                chars.push(char);
 4109            }
 4110        }
 4111        // Found a possible emoji shortcode at the beginning of the buffer
 4112        chars.reverse();
 4113        Some(chars.iter().collect())
 4114    }
 4115
 4116    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4117        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4118        self.transact(window, cx, |this, window, cx| {
 4119            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4120                let selections = this.selections.all::<usize>(cx);
 4121                let multi_buffer = this.buffer.read(cx);
 4122                let buffer = multi_buffer.snapshot(cx);
 4123                selections
 4124                    .iter()
 4125                    .map(|selection| {
 4126                        let start_point = selection.start.to_point(&buffer);
 4127                        let mut existing_indent =
 4128                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4129                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4130                        let start = selection.start;
 4131                        let end = selection.end;
 4132                        let selection_is_empty = start == end;
 4133                        let language_scope = buffer.language_scope_at(start);
 4134                        let (
 4135                            comment_delimiter,
 4136                            doc_delimiter,
 4137                            insert_extra_newline,
 4138                            indent_on_newline,
 4139                            indent_on_extra_newline,
 4140                        ) = if let Some(language) = &language_scope {
 4141                            let mut insert_extra_newline =
 4142                                insert_extra_newline_brackets(&buffer, start..end, language)
 4143                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4144
 4145                            // Comment extension on newline is allowed only for cursor selections
 4146                            let comment_delimiter = maybe!({
 4147                                if !selection_is_empty {
 4148                                    return None;
 4149                                }
 4150
 4151                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4152                                    return None;
 4153                                }
 4154
 4155                                let delimiters = language.line_comment_prefixes();
 4156                                let max_len_of_delimiter =
 4157                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4158                                let (snapshot, range) =
 4159                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4160
 4161                                let num_of_whitespaces = snapshot
 4162                                    .chars_for_range(range.clone())
 4163                                    .take_while(|c| c.is_whitespace())
 4164                                    .count();
 4165                                let comment_candidate = snapshot
 4166                                    .chars_for_range(range)
 4167                                    .skip(num_of_whitespaces)
 4168                                    .take(max_len_of_delimiter)
 4169                                    .collect::<String>();
 4170                                let (delimiter, trimmed_len) = delimiters
 4171                                    .iter()
 4172                                    .filter_map(|delimiter| {
 4173                                        let prefix = delimiter.trim_end();
 4174                                        if comment_candidate.starts_with(prefix) {
 4175                                            Some((delimiter, prefix.len()))
 4176                                        } else {
 4177                                            None
 4178                                        }
 4179                                    })
 4180                                    .max_by_key(|(_, len)| *len)?;
 4181
 4182                                let cursor_is_placed_after_comment_marker =
 4183                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4184                                if cursor_is_placed_after_comment_marker {
 4185                                    Some(delimiter.clone())
 4186                                } else {
 4187                                    None
 4188                                }
 4189                            });
 4190
 4191                            let mut indent_on_newline = IndentSize::spaces(0);
 4192                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4193
 4194                            let doc_delimiter = maybe!({
 4195                                if !selection_is_empty {
 4196                                    return None;
 4197                                }
 4198
 4199                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4200                                    return None;
 4201                                }
 4202
 4203                                let DocumentationConfig {
 4204                                    start: start_tag,
 4205                                    end: end_tag,
 4206                                    prefix: delimiter,
 4207                                    tab_size: len,
 4208                                } = language.documentation()?;
 4209
 4210                                let is_within_block_comment = buffer
 4211                                    .language_scope_at(start_point)
 4212                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4213                                if !is_within_block_comment {
 4214                                    return None;
 4215                                }
 4216
 4217                                let (snapshot, range) =
 4218                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4219
 4220                                let num_of_whitespaces = snapshot
 4221                                    .chars_for_range(range.clone())
 4222                                    .take_while(|c| c.is_whitespace())
 4223                                    .count();
 4224
 4225                                // 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.
 4226                                let column = start_point.column;
 4227                                let cursor_is_after_start_tag = {
 4228                                    let start_tag_len = start_tag.len();
 4229                                    let start_tag_line = snapshot
 4230                                        .chars_for_range(range.clone())
 4231                                        .skip(num_of_whitespaces)
 4232                                        .take(start_tag_len)
 4233                                        .collect::<String>();
 4234                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4235                                        num_of_whitespaces + start_tag_len <= column as usize
 4236                                    } else {
 4237                                        false
 4238                                    }
 4239                                };
 4240
 4241                                let cursor_is_after_delimiter = {
 4242                                    let delimiter_trim = delimiter.trim_end();
 4243                                    let delimiter_line = snapshot
 4244                                        .chars_for_range(range.clone())
 4245                                        .skip(num_of_whitespaces)
 4246                                        .take(delimiter_trim.len())
 4247                                        .collect::<String>();
 4248                                    if delimiter_line.starts_with(delimiter_trim) {
 4249                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4250                                    } else {
 4251                                        false
 4252                                    }
 4253                                };
 4254
 4255                                let cursor_is_before_end_tag_if_exists = {
 4256                                    let mut char_position = 0u32;
 4257                                    let mut end_tag_offset = None;
 4258
 4259                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4260                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4261                                            let chars_before_match =
 4262                                                chunk[..byte_pos].chars().count() as u32;
 4263                                            end_tag_offset =
 4264                                                Some(char_position + chars_before_match);
 4265                                            break 'outer;
 4266                                        }
 4267                                        char_position += chunk.chars().count() as u32;
 4268                                    }
 4269
 4270                                    if let Some(end_tag_offset) = end_tag_offset {
 4271                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4272                                        if cursor_is_after_start_tag {
 4273                                            if cursor_is_before_end_tag {
 4274                                                insert_extra_newline = true;
 4275                                            }
 4276                                            let cursor_is_at_start_of_end_tag =
 4277                                                column == end_tag_offset;
 4278                                            if cursor_is_at_start_of_end_tag {
 4279                                                indent_on_extra_newline.len = (*len).into();
 4280                                            }
 4281                                        }
 4282                                        cursor_is_before_end_tag
 4283                                    } else {
 4284                                        true
 4285                                    }
 4286                                };
 4287
 4288                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4289                                    && cursor_is_before_end_tag_if_exists
 4290                                {
 4291                                    if cursor_is_after_start_tag {
 4292                                        indent_on_newline.len = (*len).into();
 4293                                    }
 4294                                    Some(delimiter.clone())
 4295                                } else {
 4296                                    None
 4297                                }
 4298                            });
 4299
 4300                            (
 4301                                comment_delimiter,
 4302                                doc_delimiter,
 4303                                insert_extra_newline,
 4304                                indent_on_newline,
 4305                                indent_on_extra_newline,
 4306                            )
 4307                        } else {
 4308                            (
 4309                                None,
 4310                                None,
 4311                                false,
 4312                                IndentSize::default(),
 4313                                IndentSize::default(),
 4314                            )
 4315                        };
 4316
 4317                        let prevent_auto_indent = doc_delimiter.is_some();
 4318                        let delimiter = comment_delimiter.or(doc_delimiter);
 4319
 4320                        let capacity_for_delimiter =
 4321                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4322                        let mut new_text = String::with_capacity(
 4323                            1 + capacity_for_delimiter
 4324                                + existing_indent.len as usize
 4325                                + indent_on_newline.len as usize
 4326                                + indent_on_extra_newline.len as usize,
 4327                        );
 4328                        new_text.push('\n');
 4329                        new_text.extend(existing_indent.chars());
 4330                        new_text.extend(indent_on_newline.chars());
 4331
 4332                        if let Some(delimiter) = &delimiter {
 4333                            new_text.push_str(delimiter);
 4334                        }
 4335
 4336                        if insert_extra_newline {
 4337                            new_text.push('\n');
 4338                            new_text.extend(existing_indent.chars());
 4339                            new_text.extend(indent_on_extra_newline.chars());
 4340                        }
 4341
 4342                        let anchor = buffer.anchor_after(end);
 4343                        let new_selection = selection.map(|_| anchor);
 4344                        (
 4345                            ((start..end, new_text), prevent_auto_indent),
 4346                            (insert_extra_newline, new_selection),
 4347                        )
 4348                    })
 4349                    .unzip()
 4350            };
 4351
 4352            let mut auto_indent_edits = Vec::new();
 4353            let mut edits = Vec::new();
 4354            for (edit, prevent_auto_indent) in edits_with_flags {
 4355                if prevent_auto_indent {
 4356                    edits.push(edit);
 4357                } else {
 4358                    auto_indent_edits.push(edit);
 4359                }
 4360            }
 4361            if !edits.is_empty() {
 4362                this.edit(edits, cx);
 4363            }
 4364            if !auto_indent_edits.is_empty() {
 4365                this.edit_with_autoindent(auto_indent_edits, cx);
 4366            }
 4367
 4368            let buffer = this.buffer.read(cx).snapshot(cx);
 4369            let new_selections = selection_info
 4370                .into_iter()
 4371                .map(|(extra_newline_inserted, new_selection)| {
 4372                    let mut cursor = new_selection.end.to_point(&buffer);
 4373                    if extra_newline_inserted {
 4374                        cursor.row -= 1;
 4375                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4376                    }
 4377                    new_selection.map(|_| cursor)
 4378                })
 4379                .collect();
 4380
 4381            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4382                s.select(new_selections)
 4383            });
 4384            this.refresh_inline_completion(true, false, window, cx);
 4385        });
 4386    }
 4387
 4388    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4389        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4390
 4391        let buffer = self.buffer.read(cx);
 4392        let snapshot = buffer.snapshot(cx);
 4393
 4394        let mut edits = Vec::new();
 4395        let mut rows = Vec::new();
 4396
 4397        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4398            let cursor = selection.head();
 4399            let row = cursor.row;
 4400
 4401            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4402
 4403            let newline = "\n".to_string();
 4404            edits.push((start_of_line..start_of_line, newline));
 4405
 4406            rows.push(row + rows_inserted as u32);
 4407        }
 4408
 4409        self.transact(window, cx, |editor, window, cx| {
 4410            editor.edit(edits, cx);
 4411
 4412            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4413                let mut index = 0;
 4414                s.move_cursors_with(|map, _, _| {
 4415                    let row = rows[index];
 4416                    index += 1;
 4417
 4418                    let point = Point::new(row, 0);
 4419                    let boundary = map.next_line_boundary(point).1;
 4420                    let clipped = map.clip_point(boundary, Bias::Left);
 4421
 4422                    (clipped, SelectionGoal::None)
 4423                });
 4424            });
 4425
 4426            let mut indent_edits = Vec::new();
 4427            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4428            for row in rows {
 4429                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4430                for (row, indent) in indents {
 4431                    if indent.len == 0 {
 4432                        continue;
 4433                    }
 4434
 4435                    let text = match indent.kind {
 4436                        IndentKind::Space => " ".repeat(indent.len as usize),
 4437                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4438                    };
 4439                    let point = Point::new(row.0, 0);
 4440                    indent_edits.push((point..point, text));
 4441                }
 4442            }
 4443            editor.edit(indent_edits, cx);
 4444        });
 4445    }
 4446
 4447    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4448        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4449
 4450        let buffer = self.buffer.read(cx);
 4451        let snapshot = buffer.snapshot(cx);
 4452
 4453        let mut edits = Vec::new();
 4454        let mut rows = Vec::new();
 4455        let mut rows_inserted = 0;
 4456
 4457        for selection in self.selections.all_adjusted(cx) {
 4458            let cursor = selection.head();
 4459            let row = cursor.row;
 4460
 4461            let point = Point::new(row + 1, 0);
 4462            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4463
 4464            let newline = "\n".to_string();
 4465            edits.push((start_of_line..start_of_line, newline));
 4466
 4467            rows_inserted += 1;
 4468            rows.push(row + rows_inserted);
 4469        }
 4470
 4471        self.transact(window, cx, |editor, window, cx| {
 4472            editor.edit(edits, cx);
 4473
 4474            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4475                let mut index = 0;
 4476                s.move_cursors_with(|map, _, _| {
 4477                    let row = rows[index];
 4478                    index += 1;
 4479
 4480                    let point = Point::new(row, 0);
 4481                    let boundary = map.next_line_boundary(point).1;
 4482                    let clipped = map.clip_point(boundary, Bias::Left);
 4483
 4484                    (clipped, SelectionGoal::None)
 4485                });
 4486            });
 4487
 4488            let mut indent_edits = Vec::new();
 4489            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4490            for row in rows {
 4491                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4492                for (row, indent) in indents {
 4493                    if indent.len == 0 {
 4494                        continue;
 4495                    }
 4496
 4497                    let text = match indent.kind {
 4498                        IndentKind::Space => " ".repeat(indent.len as usize),
 4499                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4500                    };
 4501                    let point = Point::new(row.0, 0);
 4502                    indent_edits.push((point..point, text));
 4503                }
 4504            }
 4505            editor.edit(indent_edits, cx);
 4506        });
 4507    }
 4508
 4509    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4510        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4511            original_indent_columns: Vec::new(),
 4512        });
 4513        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4514    }
 4515
 4516    fn insert_with_autoindent_mode(
 4517        &mut self,
 4518        text: &str,
 4519        autoindent_mode: Option<AutoindentMode>,
 4520        window: &mut Window,
 4521        cx: &mut Context<Self>,
 4522    ) {
 4523        if self.read_only(cx) {
 4524            return;
 4525        }
 4526
 4527        let text: Arc<str> = text.into();
 4528        self.transact(window, cx, |this, window, cx| {
 4529            let old_selections = this.selections.all_adjusted(cx);
 4530            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4531                let anchors = {
 4532                    let snapshot = buffer.read(cx);
 4533                    old_selections
 4534                        .iter()
 4535                        .map(|s| {
 4536                            let anchor = snapshot.anchor_after(s.head());
 4537                            s.map(|_| anchor)
 4538                        })
 4539                        .collect::<Vec<_>>()
 4540                };
 4541                buffer.edit(
 4542                    old_selections
 4543                        .iter()
 4544                        .map(|s| (s.start..s.end, text.clone())),
 4545                    autoindent_mode,
 4546                    cx,
 4547                );
 4548                anchors
 4549            });
 4550
 4551            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4552                s.select_anchors(selection_anchors);
 4553            });
 4554
 4555            cx.notify();
 4556        });
 4557    }
 4558
 4559    fn trigger_completion_on_input(
 4560        &mut self,
 4561        text: &str,
 4562        trigger_in_words: bool,
 4563        window: &mut Window,
 4564        cx: &mut Context<Self>,
 4565    ) {
 4566        let completions_source = self
 4567            .context_menu
 4568            .borrow()
 4569            .as_ref()
 4570            .and_then(|menu| match menu {
 4571                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4572                CodeContextMenu::CodeActions(_) => None,
 4573            });
 4574
 4575        match completions_source {
 4576            Some(CompletionsMenuSource::Words) => {
 4577                self.show_word_completions(&ShowWordCompletions, window, cx)
 4578            }
 4579            Some(CompletionsMenuSource::Normal)
 4580            | Some(CompletionsMenuSource::SnippetChoices)
 4581            | None
 4582                if self.is_completion_trigger(
 4583                    text,
 4584                    trigger_in_words,
 4585                    completions_source.is_some(),
 4586                    cx,
 4587                ) =>
 4588            {
 4589                self.show_completions(
 4590                    &ShowCompletions {
 4591                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4592                    },
 4593                    window,
 4594                    cx,
 4595                )
 4596            }
 4597            _ => {
 4598                self.hide_context_menu(window, cx);
 4599            }
 4600        }
 4601    }
 4602
 4603    fn is_completion_trigger(
 4604        &self,
 4605        text: &str,
 4606        trigger_in_words: bool,
 4607        menu_is_open: bool,
 4608        cx: &mut Context<Self>,
 4609    ) -> bool {
 4610        let position = self.selections.newest_anchor().head();
 4611        let multibuffer = self.buffer.read(cx);
 4612        let Some(buffer) = position
 4613            .buffer_id
 4614            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4615        else {
 4616            return false;
 4617        };
 4618
 4619        if let Some(completion_provider) = &self.completion_provider {
 4620            completion_provider.is_completion_trigger(
 4621                &buffer,
 4622                position.text_anchor,
 4623                text,
 4624                trigger_in_words,
 4625                menu_is_open,
 4626                cx,
 4627            )
 4628        } else {
 4629            false
 4630        }
 4631    }
 4632
 4633    /// If any empty selections is touching the start of its innermost containing autoclose
 4634    /// region, expand it to select the brackets.
 4635    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4636        let selections = self.selections.all::<usize>(cx);
 4637        let buffer = self.buffer.read(cx).read(cx);
 4638        let new_selections = self
 4639            .selections_with_autoclose_regions(selections, &buffer)
 4640            .map(|(mut selection, region)| {
 4641                if !selection.is_empty() {
 4642                    return selection;
 4643                }
 4644
 4645                if let Some(region) = region {
 4646                    let mut range = region.range.to_offset(&buffer);
 4647                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4648                        range.start -= region.pair.start.len();
 4649                        if buffer.contains_str_at(range.start, &region.pair.start)
 4650                            && buffer.contains_str_at(range.end, &region.pair.end)
 4651                        {
 4652                            range.end += region.pair.end.len();
 4653                            selection.start = range.start;
 4654                            selection.end = range.end;
 4655
 4656                            return selection;
 4657                        }
 4658                    }
 4659                }
 4660
 4661                let always_treat_brackets_as_autoclosed = buffer
 4662                    .language_settings_at(selection.start, cx)
 4663                    .always_treat_brackets_as_autoclosed;
 4664
 4665                if !always_treat_brackets_as_autoclosed {
 4666                    return selection;
 4667                }
 4668
 4669                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4670                    for (pair, enabled) in scope.brackets() {
 4671                        if !enabled || !pair.close {
 4672                            continue;
 4673                        }
 4674
 4675                        if buffer.contains_str_at(selection.start, &pair.end) {
 4676                            let pair_start_len = pair.start.len();
 4677                            if buffer.contains_str_at(
 4678                                selection.start.saturating_sub(pair_start_len),
 4679                                &pair.start,
 4680                            ) {
 4681                                selection.start -= pair_start_len;
 4682                                selection.end += pair.end.len();
 4683
 4684                                return selection;
 4685                            }
 4686                        }
 4687                    }
 4688                }
 4689
 4690                selection
 4691            })
 4692            .collect();
 4693
 4694        drop(buffer);
 4695        self.change_selections(None, window, cx, |selections| {
 4696            selections.select(new_selections)
 4697        });
 4698    }
 4699
 4700    /// Iterate the given selections, and for each one, find the smallest surrounding
 4701    /// autoclose region. This uses the ordering of the selections and the autoclose
 4702    /// regions to avoid repeated comparisons.
 4703    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4704        &'a self,
 4705        selections: impl IntoIterator<Item = Selection<D>>,
 4706        buffer: &'a MultiBufferSnapshot,
 4707    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4708        let mut i = 0;
 4709        let mut regions = self.autoclose_regions.as_slice();
 4710        selections.into_iter().map(move |selection| {
 4711            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4712
 4713            let mut enclosing = None;
 4714            while let Some(pair_state) = regions.get(i) {
 4715                if pair_state.range.end.to_offset(buffer) < range.start {
 4716                    regions = &regions[i + 1..];
 4717                    i = 0;
 4718                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4719                    break;
 4720                } else {
 4721                    if pair_state.selection_id == selection.id {
 4722                        enclosing = Some(pair_state);
 4723                    }
 4724                    i += 1;
 4725                }
 4726            }
 4727
 4728            (selection, enclosing)
 4729        })
 4730    }
 4731
 4732    /// Remove any autoclose regions that no longer contain their selection.
 4733    fn invalidate_autoclose_regions(
 4734        &mut self,
 4735        mut selections: &[Selection<Anchor>],
 4736        buffer: &MultiBufferSnapshot,
 4737    ) {
 4738        self.autoclose_regions.retain(|state| {
 4739            let mut i = 0;
 4740            while let Some(selection) = selections.get(i) {
 4741                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4742                    selections = &selections[1..];
 4743                    continue;
 4744                }
 4745                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4746                    break;
 4747                }
 4748                if selection.id == state.selection_id {
 4749                    return true;
 4750                } else {
 4751                    i += 1;
 4752                }
 4753            }
 4754            false
 4755        });
 4756    }
 4757
 4758    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4759        let offset = position.to_offset(buffer);
 4760        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4761        if offset > word_range.start && kind == Some(CharKind::Word) {
 4762            Some(
 4763                buffer
 4764                    .text_for_range(word_range.start..offset)
 4765                    .collect::<String>(),
 4766            )
 4767        } else {
 4768            None
 4769        }
 4770    }
 4771
 4772    pub fn toggle_inline_values(
 4773        &mut self,
 4774        _: &ToggleInlineValues,
 4775        _: &mut Window,
 4776        cx: &mut Context<Self>,
 4777    ) {
 4778        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4779
 4780        self.refresh_inline_values(cx);
 4781    }
 4782
 4783    pub fn toggle_inlay_hints(
 4784        &mut self,
 4785        _: &ToggleInlayHints,
 4786        _: &mut Window,
 4787        cx: &mut Context<Self>,
 4788    ) {
 4789        self.refresh_inlay_hints(
 4790            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4791            cx,
 4792        );
 4793    }
 4794
 4795    pub fn inlay_hints_enabled(&self) -> bool {
 4796        self.inlay_hint_cache.enabled
 4797    }
 4798
 4799    pub fn inline_values_enabled(&self) -> bool {
 4800        self.inline_value_cache.enabled
 4801    }
 4802
 4803    #[cfg(any(test, feature = "test-support"))]
 4804    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4805        self.display_map
 4806            .read(cx)
 4807            .current_inlays()
 4808            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4809            .cloned()
 4810            .collect()
 4811    }
 4812
 4813    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4814        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4815            return;
 4816        }
 4817
 4818        let reason_description = reason.description();
 4819        let ignore_debounce = matches!(
 4820            reason,
 4821            InlayHintRefreshReason::SettingsChange(_)
 4822                | InlayHintRefreshReason::Toggle(_)
 4823                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4824                | InlayHintRefreshReason::ModifiersChanged(_)
 4825        );
 4826        let (invalidate_cache, required_languages) = match reason {
 4827            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4828                match self.inlay_hint_cache.modifiers_override(enabled) {
 4829                    Some(enabled) => {
 4830                        if enabled {
 4831                            (InvalidationStrategy::RefreshRequested, None)
 4832                        } else {
 4833                            self.splice_inlays(
 4834                                &self
 4835                                    .visible_inlay_hints(cx)
 4836                                    .iter()
 4837                                    .map(|inlay| inlay.id)
 4838                                    .collect::<Vec<InlayId>>(),
 4839                                Vec::new(),
 4840                                cx,
 4841                            );
 4842                            return;
 4843                        }
 4844                    }
 4845                    None => return,
 4846                }
 4847            }
 4848            InlayHintRefreshReason::Toggle(enabled) => {
 4849                if self.inlay_hint_cache.toggle(enabled) {
 4850                    if enabled {
 4851                        (InvalidationStrategy::RefreshRequested, None)
 4852                    } else {
 4853                        self.splice_inlays(
 4854                            &self
 4855                                .visible_inlay_hints(cx)
 4856                                .iter()
 4857                                .map(|inlay| inlay.id)
 4858                                .collect::<Vec<InlayId>>(),
 4859                            Vec::new(),
 4860                            cx,
 4861                        );
 4862                        return;
 4863                    }
 4864                } else {
 4865                    return;
 4866                }
 4867            }
 4868            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4869                match self.inlay_hint_cache.update_settings(
 4870                    &self.buffer,
 4871                    new_settings,
 4872                    self.visible_inlay_hints(cx),
 4873                    cx,
 4874                ) {
 4875                    ControlFlow::Break(Some(InlaySplice {
 4876                        to_remove,
 4877                        to_insert,
 4878                    })) => {
 4879                        self.splice_inlays(&to_remove, to_insert, cx);
 4880                        return;
 4881                    }
 4882                    ControlFlow::Break(None) => return,
 4883                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4884                }
 4885            }
 4886            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4887                if let Some(InlaySplice {
 4888                    to_remove,
 4889                    to_insert,
 4890                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4891                {
 4892                    self.splice_inlays(&to_remove, to_insert, cx);
 4893                }
 4894                self.display_map.update(cx, |display_map, _| {
 4895                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4896                });
 4897                return;
 4898            }
 4899            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4900            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4901                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4902            }
 4903            InlayHintRefreshReason::RefreshRequested => {
 4904                (InvalidationStrategy::RefreshRequested, None)
 4905            }
 4906        };
 4907
 4908        if let Some(InlaySplice {
 4909            to_remove,
 4910            to_insert,
 4911        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4912            reason_description,
 4913            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4914            invalidate_cache,
 4915            ignore_debounce,
 4916            cx,
 4917        ) {
 4918            self.splice_inlays(&to_remove, to_insert, cx);
 4919        }
 4920    }
 4921
 4922    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4923        self.display_map
 4924            .read(cx)
 4925            .current_inlays()
 4926            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4927            .cloned()
 4928            .collect()
 4929    }
 4930
 4931    pub fn excerpts_for_inlay_hints_query(
 4932        &self,
 4933        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4934        cx: &mut Context<Editor>,
 4935    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4936        let Some(project) = self.project.as_ref() else {
 4937            return HashMap::default();
 4938        };
 4939        let project = project.read(cx);
 4940        let multi_buffer = self.buffer().read(cx);
 4941        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4942        let multi_buffer_visible_start = self
 4943            .scroll_manager
 4944            .anchor()
 4945            .anchor
 4946            .to_point(&multi_buffer_snapshot);
 4947        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4948            multi_buffer_visible_start
 4949                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4950            Bias::Left,
 4951        );
 4952        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4953        multi_buffer_snapshot
 4954            .range_to_buffer_ranges(multi_buffer_visible_range)
 4955            .into_iter()
 4956            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4957            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4958                let buffer_file = project::File::from_dyn(buffer.file())?;
 4959                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4960                let worktree_entry = buffer_worktree
 4961                    .read(cx)
 4962                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4963                if worktree_entry.is_ignored {
 4964                    return None;
 4965                }
 4966
 4967                let language = buffer.language()?;
 4968                if let Some(restrict_to_languages) = restrict_to_languages {
 4969                    if !restrict_to_languages.contains(language) {
 4970                        return None;
 4971                    }
 4972                }
 4973                Some((
 4974                    excerpt_id,
 4975                    (
 4976                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4977                        buffer.version().clone(),
 4978                        excerpt_visible_range,
 4979                    ),
 4980                ))
 4981            })
 4982            .collect()
 4983    }
 4984
 4985    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4986        TextLayoutDetails {
 4987            text_system: window.text_system().clone(),
 4988            editor_style: self.style.clone().unwrap(),
 4989            rem_size: window.rem_size(),
 4990            scroll_anchor: self.scroll_manager.anchor(),
 4991            visible_rows: self.visible_line_count(),
 4992            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4993        }
 4994    }
 4995
 4996    pub fn splice_inlays(
 4997        &self,
 4998        to_remove: &[InlayId],
 4999        to_insert: Vec<Inlay>,
 5000        cx: &mut Context<Self>,
 5001    ) {
 5002        self.display_map.update(cx, |display_map, cx| {
 5003            display_map.splice_inlays(to_remove, to_insert, cx)
 5004        });
 5005        cx.notify();
 5006    }
 5007
 5008    fn trigger_on_type_formatting(
 5009        &self,
 5010        input: String,
 5011        window: &mut Window,
 5012        cx: &mut Context<Self>,
 5013    ) -> Option<Task<Result<()>>> {
 5014        if input.len() != 1 {
 5015            return None;
 5016        }
 5017
 5018        let project = self.project.as_ref()?;
 5019        let position = self.selections.newest_anchor().head();
 5020        let (buffer, buffer_position) = self
 5021            .buffer
 5022            .read(cx)
 5023            .text_anchor_for_position(position, cx)?;
 5024
 5025        let settings = language_settings::language_settings(
 5026            buffer
 5027                .read(cx)
 5028                .language_at(buffer_position)
 5029                .map(|l| l.name()),
 5030            buffer.read(cx).file(),
 5031            cx,
 5032        );
 5033        if !settings.use_on_type_format {
 5034            return None;
 5035        }
 5036
 5037        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5038        // hence we do LSP request & edit on host side only — add formats to host's history.
 5039        let push_to_lsp_host_history = true;
 5040        // If this is not the host, append its history with new edits.
 5041        let push_to_client_history = project.read(cx).is_via_collab();
 5042
 5043        let on_type_formatting = project.update(cx, |project, cx| {
 5044            project.on_type_format(
 5045                buffer.clone(),
 5046                buffer_position,
 5047                input,
 5048                push_to_lsp_host_history,
 5049                cx,
 5050            )
 5051        });
 5052        Some(cx.spawn_in(window, async move |editor, cx| {
 5053            if let Some(transaction) = on_type_formatting.await? {
 5054                if push_to_client_history {
 5055                    buffer
 5056                        .update(cx, |buffer, _| {
 5057                            buffer.push_transaction(transaction, Instant::now());
 5058                            buffer.finalize_last_transaction();
 5059                        })
 5060                        .ok();
 5061                }
 5062                editor.update(cx, |editor, cx| {
 5063                    editor.refresh_document_highlights(cx);
 5064                })?;
 5065            }
 5066            Ok(())
 5067        }))
 5068    }
 5069
 5070    pub fn show_word_completions(
 5071        &mut self,
 5072        _: &ShowWordCompletions,
 5073        window: &mut Window,
 5074        cx: &mut Context<Self>,
 5075    ) {
 5076        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5077    }
 5078
 5079    pub fn show_completions(
 5080        &mut self,
 5081        options: &ShowCompletions,
 5082        window: &mut Window,
 5083        cx: &mut Context<Self>,
 5084    ) {
 5085        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5086    }
 5087
 5088    fn open_or_update_completions_menu(
 5089        &mut self,
 5090        requested_source: Option<CompletionsMenuSource>,
 5091        trigger: Option<&str>,
 5092        window: &mut Window,
 5093        cx: &mut Context<Self>,
 5094    ) {
 5095        if self.pending_rename.is_some() {
 5096            return;
 5097        }
 5098
 5099        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5100
 5101        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5102        // inserted and selected. To handle that case, the start of the selection is used so that
 5103        // the menu starts with all choices.
 5104        let position = self
 5105            .selections
 5106            .newest_anchor()
 5107            .start
 5108            .bias_right(&multibuffer_snapshot);
 5109        if position.diff_base_anchor.is_some() {
 5110            return;
 5111        }
 5112        let (buffer, buffer_position) =
 5113            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5114                output
 5115            } else {
 5116                return;
 5117            };
 5118        let buffer_snapshot = buffer.read(cx).snapshot();
 5119
 5120        let query: Option<Arc<String>> =
 5121            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5122
 5123        drop(multibuffer_snapshot);
 5124
 5125        let provider = match requested_source {
 5126            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5127            Some(CompletionsMenuSource::Words) => None,
 5128            Some(CompletionsMenuSource::SnippetChoices) => {
 5129                log::error!("bug: SnippetChoices requested_source is not handled");
 5130                None
 5131            }
 5132        };
 5133
 5134        let sort_completions = provider
 5135            .as_ref()
 5136            .map_or(false, |provider| provider.sort_completions());
 5137
 5138        let filter_completions = provider
 5139            .as_ref()
 5140            .map_or(true, |provider| provider.filter_completions());
 5141
 5142        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5143            if filter_completions {
 5144                menu.filter(query.clone(), provider.clone(), window, cx);
 5145            }
 5146            // When `is_incomplete` is false, no need to re-query completions when the current query
 5147            // is a suffix of the initial query.
 5148            if !menu.is_incomplete {
 5149                // If the new query is a suffix of the old query (typing more characters) and
 5150                // the previous result was complete, the existing completions can be filtered.
 5151                //
 5152                // Note that this is always true for snippet completions.
 5153                let query_matches = match (&menu.initial_query, &query) {
 5154                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5155                    (None, _) => true,
 5156                    _ => false,
 5157                };
 5158                if query_matches {
 5159                    let position_matches = if menu.initial_position == position {
 5160                        true
 5161                    } else {
 5162                        let snapshot = self.buffer.read(cx).read(cx);
 5163                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5164                    };
 5165                    if position_matches {
 5166                        return;
 5167                    }
 5168                }
 5169            }
 5170        };
 5171
 5172        let trigger_kind = match trigger {
 5173            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5174                CompletionTriggerKind::TRIGGER_CHARACTER
 5175            }
 5176            _ => CompletionTriggerKind::INVOKED,
 5177        };
 5178        let completion_context = CompletionContext {
 5179            trigger_character: trigger.and_then(|trigger| {
 5180                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5181                    Some(String::from(trigger))
 5182                } else {
 5183                    None
 5184                }
 5185            }),
 5186            trigger_kind,
 5187        };
 5188
 5189        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5190            buffer_snapshot.surrounding_word(buffer_position)
 5191        {
 5192            let word_to_exclude = buffer_snapshot
 5193                .text_for_range(word_range.clone())
 5194                .collect::<String>();
 5195            (
 5196                buffer_snapshot.anchor_before(word_range.start)
 5197                    ..buffer_snapshot.anchor_after(buffer_position),
 5198                Some(word_to_exclude),
 5199            )
 5200        } else {
 5201            (buffer_position..buffer_position, None)
 5202        };
 5203
 5204        let language = buffer_snapshot
 5205            .language_at(buffer_position)
 5206            .map(|language| language.name());
 5207
 5208        let completion_settings =
 5209            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5210
 5211        let show_completion_documentation = buffer_snapshot
 5212            .settings_at(buffer_position, cx)
 5213            .show_completion_documentation;
 5214
 5215        // The document can be large, so stay in reasonable bounds when searching for words,
 5216        // otherwise completion pop-up might be slow to appear.
 5217        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5218        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5219        let min_word_search = buffer_snapshot.clip_point(
 5220            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5221            Bias::Left,
 5222        );
 5223        let max_word_search = buffer_snapshot.clip_point(
 5224            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5225            Bias::Right,
 5226        );
 5227        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5228            ..buffer_snapshot.point_to_offset(max_word_search);
 5229
 5230        let skip_digits = query
 5231            .as_ref()
 5232            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5233
 5234        let (mut words, provider_responses) = match &provider {
 5235            Some(provider) => {
 5236                let provider_responses = provider.completions(
 5237                    position.excerpt_id,
 5238                    &buffer,
 5239                    buffer_position,
 5240                    completion_context,
 5241                    window,
 5242                    cx,
 5243                );
 5244
 5245                let words = match completion_settings.words {
 5246                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5247                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5248                        .background_spawn(async move {
 5249                            buffer_snapshot.words_in_range(WordsQuery {
 5250                                fuzzy_contents: None,
 5251                                range: word_search_range,
 5252                                skip_digits,
 5253                            })
 5254                        }),
 5255                };
 5256
 5257                (words, provider_responses)
 5258            }
 5259            None => (
 5260                cx.background_spawn(async move {
 5261                    buffer_snapshot.words_in_range(WordsQuery {
 5262                        fuzzy_contents: None,
 5263                        range: word_search_range,
 5264                        skip_digits,
 5265                    })
 5266                }),
 5267                Task::ready(Ok(Vec::new())),
 5268            ),
 5269        };
 5270
 5271        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5272
 5273        let id = post_inc(&mut self.next_completion_id);
 5274        let task = cx.spawn_in(window, async move |editor, cx| {
 5275            let Ok(()) = editor.update(cx, |this, _| {
 5276                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5277            }) else {
 5278                return;
 5279            };
 5280
 5281            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5282            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5283            let mut completions = Vec::new();
 5284            let mut is_incomplete = false;
 5285            if let Some(provider_responses) = provider_responses.await.log_err() {
 5286                if !provider_responses.is_empty() {
 5287                    for response in provider_responses {
 5288                        completions.extend(response.completions);
 5289                        is_incomplete = is_incomplete || response.is_incomplete;
 5290                    }
 5291                    if completion_settings.words == WordsCompletionMode::Fallback {
 5292                        words = Task::ready(BTreeMap::default());
 5293                    }
 5294                }
 5295            }
 5296
 5297            let mut words = words.await;
 5298            if let Some(word_to_exclude) = &word_to_exclude {
 5299                words.remove(word_to_exclude);
 5300            }
 5301            for lsp_completion in &completions {
 5302                words.remove(&lsp_completion.new_text);
 5303            }
 5304            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5305                replace_range: word_replace_range.clone(),
 5306                new_text: word.clone(),
 5307                label: CodeLabel::plain(word, None),
 5308                icon_path: None,
 5309                documentation: None,
 5310                source: CompletionSource::BufferWord {
 5311                    word_range,
 5312                    resolved: false,
 5313                },
 5314                insert_text_mode: Some(InsertTextMode::AS_IS),
 5315                confirm: None,
 5316            }));
 5317
 5318            let menu = if completions.is_empty() {
 5319                None
 5320            } else {
 5321                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5322                    let languages = editor
 5323                        .workspace
 5324                        .as_ref()
 5325                        .and_then(|(workspace, _)| workspace.upgrade())
 5326                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5327                    let menu = CompletionsMenu::new(
 5328                        id,
 5329                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5330                        sort_completions,
 5331                        show_completion_documentation,
 5332                        position,
 5333                        query.clone(),
 5334                        is_incomplete,
 5335                        buffer.clone(),
 5336                        completions.into(),
 5337                        snippet_sort_order,
 5338                        languages,
 5339                        language,
 5340                        cx,
 5341                    );
 5342
 5343                    let query = if filter_completions { query } else { None };
 5344                    let matches_task = if let Some(query) = query {
 5345                        menu.do_async_filtering(query, cx)
 5346                    } else {
 5347                        Task::ready(menu.unfiltered_matches())
 5348                    };
 5349                    (menu, matches_task)
 5350                }) else {
 5351                    return;
 5352                };
 5353
 5354                let matches = matches_task.await;
 5355
 5356                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5357                    // Newer menu already set, so exit.
 5358                    match editor.context_menu.borrow().as_ref() {
 5359                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5360                            if prev_menu.id > id {
 5361                                return;
 5362                            }
 5363                        }
 5364                        _ => {}
 5365                    };
 5366
 5367                    // Only valid to take prev_menu because it the new menu is immediately set
 5368                    // below, or the menu is hidden.
 5369                    match editor.context_menu.borrow_mut().take() {
 5370                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5371                            let position_matches =
 5372                                if prev_menu.initial_position == menu.initial_position {
 5373                                    true
 5374                                } else {
 5375                                    let snapshot = editor.buffer.read(cx).read(cx);
 5376                                    prev_menu.initial_position.to_offset(&snapshot)
 5377                                        == menu.initial_position.to_offset(&snapshot)
 5378                                };
 5379                            if position_matches {
 5380                                // Preserve markdown cache before `set_filter_results` because it will
 5381                                // try to populate the documentation cache.
 5382                                menu.preserve_markdown_cache(prev_menu);
 5383                            }
 5384                        }
 5385                        _ => {}
 5386                    };
 5387
 5388                    menu.set_filter_results(matches, provider, window, cx);
 5389                }) else {
 5390                    return;
 5391                };
 5392
 5393                menu.visible().then_some(menu)
 5394            };
 5395
 5396            editor
 5397                .update_in(cx, |editor, window, cx| {
 5398                    if editor.focus_handle.is_focused(window) {
 5399                        if let Some(menu) = menu {
 5400                            *editor.context_menu.borrow_mut() =
 5401                                Some(CodeContextMenu::Completions(menu));
 5402
 5403                            crate::hover_popover::hide_hover(editor, cx);
 5404                            if editor.show_edit_predictions_in_menu() {
 5405                                editor.update_visible_inline_completion(window, cx);
 5406                            } else {
 5407                                editor.discard_inline_completion(false, cx);
 5408                            }
 5409
 5410                            cx.notify();
 5411                            return;
 5412                        }
 5413                    }
 5414
 5415                    if editor.completion_tasks.len() <= 1 {
 5416                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5417                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5418                        // If it was already hidden and we don't show inline completions in the menu, we should
 5419                        // also show the inline-completion when available.
 5420                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5421                            editor.update_visible_inline_completion(window, cx);
 5422                        }
 5423                    }
 5424                })
 5425                .ok();
 5426        });
 5427
 5428        self.completion_tasks.push((id, task));
 5429    }
 5430
 5431    #[cfg(feature = "test-support")]
 5432    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5433        let menu = self.context_menu.borrow();
 5434        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5435            let completions = menu.completions.borrow();
 5436            Some(completions.to_vec())
 5437        } else {
 5438            None
 5439        }
 5440    }
 5441
 5442    pub fn with_completions_menu_matching_id<R>(
 5443        &self,
 5444        id: CompletionId,
 5445        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5446    ) -> R {
 5447        let mut context_menu = self.context_menu.borrow_mut();
 5448        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5449            return f(None);
 5450        };
 5451        if completions_menu.id != id {
 5452            return f(None);
 5453        }
 5454        f(Some(completions_menu))
 5455    }
 5456
 5457    pub fn confirm_completion(
 5458        &mut self,
 5459        action: &ConfirmCompletion,
 5460        window: &mut Window,
 5461        cx: &mut Context<Self>,
 5462    ) -> Option<Task<Result<()>>> {
 5463        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5464        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5465    }
 5466
 5467    pub fn confirm_completion_insert(
 5468        &mut self,
 5469        _: &ConfirmCompletionInsert,
 5470        window: &mut Window,
 5471        cx: &mut Context<Self>,
 5472    ) -> Option<Task<Result<()>>> {
 5473        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5474        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5475    }
 5476
 5477    pub fn confirm_completion_replace(
 5478        &mut self,
 5479        _: &ConfirmCompletionReplace,
 5480        window: &mut Window,
 5481        cx: &mut Context<Self>,
 5482    ) -> Option<Task<Result<()>>> {
 5483        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5484        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5485    }
 5486
 5487    pub fn compose_completion(
 5488        &mut self,
 5489        action: &ComposeCompletion,
 5490        window: &mut Window,
 5491        cx: &mut Context<Self>,
 5492    ) -> Option<Task<Result<()>>> {
 5493        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5494        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5495    }
 5496
 5497    fn do_completion(
 5498        &mut self,
 5499        item_ix: Option<usize>,
 5500        intent: CompletionIntent,
 5501        window: &mut Window,
 5502        cx: &mut Context<Editor>,
 5503    ) -> Option<Task<Result<()>>> {
 5504        use language::ToOffset as _;
 5505
 5506        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5507        else {
 5508            return None;
 5509        };
 5510
 5511        let candidate_id = {
 5512            let entries = completions_menu.entries.borrow();
 5513            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5514            if self.show_edit_predictions_in_menu() {
 5515                self.discard_inline_completion(true, cx);
 5516            }
 5517            mat.candidate_id
 5518        };
 5519
 5520        let completion = completions_menu
 5521            .completions
 5522            .borrow()
 5523            .get(candidate_id)?
 5524            .clone();
 5525        cx.stop_propagation();
 5526
 5527        let buffer_handle = completions_menu.buffer.clone();
 5528
 5529        let CompletionEdit {
 5530            new_text,
 5531            snippet,
 5532            replace_range,
 5533        } = process_completion_for_edit(
 5534            &completion,
 5535            intent,
 5536            &buffer_handle,
 5537            &completions_menu.initial_position.text_anchor,
 5538            cx,
 5539        );
 5540
 5541        let buffer = buffer_handle.read(cx);
 5542        let snapshot = self.buffer.read(cx).snapshot(cx);
 5543        let newest_anchor = self.selections.newest_anchor();
 5544        let replace_range_multibuffer = {
 5545            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5546            let multibuffer_anchor = snapshot
 5547                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5548                .unwrap()
 5549                ..snapshot
 5550                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5551                    .unwrap();
 5552            multibuffer_anchor.start.to_offset(&snapshot)
 5553                ..multibuffer_anchor.end.to_offset(&snapshot)
 5554        };
 5555        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5556            return None;
 5557        }
 5558
 5559        let old_text = buffer
 5560            .text_for_range(replace_range.clone())
 5561            .collect::<String>();
 5562        let lookbehind = newest_anchor
 5563            .start
 5564            .text_anchor
 5565            .to_offset(buffer)
 5566            .saturating_sub(replace_range.start);
 5567        let lookahead = replace_range
 5568            .end
 5569            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5570        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5571        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5572
 5573        let selections = self.selections.all::<usize>(cx);
 5574        let mut ranges = Vec::new();
 5575        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5576
 5577        for selection in &selections {
 5578            let range = if selection.id == newest_anchor.id {
 5579                replace_range_multibuffer.clone()
 5580            } else {
 5581                let mut range = selection.range();
 5582
 5583                // if prefix is present, don't duplicate it
 5584                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5585                    range.start = range.start.saturating_sub(lookbehind);
 5586
 5587                    // if suffix is also present, mimic the newest cursor and replace it
 5588                    if selection.id != newest_anchor.id
 5589                        && snapshot.contains_str_at(range.end, suffix)
 5590                    {
 5591                        range.end += lookahead;
 5592                    }
 5593                }
 5594                range
 5595            };
 5596
 5597            ranges.push(range.clone());
 5598
 5599            if !self.linked_edit_ranges.is_empty() {
 5600                let start_anchor = snapshot.anchor_before(range.start);
 5601                let end_anchor = snapshot.anchor_after(range.end);
 5602                if let Some(ranges) = self
 5603                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5604                {
 5605                    for (buffer, edits) in ranges {
 5606                        linked_edits
 5607                            .entry(buffer.clone())
 5608                            .or_default()
 5609                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5610                    }
 5611                }
 5612            }
 5613        }
 5614
 5615        let common_prefix_len = old_text
 5616            .chars()
 5617            .zip(new_text.chars())
 5618            .take_while(|(a, b)| a == b)
 5619            .map(|(a, _)| a.len_utf8())
 5620            .sum::<usize>();
 5621
 5622        cx.emit(EditorEvent::InputHandled {
 5623            utf16_range_to_replace: None,
 5624            text: new_text[common_prefix_len..].into(),
 5625        });
 5626
 5627        self.transact(window, cx, |this, window, cx| {
 5628            if let Some(mut snippet) = snippet {
 5629                snippet.text = new_text.to_string();
 5630                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5631            } else {
 5632                this.buffer.update(cx, |buffer, cx| {
 5633                    let auto_indent = match completion.insert_text_mode {
 5634                        Some(InsertTextMode::AS_IS) => None,
 5635                        _ => this.autoindent_mode.clone(),
 5636                    };
 5637                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5638                    buffer.edit(edits, auto_indent, cx);
 5639                });
 5640            }
 5641            for (buffer, edits) in linked_edits {
 5642                buffer.update(cx, |buffer, cx| {
 5643                    let snapshot = buffer.snapshot();
 5644                    let edits = edits
 5645                        .into_iter()
 5646                        .map(|(range, text)| {
 5647                            use text::ToPoint as TP;
 5648                            let end_point = TP::to_point(&range.end, &snapshot);
 5649                            let start_point = TP::to_point(&range.start, &snapshot);
 5650                            (start_point..end_point, text)
 5651                        })
 5652                        .sorted_by_key(|(range, _)| range.start);
 5653                    buffer.edit(edits, None, cx);
 5654                })
 5655            }
 5656
 5657            this.refresh_inline_completion(true, false, window, cx);
 5658        });
 5659
 5660        let show_new_completions_on_confirm = completion
 5661            .confirm
 5662            .as_ref()
 5663            .map_or(false, |confirm| confirm(intent, window, cx));
 5664        if show_new_completions_on_confirm {
 5665            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5666        }
 5667
 5668        let provider = self.completion_provider.as_ref()?;
 5669        drop(completion);
 5670        let apply_edits = provider.apply_additional_edits_for_completion(
 5671            buffer_handle,
 5672            completions_menu.completions.clone(),
 5673            candidate_id,
 5674            true,
 5675            cx,
 5676        );
 5677
 5678        let editor_settings = EditorSettings::get_global(cx);
 5679        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5680            // After the code completion is finished, users often want to know what signatures are needed.
 5681            // so we should automatically call signature_help
 5682            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5683        }
 5684
 5685        Some(cx.foreground_executor().spawn(async move {
 5686            apply_edits.await?;
 5687            Ok(())
 5688        }))
 5689    }
 5690
 5691    pub fn toggle_code_actions(
 5692        &mut self,
 5693        action: &ToggleCodeActions,
 5694        window: &mut Window,
 5695        cx: &mut Context<Self>,
 5696    ) {
 5697        let quick_launch = action.quick_launch;
 5698        let mut context_menu = self.context_menu.borrow_mut();
 5699        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5700            if code_actions.deployed_from == action.deployed_from {
 5701                // Toggle if we're selecting the same one
 5702                *context_menu = None;
 5703                cx.notify();
 5704                return;
 5705            } else {
 5706                // Otherwise, clear it and start a new one
 5707                *context_menu = None;
 5708                cx.notify();
 5709            }
 5710        }
 5711        drop(context_menu);
 5712        let snapshot = self.snapshot(window, cx);
 5713        let deployed_from = action.deployed_from.clone();
 5714        let action = action.clone();
 5715        self.completion_tasks.clear();
 5716        self.discard_inline_completion(false, cx);
 5717
 5718        let multibuffer_point = match &action.deployed_from {
 5719            Some(CodeActionSource::Indicator(row)) => {
 5720                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5721            }
 5722            _ => self.selections.newest::<Point>(cx).head(),
 5723        };
 5724        let Some((buffer, buffer_row)) = snapshot
 5725            .buffer_snapshot
 5726            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5727            .and_then(|(buffer_snapshot, range)| {
 5728                self.buffer()
 5729                    .read(cx)
 5730                    .buffer(buffer_snapshot.remote_id())
 5731                    .map(|buffer| (buffer, range.start.row))
 5732            })
 5733        else {
 5734            return;
 5735        };
 5736        let buffer_id = buffer.read(cx).remote_id();
 5737        let tasks = self
 5738            .tasks
 5739            .get(&(buffer_id, buffer_row))
 5740            .map(|t| Arc::new(t.to_owned()));
 5741
 5742        if !self.focus_handle.is_focused(window) {
 5743            return;
 5744        }
 5745        let project = self.project.clone();
 5746
 5747        let code_actions_task = match deployed_from {
 5748            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5749            _ => self.code_actions(buffer_row, window, cx),
 5750        };
 5751
 5752        let runnable_task = match deployed_from {
 5753            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5754            _ => {
 5755                let mut task_context_task = Task::ready(None);
 5756                if let Some(tasks) = &tasks {
 5757                    if let Some(project) = project {
 5758                        task_context_task =
 5759                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5760                    }
 5761                }
 5762
 5763                cx.spawn_in(window, {
 5764                    let buffer = buffer.clone();
 5765                    async move |editor, cx| {
 5766                        let task_context = task_context_task.await;
 5767
 5768                        let resolved_tasks =
 5769                            tasks
 5770                                .zip(task_context.clone())
 5771                                .map(|(tasks, task_context)| ResolvedTasks {
 5772                                    templates: tasks.resolve(&task_context).collect(),
 5773                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5774                                        multibuffer_point.row,
 5775                                        tasks.column,
 5776                                    )),
 5777                                });
 5778                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5779                            editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5780                        })?;
 5781                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5782                    }
 5783                })
 5784            }
 5785        };
 5786
 5787        cx.spawn_in(window, async move |editor, cx| {
 5788            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5789            let code_actions = code_actions_task.await;
 5790            let spawn_straight_away = quick_launch
 5791                && resolved_tasks
 5792                    .as_ref()
 5793                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5794                && code_actions
 5795                    .as_ref()
 5796                    .map_or(true, |actions| actions.is_empty())
 5797                && debug_scenarios.is_empty();
 5798
 5799            editor.update_in(cx, |editor, window, cx| {
 5800                crate::hover_popover::hide_hover(editor, cx);
 5801                *editor.context_menu.borrow_mut() =
 5802                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5803                        buffer,
 5804                        actions: CodeActionContents::new(
 5805                            resolved_tasks,
 5806                            code_actions,
 5807                            debug_scenarios,
 5808                            task_context.unwrap_or_default(),
 5809                        ),
 5810                        selected_item: Default::default(),
 5811                        scroll_handle: UniformListScrollHandle::default(),
 5812                        deployed_from,
 5813                    }));
 5814                if spawn_straight_away {
 5815                    if let Some(task) = editor.confirm_code_action(
 5816                        &ConfirmCodeAction { item_ix: Some(0) },
 5817                        window,
 5818                        cx,
 5819                    ) {
 5820                        cx.notify();
 5821                        return task;
 5822                    }
 5823                }
 5824
 5825                Task::ready(Ok(()))
 5826            })
 5827        })
 5828        .detach_and_log_err(cx);
 5829    }
 5830
 5831    fn debug_scenarios(
 5832        &mut self,
 5833        resolved_tasks: &Option<ResolvedTasks>,
 5834        buffer: &Entity<Buffer>,
 5835        cx: &mut App,
 5836    ) -> Vec<task::DebugScenario> {
 5837        if cx.has_flag::<DebuggerFeatureFlag>() {
 5838            maybe!({
 5839                let project = self.project.as_ref()?;
 5840                let dap_store = project.read(cx).dap_store();
 5841                let mut scenarios = vec![];
 5842                let resolved_tasks = resolved_tasks.as_ref()?;
 5843                let buffer = buffer.read(cx);
 5844                let language = buffer.language()?;
 5845                let file = buffer.file();
 5846                let debug_adapter = language_settings(language.name().into(), file, cx)
 5847                    .debuggers
 5848                    .first()
 5849                    .map(SharedString::from)
 5850                    .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 5851
 5852                dap_store.update(cx, |dap_store, cx| {
 5853                    for (_, task) in &resolved_tasks.templates {
 5854                        if let Some(scenario) = dap_store.debug_scenario_for_build_task(
 5855                            task.original_task().clone(),
 5856                            debug_adapter.clone().into(),
 5857                            task.display_label().to_owned().into(),
 5858                            cx,
 5859                        ) {
 5860                            scenarios.push(scenario);
 5861                        }
 5862                    }
 5863                });
 5864                Some(scenarios)
 5865            })
 5866            .unwrap_or_default()
 5867        } else {
 5868            vec![]
 5869        }
 5870    }
 5871
 5872    fn code_actions(
 5873        &mut self,
 5874        buffer_row: u32,
 5875        window: &mut Window,
 5876        cx: &mut Context<Self>,
 5877    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 5878        let mut task = self.code_actions_task.take();
 5879        cx.spawn_in(window, async move |editor, cx| {
 5880            while let Some(prev_task) = task {
 5881                prev_task.await.log_err();
 5882                task = editor
 5883                    .update(cx, |this, _| this.code_actions_task.take())
 5884                    .ok()?;
 5885            }
 5886
 5887            editor
 5888                .update(cx, |editor, cx| {
 5889                    editor
 5890                        .available_code_actions
 5891                        .clone()
 5892                        .and_then(|(location, code_actions)| {
 5893                            let snapshot = location.buffer.read(cx).snapshot();
 5894                            let point_range = location.range.to_point(&snapshot);
 5895                            let point_range = point_range.start.row..=point_range.end.row;
 5896                            if point_range.contains(&buffer_row) {
 5897                                Some(code_actions)
 5898                            } else {
 5899                                None
 5900                            }
 5901                        })
 5902                })
 5903                .ok()
 5904                .flatten()
 5905        })
 5906    }
 5907
 5908    pub fn confirm_code_action(
 5909        &mut self,
 5910        action: &ConfirmCodeAction,
 5911        window: &mut Window,
 5912        cx: &mut Context<Self>,
 5913    ) -> Option<Task<Result<()>>> {
 5914        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5915
 5916        let actions_menu =
 5917            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5918                menu
 5919            } else {
 5920                return None;
 5921            };
 5922
 5923        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5924        let action = actions_menu.actions.get(action_ix)?;
 5925        let title = action.label();
 5926        let buffer = actions_menu.buffer;
 5927        let workspace = self.workspace()?;
 5928
 5929        match action {
 5930            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5931                workspace.update(cx, |workspace, cx| {
 5932                    workspace.schedule_resolved_task(
 5933                        task_source_kind,
 5934                        resolved_task,
 5935                        false,
 5936                        window,
 5937                        cx,
 5938                    );
 5939
 5940                    Some(Task::ready(Ok(())))
 5941                })
 5942            }
 5943            CodeActionsItem::CodeAction {
 5944                excerpt_id,
 5945                action,
 5946                provider,
 5947            } => {
 5948                let apply_code_action =
 5949                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5950                let workspace = workspace.downgrade();
 5951                Some(cx.spawn_in(window, async move |editor, cx| {
 5952                    let project_transaction = apply_code_action.await?;
 5953                    Self::open_project_transaction(
 5954                        &editor,
 5955                        workspace,
 5956                        project_transaction,
 5957                        title,
 5958                        cx,
 5959                    )
 5960                    .await
 5961                }))
 5962            }
 5963            CodeActionsItem::DebugScenario(scenario) => {
 5964                let context = actions_menu.actions.context.clone();
 5965
 5966                workspace.update(cx, |workspace, cx| {
 5967                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5968                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5969                });
 5970                Some(Task::ready(Ok(())))
 5971            }
 5972        }
 5973    }
 5974
 5975    pub async fn open_project_transaction(
 5976        this: &WeakEntity<Editor>,
 5977        workspace: WeakEntity<Workspace>,
 5978        transaction: ProjectTransaction,
 5979        title: String,
 5980        cx: &mut AsyncWindowContext,
 5981    ) -> Result<()> {
 5982        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5983        cx.update(|_, cx| {
 5984            entries.sort_unstable_by_key(|(buffer, _)| {
 5985                buffer.read(cx).file().map(|f| f.path().clone())
 5986            });
 5987        })?;
 5988
 5989        // If the project transaction's edits are all contained within this editor, then
 5990        // avoid opening a new editor to display them.
 5991
 5992        if let Some((buffer, transaction)) = entries.first() {
 5993            if entries.len() == 1 {
 5994                let excerpt = this.update(cx, |editor, cx| {
 5995                    editor
 5996                        .buffer()
 5997                        .read(cx)
 5998                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5999                })?;
 6000                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6001                    if excerpted_buffer == *buffer {
 6002                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6003                            let excerpt_range = excerpt_range.to_offset(buffer);
 6004                            buffer
 6005                                .edited_ranges_for_transaction::<usize>(transaction)
 6006                                .all(|range| {
 6007                                    excerpt_range.start <= range.start
 6008                                        && excerpt_range.end >= range.end
 6009                                })
 6010                        })?;
 6011
 6012                        if all_edits_within_excerpt {
 6013                            return Ok(());
 6014                        }
 6015                    }
 6016                }
 6017            }
 6018        } else {
 6019            return Ok(());
 6020        }
 6021
 6022        let mut ranges_to_highlight = Vec::new();
 6023        let excerpt_buffer = cx.new(|cx| {
 6024            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6025            for (buffer_handle, transaction) in &entries {
 6026                let edited_ranges = buffer_handle
 6027                    .read(cx)
 6028                    .edited_ranges_for_transaction::<Point>(transaction)
 6029                    .collect::<Vec<_>>();
 6030                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6031                    PathKey::for_buffer(buffer_handle, cx),
 6032                    buffer_handle.clone(),
 6033                    edited_ranges,
 6034                    DEFAULT_MULTIBUFFER_CONTEXT,
 6035                    cx,
 6036                );
 6037
 6038                ranges_to_highlight.extend(ranges);
 6039            }
 6040            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6041            multibuffer
 6042        })?;
 6043
 6044        workspace.update_in(cx, |workspace, window, cx| {
 6045            let project = workspace.project().clone();
 6046            let editor =
 6047                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6048            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6049            editor.update(cx, |editor, cx| {
 6050                editor.highlight_background::<Self>(
 6051                    &ranges_to_highlight,
 6052                    |theme| theme.editor_highlighted_line_background,
 6053                    cx,
 6054                );
 6055            });
 6056        })?;
 6057
 6058        Ok(())
 6059    }
 6060
 6061    pub fn clear_code_action_providers(&mut self) {
 6062        self.code_action_providers.clear();
 6063        self.available_code_actions.take();
 6064    }
 6065
 6066    pub fn add_code_action_provider(
 6067        &mut self,
 6068        provider: Rc<dyn CodeActionProvider>,
 6069        window: &mut Window,
 6070        cx: &mut Context<Self>,
 6071    ) {
 6072        if self
 6073            .code_action_providers
 6074            .iter()
 6075            .any(|existing_provider| existing_provider.id() == provider.id())
 6076        {
 6077            return;
 6078        }
 6079
 6080        self.code_action_providers.push(provider);
 6081        self.refresh_code_actions(window, cx);
 6082    }
 6083
 6084    pub fn remove_code_action_provider(
 6085        &mut self,
 6086        id: Arc<str>,
 6087        window: &mut Window,
 6088        cx: &mut Context<Self>,
 6089    ) {
 6090        self.code_action_providers
 6091            .retain(|provider| provider.id() != id);
 6092        self.refresh_code_actions(window, cx);
 6093    }
 6094
 6095    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6096        !self.code_action_providers.is_empty()
 6097            && EditorSettings::get_global(cx).toolbar.code_actions
 6098    }
 6099
 6100    pub fn has_available_code_actions(&self) -> bool {
 6101        self.available_code_actions
 6102            .as_ref()
 6103            .is_some_and(|(_, actions)| !actions.is_empty())
 6104    }
 6105
 6106    fn render_inline_code_actions(
 6107        &self,
 6108        icon_size: ui::IconSize,
 6109        display_row: DisplayRow,
 6110        is_active: bool,
 6111        cx: &mut Context<Self>,
 6112    ) -> AnyElement {
 6113        let show_tooltip = !self.context_menu_visible();
 6114        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6115            .icon_size(icon_size)
 6116            .shape(ui::IconButtonShape::Square)
 6117            .style(ButtonStyle::Transparent)
 6118            .icon_color(ui::Color::Hidden)
 6119            .toggle_state(is_active)
 6120            .when(show_tooltip, |this| {
 6121                this.tooltip({
 6122                    let focus_handle = self.focus_handle.clone();
 6123                    move |window, cx| {
 6124                        Tooltip::for_action_in(
 6125                            "Toggle Code Actions",
 6126                            &ToggleCodeActions {
 6127                                deployed_from: None,
 6128                                quick_launch: false,
 6129                            },
 6130                            &focus_handle,
 6131                            window,
 6132                            cx,
 6133                        )
 6134                    }
 6135                })
 6136            })
 6137            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6138                window.focus(&editor.focus_handle(cx));
 6139                editor.toggle_code_actions(
 6140                    &crate::actions::ToggleCodeActions {
 6141                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6142                            display_row,
 6143                        )),
 6144                        quick_launch: false,
 6145                    },
 6146                    window,
 6147                    cx,
 6148                );
 6149            }))
 6150            .into_any_element()
 6151    }
 6152
 6153    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6154        &self.context_menu
 6155    }
 6156
 6157    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6158        let newest_selection = self.selections.newest_anchor().clone();
 6159        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6160        let buffer = self.buffer.read(cx);
 6161        if newest_selection.head().diff_base_anchor.is_some() {
 6162            return None;
 6163        }
 6164        let (start_buffer, start) =
 6165            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6166        let (end_buffer, end) =
 6167            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6168        if start_buffer != end_buffer {
 6169            return None;
 6170        }
 6171
 6172        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6173            cx.background_executor()
 6174                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6175                .await;
 6176
 6177            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6178                let providers = this.code_action_providers.clone();
 6179                let tasks = this
 6180                    .code_action_providers
 6181                    .iter()
 6182                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6183                    .collect::<Vec<_>>();
 6184                (providers, tasks)
 6185            })?;
 6186
 6187            let mut actions = Vec::new();
 6188            for (provider, provider_actions) in
 6189                providers.into_iter().zip(future::join_all(tasks).await)
 6190            {
 6191                if let Some(provider_actions) = provider_actions.log_err() {
 6192                    actions.extend(provider_actions.into_iter().map(|action| {
 6193                        AvailableCodeAction {
 6194                            excerpt_id: newest_selection.start.excerpt_id,
 6195                            action,
 6196                            provider: provider.clone(),
 6197                        }
 6198                    }));
 6199                }
 6200            }
 6201
 6202            this.update(cx, |this, cx| {
 6203                this.available_code_actions = if actions.is_empty() {
 6204                    None
 6205                } else {
 6206                    Some((
 6207                        Location {
 6208                            buffer: start_buffer,
 6209                            range: start..end,
 6210                        },
 6211                        actions.into(),
 6212                    ))
 6213                };
 6214                cx.notify();
 6215            })
 6216        }));
 6217        None
 6218    }
 6219
 6220    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6221        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6222            self.show_git_blame_inline = false;
 6223
 6224            self.show_git_blame_inline_delay_task =
 6225                Some(cx.spawn_in(window, async move |this, cx| {
 6226                    cx.background_executor().timer(delay).await;
 6227
 6228                    this.update(cx, |this, cx| {
 6229                        this.show_git_blame_inline = true;
 6230                        cx.notify();
 6231                    })
 6232                    .log_err();
 6233                }));
 6234        }
 6235    }
 6236
 6237    fn show_blame_popover(
 6238        &mut self,
 6239        blame_entry: &BlameEntry,
 6240        position: gpui::Point<Pixels>,
 6241        cx: &mut Context<Self>,
 6242    ) {
 6243        if let Some(state) = &mut self.inline_blame_popover {
 6244            state.hide_task.take();
 6245            cx.notify();
 6246        } else {
 6247            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6248            let show_task = cx.spawn(async move |editor, cx| {
 6249                cx.background_executor()
 6250                    .timer(std::time::Duration::from_millis(delay))
 6251                    .await;
 6252                editor
 6253                    .update(cx, |editor, cx| {
 6254                        if let Some(state) = &mut editor.inline_blame_popover {
 6255                            state.show_task = None;
 6256                            cx.notify();
 6257                        }
 6258                    })
 6259                    .ok();
 6260            });
 6261            let Some(blame) = self.blame.as_ref() else {
 6262                return;
 6263            };
 6264            let blame = blame.read(cx);
 6265            let details = blame.details_for_entry(&blame_entry);
 6266            let markdown = cx.new(|cx| {
 6267                Markdown::new(
 6268                    details
 6269                        .as_ref()
 6270                        .map(|message| message.message.clone())
 6271                        .unwrap_or_default(),
 6272                    None,
 6273                    None,
 6274                    cx,
 6275                )
 6276            });
 6277            self.inline_blame_popover = Some(InlineBlamePopover {
 6278                position,
 6279                show_task: Some(show_task),
 6280                hide_task: None,
 6281                popover_bounds: None,
 6282                popover_state: InlineBlamePopoverState {
 6283                    scroll_handle: ScrollHandle::new(),
 6284                    commit_message: details,
 6285                    markdown,
 6286                },
 6287            });
 6288        }
 6289    }
 6290
 6291    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6292        if let Some(state) = &mut self.inline_blame_popover {
 6293            if state.show_task.is_some() {
 6294                self.inline_blame_popover.take();
 6295                cx.notify();
 6296            } else {
 6297                let hide_task = cx.spawn(async move |editor, cx| {
 6298                    cx.background_executor()
 6299                        .timer(std::time::Duration::from_millis(100))
 6300                        .await;
 6301                    editor
 6302                        .update(cx, |editor, cx| {
 6303                            editor.inline_blame_popover.take();
 6304                            cx.notify();
 6305                        })
 6306                        .ok();
 6307                });
 6308                state.hide_task = Some(hide_task);
 6309            }
 6310        }
 6311    }
 6312
 6313    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6314        if self.pending_rename.is_some() {
 6315            return None;
 6316        }
 6317
 6318        let provider = self.semantics_provider.clone()?;
 6319        let buffer = self.buffer.read(cx);
 6320        let newest_selection = self.selections.newest_anchor().clone();
 6321        let cursor_position = newest_selection.head();
 6322        let (cursor_buffer, cursor_buffer_position) =
 6323            buffer.text_anchor_for_position(cursor_position, cx)?;
 6324        let (tail_buffer, tail_buffer_position) =
 6325            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6326        if cursor_buffer != tail_buffer {
 6327            return None;
 6328        }
 6329
 6330        let snapshot = cursor_buffer.read(cx).snapshot();
 6331        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6332        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6333        if start_word_range != end_word_range {
 6334            self.document_highlights_task.take();
 6335            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6336            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6337            return None;
 6338        }
 6339
 6340        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6341        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6342            cx.background_executor()
 6343                .timer(Duration::from_millis(debounce))
 6344                .await;
 6345
 6346            let highlights = if let Some(highlights) = cx
 6347                .update(|cx| {
 6348                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6349                })
 6350                .ok()
 6351                .flatten()
 6352            {
 6353                highlights.await.log_err()
 6354            } else {
 6355                None
 6356            };
 6357
 6358            if let Some(highlights) = highlights {
 6359                this.update(cx, |this, cx| {
 6360                    if this.pending_rename.is_some() {
 6361                        return;
 6362                    }
 6363
 6364                    let buffer_id = cursor_position.buffer_id;
 6365                    let buffer = this.buffer.read(cx);
 6366                    if !buffer
 6367                        .text_anchor_for_position(cursor_position, cx)
 6368                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6369                    {
 6370                        return;
 6371                    }
 6372
 6373                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6374                    let mut write_ranges = Vec::new();
 6375                    let mut read_ranges = Vec::new();
 6376                    for highlight in highlights {
 6377                        for (excerpt_id, excerpt_range) in
 6378                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6379                        {
 6380                            let start = highlight
 6381                                .range
 6382                                .start
 6383                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6384                            let end = highlight
 6385                                .range
 6386                                .end
 6387                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6388                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6389                                continue;
 6390                            }
 6391
 6392                            let range = Anchor {
 6393                                buffer_id,
 6394                                excerpt_id,
 6395                                text_anchor: start,
 6396                                diff_base_anchor: None,
 6397                            }..Anchor {
 6398                                buffer_id,
 6399                                excerpt_id,
 6400                                text_anchor: end,
 6401                                diff_base_anchor: None,
 6402                            };
 6403                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6404                                write_ranges.push(range);
 6405                            } else {
 6406                                read_ranges.push(range);
 6407                            }
 6408                        }
 6409                    }
 6410
 6411                    this.highlight_background::<DocumentHighlightRead>(
 6412                        &read_ranges,
 6413                        |theme| theme.editor_document_highlight_read_background,
 6414                        cx,
 6415                    );
 6416                    this.highlight_background::<DocumentHighlightWrite>(
 6417                        &write_ranges,
 6418                        |theme| theme.editor_document_highlight_write_background,
 6419                        cx,
 6420                    );
 6421                    cx.notify();
 6422                })
 6423                .log_err();
 6424            }
 6425        }));
 6426        None
 6427    }
 6428
 6429    fn prepare_highlight_query_from_selection(
 6430        &mut self,
 6431        cx: &mut Context<Editor>,
 6432    ) -> Option<(String, Range<Anchor>)> {
 6433        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6434            return None;
 6435        }
 6436        if !EditorSettings::get_global(cx).selection_highlight {
 6437            return None;
 6438        }
 6439        if self.selections.count() != 1 || self.selections.line_mode {
 6440            return None;
 6441        }
 6442        let selection = self.selections.newest::<Point>(cx);
 6443        if selection.is_empty() || selection.start.row != selection.end.row {
 6444            return None;
 6445        }
 6446        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6447        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6448        let query = multi_buffer_snapshot
 6449            .text_for_range(selection_anchor_range.clone())
 6450            .collect::<String>();
 6451        if query.trim().is_empty() {
 6452            return None;
 6453        }
 6454        Some((query, selection_anchor_range))
 6455    }
 6456
 6457    fn update_selection_occurrence_highlights(
 6458        &mut self,
 6459        query_text: String,
 6460        query_range: Range<Anchor>,
 6461        multi_buffer_range_to_query: Range<Point>,
 6462        use_debounce: bool,
 6463        window: &mut Window,
 6464        cx: &mut Context<Editor>,
 6465    ) -> Task<()> {
 6466        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6467        cx.spawn_in(window, async move |editor, cx| {
 6468            if use_debounce {
 6469                cx.background_executor()
 6470                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6471                    .await;
 6472            }
 6473            let match_task = cx.background_spawn(async move {
 6474                let buffer_ranges = multi_buffer_snapshot
 6475                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6476                    .into_iter()
 6477                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6478                let mut match_ranges = Vec::new();
 6479                let Ok(regex) = project::search::SearchQuery::text(
 6480                    query_text.clone(),
 6481                    false,
 6482                    false,
 6483                    false,
 6484                    Default::default(),
 6485                    Default::default(),
 6486                    false,
 6487                    None,
 6488                ) else {
 6489                    return Vec::default();
 6490                };
 6491                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6492                    match_ranges.extend(
 6493                        regex
 6494                            .search(&buffer_snapshot, Some(search_range.clone()))
 6495                            .await
 6496                            .into_iter()
 6497                            .filter_map(|match_range| {
 6498                                let match_start = buffer_snapshot
 6499                                    .anchor_after(search_range.start + match_range.start);
 6500                                let match_end = buffer_snapshot
 6501                                    .anchor_before(search_range.start + match_range.end);
 6502                                let match_anchor_range = Anchor::range_in_buffer(
 6503                                    excerpt_id,
 6504                                    buffer_snapshot.remote_id(),
 6505                                    match_start..match_end,
 6506                                );
 6507                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6508                            }),
 6509                    );
 6510                }
 6511                match_ranges
 6512            });
 6513            let match_ranges = match_task.await;
 6514            editor
 6515                .update_in(cx, |editor, _, cx| {
 6516                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6517                    if !match_ranges.is_empty() {
 6518                        editor.highlight_background::<SelectedTextHighlight>(
 6519                            &match_ranges,
 6520                            |theme| theme.editor_document_highlight_bracket_background,
 6521                            cx,
 6522                        )
 6523                    }
 6524                })
 6525                .log_err();
 6526        })
 6527    }
 6528
 6529    fn refresh_selected_text_highlights(
 6530        &mut self,
 6531        on_buffer_edit: bool,
 6532        window: &mut Window,
 6533        cx: &mut Context<Editor>,
 6534    ) {
 6535        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6536        else {
 6537            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6538            self.quick_selection_highlight_task.take();
 6539            self.debounced_selection_highlight_task.take();
 6540            return;
 6541        };
 6542        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6543        if on_buffer_edit
 6544            || self
 6545                .quick_selection_highlight_task
 6546                .as_ref()
 6547                .map_or(true, |(prev_anchor_range, _)| {
 6548                    prev_anchor_range != &query_range
 6549                })
 6550        {
 6551            let multi_buffer_visible_start = self
 6552                .scroll_manager
 6553                .anchor()
 6554                .anchor
 6555                .to_point(&multi_buffer_snapshot);
 6556            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6557                multi_buffer_visible_start
 6558                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6559                Bias::Left,
 6560            );
 6561            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6562            self.quick_selection_highlight_task = Some((
 6563                query_range.clone(),
 6564                self.update_selection_occurrence_highlights(
 6565                    query_text.clone(),
 6566                    query_range.clone(),
 6567                    multi_buffer_visible_range,
 6568                    false,
 6569                    window,
 6570                    cx,
 6571                ),
 6572            ));
 6573        }
 6574        if on_buffer_edit
 6575            || self
 6576                .debounced_selection_highlight_task
 6577                .as_ref()
 6578                .map_or(true, |(prev_anchor_range, _)| {
 6579                    prev_anchor_range != &query_range
 6580                })
 6581        {
 6582            let multi_buffer_start = multi_buffer_snapshot
 6583                .anchor_before(0)
 6584                .to_point(&multi_buffer_snapshot);
 6585            let multi_buffer_end = multi_buffer_snapshot
 6586                .anchor_after(multi_buffer_snapshot.len())
 6587                .to_point(&multi_buffer_snapshot);
 6588            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6589            self.debounced_selection_highlight_task = Some((
 6590                query_range.clone(),
 6591                self.update_selection_occurrence_highlights(
 6592                    query_text,
 6593                    query_range,
 6594                    multi_buffer_full_range,
 6595                    true,
 6596                    window,
 6597                    cx,
 6598                ),
 6599            ));
 6600        }
 6601    }
 6602
 6603    pub fn refresh_inline_completion(
 6604        &mut self,
 6605        debounce: bool,
 6606        user_requested: bool,
 6607        window: &mut Window,
 6608        cx: &mut Context<Self>,
 6609    ) -> Option<()> {
 6610        let provider = self.edit_prediction_provider()?;
 6611        let cursor = self.selections.newest_anchor().head();
 6612        let (buffer, cursor_buffer_position) =
 6613            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6614
 6615        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6616            self.discard_inline_completion(false, cx);
 6617            return None;
 6618        }
 6619
 6620        if !user_requested
 6621            && (!self.should_show_edit_predictions()
 6622                || !self.is_focused(window)
 6623                || buffer.read(cx).is_empty())
 6624        {
 6625            self.discard_inline_completion(false, cx);
 6626            return None;
 6627        }
 6628
 6629        self.update_visible_inline_completion(window, cx);
 6630        provider.refresh(
 6631            self.project.clone(),
 6632            buffer,
 6633            cursor_buffer_position,
 6634            debounce,
 6635            cx,
 6636        );
 6637        Some(())
 6638    }
 6639
 6640    fn show_edit_predictions_in_menu(&self) -> bool {
 6641        match self.edit_prediction_settings {
 6642            EditPredictionSettings::Disabled => false,
 6643            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6644        }
 6645    }
 6646
 6647    pub fn edit_predictions_enabled(&self) -> bool {
 6648        match self.edit_prediction_settings {
 6649            EditPredictionSettings::Disabled => false,
 6650            EditPredictionSettings::Enabled { .. } => true,
 6651        }
 6652    }
 6653
 6654    fn edit_prediction_requires_modifier(&self) -> bool {
 6655        match self.edit_prediction_settings {
 6656            EditPredictionSettings::Disabled => false,
 6657            EditPredictionSettings::Enabled {
 6658                preview_requires_modifier,
 6659                ..
 6660            } => preview_requires_modifier,
 6661        }
 6662    }
 6663
 6664    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6665        if self.edit_prediction_provider.is_none() {
 6666            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6667        } else {
 6668            let selection = self.selections.newest_anchor();
 6669            let cursor = selection.head();
 6670
 6671            if let Some((buffer, cursor_buffer_position)) =
 6672                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6673            {
 6674                self.edit_prediction_settings =
 6675                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6676            }
 6677        }
 6678    }
 6679
 6680    fn edit_prediction_settings_at_position(
 6681        &self,
 6682        buffer: &Entity<Buffer>,
 6683        buffer_position: language::Anchor,
 6684        cx: &App,
 6685    ) -> EditPredictionSettings {
 6686        if !self.mode.is_full()
 6687            || !self.show_inline_completions_override.unwrap_or(true)
 6688            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6689        {
 6690            return EditPredictionSettings::Disabled;
 6691        }
 6692
 6693        let buffer = buffer.read(cx);
 6694
 6695        let file = buffer.file();
 6696
 6697        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6698            return EditPredictionSettings::Disabled;
 6699        };
 6700
 6701        let by_provider = matches!(
 6702            self.menu_inline_completions_policy,
 6703            MenuInlineCompletionsPolicy::ByProvider
 6704        );
 6705
 6706        let show_in_menu = by_provider
 6707            && self
 6708                .edit_prediction_provider
 6709                .as_ref()
 6710                .map_or(false, |provider| {
 6711                    provider.provider.show_completions_in_menu()
 6712                });
 6713
 6714        let preview_requires_modifier =
 6715            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6716
 6717        EditPredictionSettings::Enabled {
 6718            show_in_menu,
 6719            preview_requires_modifier,
 6720        }
 6721    }
 6722
 6723    fn should_show_edit_predictions(&self) -> bool {
 6724        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6725    }
 6726
 6727    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6728        matches!(
 6729            self.edit_prediction_preview,
 6730            EditPredictionPreview::Active { .. }
 6731        )
 6732    }
 6733
 6734    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6735        let cursor = self.selections.newest_anchor().head();
 6736        if let Some((buffer, cursor_position)) =
 6737            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6738        {
 6739            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6740        } else {
 6741            false
 6742        }
 6743    }
 6744
 6745    pub fn supports_minimap(&self, cx: &App) -> bool {
 6746        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6747    }
 6748
 6749    fn edit_predictions_enabled_in_buffer(
 6750        &self,
 6751        buffer: &Entity<Buffer>,
 6752        buffer_position: language::Anchor,
 6753        cx: &App,
 6754    ) -> bool {
 6755        maybe!({
 6756            if self.read_only(cx) {
 6757                return Some(false);
 6758            }
 6759            let provider = self.edit_prediction_provider()?;
 6760            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6761                return Some(false);
 6762            }
 6763            let buffer = buffer.read(cx);
 6764            let Some(file) = buffer.file() else {
 6765                return Some(true);
 6766            };
 6767            let settings = all_language_settings(Some(file), cx);
 6768            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6769        })
 6770        .unwrap_or(false)
 6771    }
 6772
 6773    fn cycle_inline_completion(
 6774        &mut self,
 6775        direction: Direction,
 6776        window: &mut Window,
 6777        cx: &mut Context<Self>,
 6778    ) -> Option<()> {
 6779        let provider = self.edit_prediction_provider()?;
 6780        let cursor = self.selections.newest_anchor().head();
 6781        let (buffer, cursor_buffer_position) =
 6782            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6783        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6784            return None;
 6785        }
 6786
 6787        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6788        self.update_visible_inline_completion(window, cx);
 6789
 6790        Some(())
 6791    }
 6792
 6793    pub fn show_inline_completion(
 6794        &mut self,
 6795        _: &ShowEditPrediction,
 6796        window: &mut Window,
 6797        cx: &mut Context<Self>,
 6798    ) {
 6799        if !self.has_active_inline_completion() {
 6800            self.refresh_inline_completion(false, true, window, cx);
 6801            return;
 6802        }
 6803
 6804        self.update_visible_inline_completion(window, cx);
 6805    }
 6806
 6807    pub fn display_cursor_names(
 6808        &mut self,
 6809        _: &DisplayCursorNames,
 6810        window: &mut Window,
 6811        cx: &mut Context<Self>,
 6812    ) {
 6813        self.show_cursor_names(window, cx);
 6814    }
 6815
 6816    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6817        self.show_cursor_names = true;
 6818        cx.notify();
 6819        cx.spawn_in(window, async move |this, cx| {
 6820            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6821            this.update(cx, |this, cx| {
 6822                this.show_cursor_names = false;
 6823                cx.notify()
 6824            })
 6825            .ok()
 6826        })
 6827        .detach();
 6828    }
 6829
 6830    pub fn next_edit_prediction(
 6831        &mut self,
 6832        _: &NextEditPrediction,
 6833        window: &mut Window,
 6834        cx: &mut Context<Self>,
 6835    ) {
 6836        if self.has_active_inline_completion() {
 6837            self.cycle_inline_completion(Direction::Next, window, cx);
 6838        } else {
 6839            let is_copilot_disabled = self
 6840                .refresh_inline_completion(false, true, window, cx)
 6841                .is_none();
 6842            if is_copilot_disabled {
 6843                cx.propagate();
 6844            }
 6845        }
 6846    }
 6847
 6848    pub fn previous_edit_prediction(
 6849        &mut self,
 6850        _: &PreviousEditPrediction,
 6851        window: &mut Window,
 6852        cx: &mut Context<Self>,
 6853    ) {
 6854        if self.has_active_inline_completion() {
 6855            self.cycle_inline_completion(Direction::Prev, window, cx);
 6856        } else {
 6857            let is_copilot_disabled = self
 6858                .refresh_inline_completion(false, true, window, cx)
 6859                .is_none();
 6860            if is_copilot_disabled {
 6861                cx.propagate();
 6862            }
 6863        }
 6864    }
 6865
 6866    pub fn accept_edit_prediction(
 6867        &mut self,
 6868        _: &AcceptEditPrediction,
 6869        window: &mut Window,
 6870        cx: &mut Context<Self>,
 6871    ) {
 6872        if self.show_edit_predictions_in_menu() {
 6873            self.hide_context_menu(window, cx);
 6874        }
 6875
 6876        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6877            return;
 6878        };
 6879
 6880        self.report_inline_completion_event(
 6881            active_inline_completion.completion_id.clone(),
 6882            true,
 6883            cx,
 6884        );
 6885
 6886        match &active_inline_completion.completion {
 6887            InlineCompletion::Move { target, .. } => {
 6888                let target = *target;
 6889
 6890                if let Some(position_map) = &self.last_position_map {
 6891                    if position_map
 6892                        .visible_row_range
 6893                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6894                        || !self.edit_prediction_requires_modifier()
 6895                    {
 6896                        self.unfold_ranges(&[target..target], true, false, cx);
 6897                        // Note that this is also done in vim's handler of the Tab action.
 6898                        self.change_selections(
 6899                            Some(Autoscroll::newest()),
 6900                            window,
 6901                            cx,
 6902                            |selections| {
 6903                                selections.select_anchor_ranges([target..target]);
 6904                            },
 6905                        );
 6906                        self.clear_row_highlights::<EditPredictionPreview>();
 6907
 6908                        self.edit_prediction_preview
 6909                            .set_previous_scroll_position(None);
 6910                    } else {
 6911                        self.edit_prediction_preview
 6912                            .set_previous_scroll_position(Some(
 6913                                position_map.snapshot.scroll_anchor,
 6914                            ));
 6915
 6916                        self.highlight_rows::<EditPredictionPreview>(
 6917                            target..target,
 6918                            cx.theme().colors().editor_highlighted_line_background,
 6919                            RowHighlightOptions {
 6920                                autoscroll: true,
 6921                                ..Default::default()
 6922                            },
 6923                            cx,
 6924                        );
 6925                        self.request_autoscroll(Autoscroll::fit(), cx);
 6926                    }
 6927                }
 6928            }
 6929            InlineCompletion::Edit { edits, .. } => {
 6930                if let Some(provider) = self.edit_prediction_provider() {
 6931                    provider.accept(cx);
 6932                }
 6933
 6934                // Store the transaction ID and selections before applying the edit
 6935                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6936
 6937                let snapshot = self.buffer.read(cx).snapshot(cx);
 6938                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6939
 6940                self.buffer.update(cx, |buffer, cx| {
 6941                    buffer.edit(edits.iter().cloned(), None, cx)
 6942                });
 6943
 6944                self.change_selections(None, window, cx, |s| {
 6945                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6946                });
 6947
 6948                let selections = self.selections.disjoint_anchors();
 6949                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6950                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6951                    if has_new_transaction {
 6952                        self.selection_history
 6953                            .insert_transaction(transaction_id_now, selections);
 6954                    }
 6955                }
 6956
 6957                self.update_visible_inline_completion(window, cx);
 6958                if self.active_inline_completion.is_none() {
 6959                    self.refresh_inline_completion(true, true, window, cx);
 6960                }
 6961
 6962                cx.notify();
 6963            }
 6964        }
 6965
 6966        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6967    }
 6968
 6969    pub fn accept_partial_inline_completion(
 6970        &mut self,
 6971        _: &AcceptPartialEditPrediction,
 6972        window: &mut Window,
 6973        cx: &mut Context<Self>,
 6974    ) {
 6975        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6976            return;
 6977        };
 6978        if self.selections.count() != 1 {
 6979            return;
 6980        }
 6981
 6982        self.report_inline_completion_event(
 6983            active_inline_completion.completion_id.clone(),
 6984            true,
 6985            cx,
 6986        );
 6987
 6988        match &active_inline_completion.completion {
 6989            InlineCompletion::Move { target, .. } => {
 6990                let target = *target;
 6991                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6992                    selections.select_anchor_ranges([target..target]);
 6993                });
 6994            }
 6995            InlineCompletion::Edit { edits, .. } => {
 6996                // Find an insertion that starts at the cursor position.
 6997                let snapshot = self.buffer.read(cx).snapshot(cx);
 6998                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6999                let insertion = edits.iter().find_map(|(range, text)| {
 7000                    let range = range.to_offset(&snapshot);
 7001                    if range.is_empty() && range.start == cursor_offset {
 7002                        Some(text)
 7003                    } else {
 7004                        None
 7005                    }
 7006                });
 7007
 7008                if let Some(text) = insertion {
 7009                    let mut partial_completion = text
 7010                        .chars()
 7011                        .by_ref()
 7012                        .take_while(|c| c.is_alphabetic())
 7013                        .collect::<String>();
 7014                    if partial_completion.is_empty() {
 7015                        partial_completion = text
 7016                            .chars()
 7017                            .by_ref()
 7018                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7019                            .collect::<String>();
 7020                    }
 7021
 7022                    cx.emit(EditorEvent::InputHandled {
 7023                        utf16_range_to_replace: None,
 7024                        text: partial_completion.clone().into(),
 7025                    });
 7026
 7027                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7028
 7029                    self.refresh_inline_completion(true, true, window, cx);
 7030                    cx.notify();
 7031                } else {
 7032                    self.accept_edit_prediction(&Default::default(), window, cx);
 7033                }
 7034            }
 7035        }
 7036    }
 7037
 7038    fn discard_inline_completion(
 7039        &mut self,
 7040        should_report_inline_completion_event: bool,
 7041        cx: &mut Context<Self>,
 7042    ) -> bool {
 7043        if should_report_inline_completion_event {
 7044            let completion_id = self
 7045                .active_inline_completion
 7046                .as_ref()
 7047                .and_then(|active_completion| active_completion.completion_id.clone());
 7048
 7049            self.report_inline_completion_event(completion_id, false, cx);
 7050        }
 7051
 7052        if let Some(provider) = self.edit_prediction_provider() {
 7053            provider.discard(cx);
 7054        }
 7055
 7056        self.take_active_inline_completion(cx)
 7057    }
 7058
 7059    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7060        let Some(provider) = self.edit_prediction_provider() else {
 7061            return;
 7062        };
 7063
 7064        let Some((_, buffer, _)) = self
 7065            .buffer
 7066            .read(cx)
 7067            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7068        else {
 7069            return;
 7070        };
 7071
 7072        let extension = buffer
 7073            .read(cx)
 7074            .file()
 7075            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7076
 7077        let event_type = match accepted {
 7078            true => "Edit Prediction Accepted",
 7079            false => "Edit Prediction Discarded",
 7080        };
 7081        telemetry::event!(
 7082            event_type,
 7083            provider = provider.name(),
 7084            prediction_id = id,
 7085            suggestion_accepted = accepted,
 7086            file_extension = extension,
 7087        );
 7088    }
 7089
 7090    pub fn has_active_inline_completion(&self) -> bool {
 7091        self.active_inline_completion.is_some()
 7092    }
 7093
 7094    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7095        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7096            return false;
 7097        };
 7098
 7099        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7100        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7101        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7102        true
 7103    }
 7104
 7105    /// Returns true when we're displaying the edit prediction popover below the cursor
 7106    /// like we are not previewing and the LSP autocomplete menu is visible
 7107    /// or we are in `when_holding_modifier` mode.
 7108    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7109        if self.edit_prediction_preview_is_active()
 7110            || !self.show_edit_predictions_in_menu()
 7111            || !self.edit_predictions_enabled()
 7112        {
 7113            return false;
 7114        }
 7115
 7116        if self.has_visible_completions_menu() {
 7117            return true;
 7118        }
 7119
 7120        has_completion && self.edit_prediction_requires_modifier()
 7121    }
 7122
 7123    fn handle_modifiers_changed(
 7124        &mut self,
 7125        modifiers: Modifiers,
 7126        position_map: &PositionMap,
 7127        window: &mut Window,
 7128        cx: &mut Context<Self>,
 7129    ) {
 7130        if self.show_edit_predictions_in_menu() {
 7131            self.update_edit_prediction_preview(&modifiers, window, cx);
 7132        }
 7133
 7134        self.update_selection_mode(&modifiers, position_map, window, cx);
 7135
 7136        let mouse_position = window.mouse_position();
 7137        if !position_map.text_hitbox.is_hovered(window) {
 7138            return;
 7139        }
 7140
 7141        self.update_hovered_link(
 7142            position_map.point_for_position(mouse_position),
 7143            &position_map.snapshot,
 7144            modifiers,
 7145            window,
 7146            cx,
 7147        )
 7148    }
 7149
 7150    fn multi_cursor_modifier(
 7151        cursor_event: bool,
 7152        modifiers: &Modifiers,
 7153        cx: &mut Context<Self>,
 7154    ) -> bool {
 7155        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7156        if cursor_event {
 7157            match multi_cursor_setting {
 7158                MultiCursorModifier::Alt => modifiers.alt,
 7159                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7160            }
 7161        } else {
 7162            match multi_cursor_setting {
 7163                MultiCursorModifier::Alt => modifiers.secondary(),
 7164                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7165            }
 7166        }
 7167    }
 7168
 7169    fn columnar_selection_modifiers(multi_cursor_modifier: bool, modifiers: &Modifiers) -> bool {
 7170        modifiers.shift && multi_cursor_modifier && modifiers.number_of_modifiers() == 2
 7171    }
 7172
 7173    fn update_selection_mode(
 7174        &mut self,
 7175        modifiers: &Modifiers,
 7176        position_map: &PositionMap,
 7177        window: &mut Window,
 7178        cx: &mut Context<Self>,
 7179    ) {
 7180        let multi_cursor_modifier = Self::multi_cursor_modifier(true, modifiers, cx);
 7181        if !Self::columnar_selection_modifiers(multi_cursor_modifier, modifiers)
 7182            || self.selections.pending.is_none()
 7183        {
 7184            return;
 7185        }
 7186
 7187        let mouse_position = window.mouse_position();
 7188        let point_for_position = position_map.point_for_position(mouse_position);
 7189        let position = point_for_position.previous_valid;
 7190
 7191        self.select(
 7192            SelectPhase::BeginColumnar {
 7193                position,
 7194                reset: false,
 7195                goal_column: point_for_position.exact_unclipped.column(),
 7196            },
 7197            window,
 7198            cx,
 7199        );
 7200    }
 7201
 7202    fn update_edit_prediction_preview(
 7203        &mut self,
 7204        modifiers: &Modifiers,
 7205        window: &mut Window,
 7206        cx: &mut Context<Self>,
 7207    ) {
 7208        let mut modifiers_held = false;
 7209        if let Some(accept_keystroke) = self
 7210            .accept_edit_prediction_keybind(false, window, cx)
 7211            .keystroke()
 7212        {
 7213            modifiers_held = modifiers_held
 7214                || (&accept_keystroke.modifiers == modifiers
 7215                    && accept_keystroke.modifiers.modified());
 7216        };
 7217        if let Some(accept_partial_keystroke) = self
 7218            .accept_edit_prediction_keybind(true, window, cx)
 7219            .keystroke()
 7220        {
 7221            modifiers_held = modifiers_held
 7222                || (&accept_partial_keystroke.modifiers == modifiers
 7223                    && accept_partial_keystroke.modifiers.modified());
 7224        }
 7225
 7226        if modifiers_held {
 7227            if matches!(
 7228                self.edit_prediction_preview,
 7229                EditPredictionPreview::Inactive { .. }
 7230            ) {
 7231                self.edit_prediction_preview = EditPredictionPreview::Active {
 7232                    previous_scroll_position: None,
 7233                    since: Instant::now(),
 7234                };
 7235
 7236                self.update_visible_inline_completion(window, cx);
 7237                cx.notify();
 7238            }
 7239        } else if let EditPredictionPreview::Active {
 7240            previous_scroll_position,
 7241            since,
 7242        } = self.edit_prediction_preview
 7243        {
 7244            if let (Some(previous_scroll_position), Some(position_map)) =
 7245                (previous_scroll_position, self.last_position_map.as_ref())
 7246            {
 7247                self.set_scroll_position(
 7248                    previous_scroll_position
 7249                        .scroll_position(&position_map.snapshot.display_snapshot),
 7250                    window,
 7251                    cx,
 7252                );
 7253            }
 7254
 7255            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7256                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7257            };
 7258            self.clear_row_highlights::<EditPredictionPreview>();
 7259            self.update_visible_inline_completion(window, cx);
 7260            cx.notify();
 7261        }
 7262    }
 7263
 7264    fn update_visible_inline_completion(
 7265        &mut self,
 7266        _window: &mut Window,
 7267        cx: &mut Context<Self>,
 7268    ) -> Option<()> {
 7269        let selection = self.selections.newest_anchor();
 7270        let cursor = selection.head();
 7271        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7272        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7273        let excerpt_id = cursor.excerpt_id;
 7274
 7275        let show_in_menu = self.show_edit_predictions_in_menu();
 7276        let completions_menu_has_precedence = !show_in_menu
 7277            && (self.context_menu.borrow().is_some()
 7278                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7279
 7280        if completions_menu_has_precedence
 7281            || !offset_selection.is_empty()
 7282            || self
 7283                .active_inline_completion
 7284                .as_ref()
 7285                .map_or(false, |completion| {
 7286                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7287                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7288                    !invalidation_range.contains(&offset_selection.head())
 7289                })
 7290        {
 7291            self.discard_inline_completion(false, cx);
 7292            return None;
 7293        }
 7294
 7295        self.take_active_inline_completion(cx);
 7296        let Some(provider) = self.edit_prediction_provider() else {
 7297            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7298            return None;
 7299        };
 7300
 7301        let (buffer, cursor_buffer_position) =
 7302            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7303
 7304        self.edit_prediction_settings =
 7305            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7306
 7307        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7308
 7309        if self.edit_prediction_indent_conflict {
 7310            let cursor_point = cursor.to_point(&multibuffer);
 7311
 7312            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7313
 7314            if let Some((_, indent)) = indents.iter().next() {
 7315                if indent.len == cursor_point.column {
 7316                    self.edit_prediction_indent_conflict = false;
 7317                }
 7318            }
 7319        }
 7320
 7321        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7322        let edits = inline_completion
 7323            .edits
 7324            .into_iter()
 7325            .flat_map(|(range, new_text)| {
 7326                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7327                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7328                Some((start..end, new_text))
 7329            })
 7330            .collect::<Vec<_>>();
 7331        if edits.is_empty() {
 7332            return None;
 7333        }
 7334
 7335        let first_edit_start = edits.first().unwrap().0.start;
 7336        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7337        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7338
 7339        let last_edit_end = edits.last().unwrap().0.end;
 7340        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7341        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7342
 7343        let cursor_row = cursor.to_point(&multibuffer).row;
 7344
 7345        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7346
 7347        let mut inlay_ids = Vec::new();
 7348        let invalidation_row_range;
 7349        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7350            Some(cursor_row..edit_end_row)
 7351        } else if cursor_row > edit_end_row {
 7352            Some(edit_start_row..cursor_row)
 7353        } else {
 7354            None
 7355        };
 7356        let is_move =
 7357            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7358        let completion = if is_move {
 7359            invalidation_row_range =
 7360                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7361            let target = first_edit_start;
 7362            InlineCompletion::Move { target, snapshot }
 7363        } else {
 7364            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7365                && !self.inline_completions_hidden_for_vim_mode;
 7366
 7367            if show_completions_in_buffer {
 7368                if edits
 7369                    .iter()
 7370                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7371                {
 7372                    let mut inlays = Vec::new();
 7373                    for (range, new_text) in &edits {
 7374                        let inlay = Inlay::inline_completion(
 7375                            post_inc(&mut self.next_inlay_id),
 7376                            range.start,
 7377                            new_text.as_str(),
 7378                        );
 7379                        inlay_ids.push(inlay.id);
 7380                        inlays.push(inlay);
 7381                    }
 7382
 7383                    self.splice_inlays(&[], inlays, cx);
 7384                } else {
 7385                    let background_color = cx.theme().status().deleted_background;
 7386                    self.highlight_text::<InlineCompletionHighlight>(
 7387                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7388                        HighlightStyle {
 7389                            background_color: Some(background_color),
 7390                            ..Default::default()
 7391                        },
 7392                        cx,
 7393                    );
 7394                }
 7395            }
 7396
 7397            invalidation_row_range = edit_start_row..edit_end_row;
 7398
 7399            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7400                if provider.show_tab_accept_marker() {
 7401                    EditDisplayMode::TabAccept
 7402                } else {
 7403                    EditDisplayMode::Inline
 7404                }
 7405            } else {
 7406                EditDisplayMode::DiffPopover
 7407            };
 7408
 7409            InlineCompletion::Edit {
 7410                edits,
 7411                edit_preview: inline_completion.edit_preview,
 7412                display_mode,
 7413                snapshot,
 7414            }
 7415        };
 7416
 7417        let invalidation_range = multibuffer
 7418            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7419            ..multibuffer.anchor_after(Point::new(
 7420                invalidation_row_range.end,
 7421                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7422            ));
 7423
 7424        self.stale_inline_completion_in_menu = None;
 7425        self.active_inline_completion = Some(InlineCompletionState {
 7426            inlay_ids,
 7427            completion,
 7428            completion_id: inline_completion.id,
 7429            invalidation_range,
 7430        });
 7431
 7432        cx.notify();
 7433
 7434        Some(())
 7435    }
 7436
 7437    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7438        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7439    }
 7440
 7441    fn clear_tasks(&mut self) {
 7442        self.tasks.clear()
 7443    }
 7444
 7445    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7446        if self.tasks.insert(key, value).is_some() {
 7447            // This case should hopefully be rare, but just in case...
 7448            log::error!(
 7449                "multiple different run targets found on a single line, only the last target will be rendered"
 7450            )
 7451        }
 7452    }
 7453
 7454    /// Get all display points of breakpoints that will be rendered within editor
 7455    ///
 7456    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7457    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7458    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7459    fn active_breakpoints(
 7460        &self,
 7461        range: Range<DisplayRow>,
 7462        window: &mut Window,
 7463        cx: &mut Context<Self>,
 7464    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7465        let mut breakpoint_display_points = HashMap::default();
 7466
 7467        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7468            return breakpoint_display_points;
 7469        };
 7470
 7471        let snapshot = self.snapshot(window, cx);
 7472
 7473        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7474        let Some(project) = self.project.as_ref() else {
 7475            return breakpoint_display_points;
 7476        };
 7477
 7478        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7479            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7480
 7481        for (buffer_snapshot, range, excerpt_id) in
 7482            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7483        {
 7484            let Some(buffer) = project
 7485                .read(cx)
 7486                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7487            else {
 7488                continue;
 7489            };
 7490            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7491                &buffer,
 7492                Some(
 7493                    buffer_snapshot.anchor_before(range.start)
 7494                        ..buffer_snapshot.anchor_after(range.end),
 7495                ),
 7496                buffer_snapshot,
 7497                cx,
 7498            );
 7499            for (breakpoint, state) in breakpoints {
 7500                let multi_buffer_anchor =
 7501                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7502                let position = multi_buffer_anchor
 7503                    .to_point(&multi_buffer_snapshot)
 7504                    .to_display_point(&snapshot);
 7505
 7506                breakpoint_display_points.insert(
 7507                    position.row(),
 7508                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7509                );
 7510            }
 7511        }
 7512
 7513        breakpoint_display_points
 7514    }
 7515
 7516    fn breakpoint_context_menu(
 7517        &self,
 7518        anchor: Anchor,
 7519        window: &mut Window,
 7520        cx: &mut Context<Self>,
 7521    ) -> Entity<ui::ContextMenu> {
 7522        let weak_editor = cx.weak_entity();
 7523        let focus_handle = self.focus_handle(cx);
 7524
 7525        let row = self
 7526            .buffer
 7527            .read(cx)
 7528            .snapshot(cx)
 7529            .summary_for_anchor::<Point>(&anchor)
 7530            .row;
 7531
 7532        let breakpoint = self
 7533            .breakpoint_at_row(row, window, cx)
 7534            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7535
 7536        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7537            "Edit Log Breakpoint"
 7538        } else {
 7539            "Set Log Breakpoint"
 7540        };
 7541
 7542        let condition_breakpoint_msg = if breakpoint
 7543            .as_ref()
 7544            .is_some_and(|bp| bp.1.condition.is_some())
 7545        {
 7546            "Edit Condition Breakpoint"
 7547        } else {
 7548            "Set Condition Breakpoint"
 7549        };
 7550
 7551        let hit_condition_breakpoint_msg = if breakpoint
 7552            .as_ref()
 7553            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7554        {
 7555            "Edit Hit Condition Breakpoint"
 7556        } else {
 7557            "Set Hit Condition Breakpoint"
 7558        };
 7559
 7560        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7561            "Unset Breakpoint"
 7562        } else {
 7563            "Set Breakpoint"
 7564        };
 7565
 7566        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7567
 7568        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7569            BreakpointState::Enabled => Some("Disable"),
 7570            BreakpointState::Disabled => Some("Enable"),
 7571        });
 7572
 7573        let (anchor, breakpoint) =
 7574            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7575
 7576        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7577            menu.on_blur_subscription(Subscription::new(|| {}))
 7578                .context(focus_handle)
 7579                .when(run_to_cursor, |this| {
 7580                    let weak_editor = weak_editor.clone();
 7581                    this.entry("Run to cursor", None, move |window, cx| {
 7582                        weak_editor
 7583                            .update(cx, |editor, cx| {
 7584                                editor.change_selections(None, window, cx, |s| {
 7585                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7586                                });
 7587                            })
 7588                            .ok();
 7589
 7590                        window.dispatch_action(Box::new(RunToCursor), cx);
 7591                    })
 7592                    .separator()
 7593                })
 7594                .when_some(toggle_state_msg, |this, msg| {
 7595                    this.entry(msg, None, {
 7596                        let weak_editor = weak_editor.clone();
 7597                        let breakpoint = breakpoint.clone();
 7598                        move |_window, cx| {
 7599                            weak_editor
 7600                                .update(cx, |this, cx| {
 7601                                    this.edit_breakpoint_at_anchor(
 7602                                        anchor,
 7603                                        breakpoint.as_ref().clone(),
 7604                                        BreakpointEditAction::InvertState,
 7605                                        cx,
 7606                                    );
 7607                                })
 7608                                .log_err();
 7609                        }
 7610                    })
 7611                })
 7612                .entry(set_breakpoint_msg, None, {
 7613                    let weak_editor = weak_editor.clone();
 7614                    let breakpoint = breakpoint.clone();
 7615                    move |_window, cx| {
 7616                        weak_editor
 7617                            .update(cx, |this, cx| {
 7618                                this.edit_breakpoint_at_anchor(
 7619                                    anchor,
 7620                                    breakpoint.as_ref().clone(),
 7621                                    BreakpointEditAction::Toggle,
 7622                                    cx,
 7623                                );
 7624                            })
 7625                            .log_err();
 7626                    }
 7627                })
 7628                .entry(log_breakpoint_msg, None, {
 7629                    let breakpoint = breakpoint.clone();
 7630                    let weak_editor = weak_editor.clone();
 7631                    move |window, cx| {
 7632                        weak_editor
 7633                            .update(cx, |this, cx| {
 7634                                this.add_edit_breakpoint_block(
 7635                                    anchor,
 7636                                    breakpoint.as_ref(),
 7637                                    BreakpointPromptEditAction::Log,
 7638                                    window,
 7639                                    cx,
 7640                                );
 7641                            })
 7642                            .log_err();
 7643                    }
 7644                })
 7645                .entry(condition_breakpoint_msg, None, {
 7646                    let breakpoint = breakpoint.clone();
 7647                    let weak_editor = weak_editor.clone();
 7648                    move |window, cx| {
 7649                        weak_editor
 7650                            .update(cx, |this, cx| {
 7651                                this.add_edit_breakpoint_block(
 7652                                    anchor,
 7653                                    breakpoint.as_ref(),
 7654                                    BreakpointPromptEditAction::Condition,
 7655                                    window,
 7656                                    cx,
 7657                                );
 7658                            })
 7659                            .log_err();
 7660                    }
 7661                })
 7662                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7663                    weak_editor
 7664                        .update(cx, |this, cx| {
 7665                            this.add_edit_breakpoint_block(
 7666                                anchor,
 7667                                breakpoint.as_ref(),
 7668                                BreakpointPromptEditAction::HitCondition,
 7669                                window,
 7670                                cx,
 7671                            );
 7672                        })
 7673                        .log_err();
 7674                })
 7675        })
 7676    }
 7677
 7678    fn render_breakpoint(
 7679        &self,
 7680        position: Anchor,
 7681        row: DisplayRow,
 7682        breakpoint: &Breakpoint,
 7683        state: Option<BreakpointSessionState>,
 7684        cx: &mut Context<Self>,
 7685    ) -> IconButton {
 7686        let is_rejected = state.is_some_and(|s| !s.verified);
 7687        // Is it a breakpoint that shows up when hovering over gutter?
 7688        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7689            (false, false),
 7690            |PhantomBreakpointIndicator {
 7691                 is_active,
 7692                 display_row,
 7693                 collides_with_existing_breakpoint,
 7694             }| {
 7695                (
 7696                    is_active && display_row == row,
 7697                    collides_with_existing_breakpoint,
 7698                )
 7699            },
 7700        );
 7701
 7702        let (color, icon) = {
 7703            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7704                (false, false) => ui::IconName::DebugBreakpoint,
 7705                (true, false) => ui::IconName::DebugLogBreakpoint,
 7706                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7707                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7708            };
 7709
 7710            let color = if is_phantom {
 7711                Color::Hint
 7712            } else if is_rejected {
 7713                Color::Disabled
 7714            } else {
 7715                Color::Debugger
 7716            };
 7717
 7718            (color, icon)
 7719        };
 7720
 7721        let breakpoint = Arc::from(breakpoint.clone());
 7722
 7723        let alt_as_text = gpui::Keystroke {
 7724            modifiers: Modifiers::secondary_key(),
 7725            ..Default::default()
 7726        };
 7727        let primary_action_text = if breakpoint.is_disabled() {
 7728            "Enable breakpoint"
 7729        } else if is_phantom && !collides_with_existing {
 7730            "Set breakpoint"
 7731        } else {
 7732            "Unset breakpoint"
 7733        };
 7734        let focus_handle = self.focus_handle.clone();
 7735
 7736        let meta = if is_rejected {
 7737            SharedString::from("No executable code is associated with this line.")
 7738        } else if collides_with_existing && !breakpoint.is_disabled() {
 7739            SharedString::from(format!(
 7740                "{alt_as_text}-click to disable,\nright-click for more options."
 7741            ))
 7742        } else {
 7743            SharedString::from("Right-click for more options.")
 7744        };
 7745        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7746            .icon_size(IconSize::XSmall)
 7747            .size(ui::ButtonSize::None)
 7748            .when(is_rejected, |this| {
 7749                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7750            })
 7751            .icon_color(color)
 7752            .style(ButtonStyle::Transparent)
 7753            .on_click(cx.listener({
 7754                let breakpoint = breakpoint.clone();
 7755
 7756                move |editor, event: &ClickEvent, window, cx| {
 7757                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7758                        BreakpointEditAction::InvertState
 7759                    } else {
 7760                        BreakpointEditAction::Toggle
 7761                    };
 7762
 7763                    window.focus(&editor.focus_handle(cx));
 7764                    editor.edit_breakpoint_at_anchor(
 7765                        position,
 7766                        breakpoint.as_ref().clone(),
 7767                        edit_action,
 7768                        cx,
 7769                    );
 7770                }
 7771            }))
 7772            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7773                editor.set_breakpoint_context_menu(
 7774                    row,
 7775                    Some(position),
 7776                    event.down.position,
 7777                    window,
 7778                    cx,
 7779                );
 7780            }))
 7781            .tooltip(move |window, cx| {
 7782                Tooltip::with_meta_in(
 7783                    primary_action_text,
 7784                    Some(&ToggleBreakpoint),
 7785                    meta.clone(),
 7786                    &focus_handle,
 7787                    window,
 7788                    cx,
 7789                )
 7790            })
 7791    }
 7792
 7793    fn build_tasks_context(
 7794        project: &Entity<Project>,
 7795        buffer: &Entity<Buffer>,
 7796        buffer_row: u32,
 7797        tasks: &Arc<RunnableTasks>,
 7798        cx: &mut Context<Self>,
 7799    ) -> Task<Option<task::TaskContext>> {
 7800        let position = Point::new(buffer_row, tasks.column);
 7801        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7802        let location = Location {
 7803            buffer: buffer.clone(),
 7804            range: range_start..range_start,
 7805        };
 7806        // Fill in the environmental variables from the tree-sitter captures
 7807        let mut captured_task_variables = TaskVariables::default();
 7808        for (capture_name, value) in tasks.extra_variables.clone() {
 7809            captured_task_variables.insert(
 7810                task::VariableName::Custom(capture_name.into()),
 7811                value.clone(),
 7812            );
 7813        }
 7814        project.update(cx, |project, cx| {
 7815            project.task_store().update(cx, |task_store, cx| {
 7816                task_store.task_context_for_location(captured_task_variables, location, cx)
 7817            })
 7818        })
 7819    }
 7820
 7821    pub fn spawn_nearest_task(
 7822        &mut self,
 7823        action: &SpawnNearestTask,
 7824        window: &mut Window,
 7825        cx: &mut Context<Self>,
 7826    ) {
 7827        let Some((workspace, _)) = self.workspace.clone() else {
 7828            return;
 7829        };
 7830        let Some(project) = self.project.clone() else {
 7831            return;
 7832        };
 7833
 7834        // Try to find a closest, enclosing node using tree-sitter that has a
 7835        // task
 7836        let Some((buffer, buffer_row, tasks)) = self
 7837            .find_enclosing_node_task(cx)
 7838            // Or find the task that's closest in row-distance.
 7839            .or_else(|| self.find_closest_task(cx))
 7840        else {
 7841            return;
 7842        };
 7843
 7844        let reveal_strategy = action.reveal;
 7845        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7846        cx.spawn_in(window, async move |_, cx| {
 7847            let context = task_context.await?;
 7848            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7849
 7850            let resolved = &mut resolved_task.resolved;
 7851            resolved.reveal = reveal_strategy;
 7852
 7853            workspace
 7854                .update_in(cx, |workspace, window, cx| {
 7855                    workspace.schedule_resolved_task(
 7856                        task_source_kind,
 7857                        resolved_task,
 7858                        false,
 7859                        window,
 7860                        cx,
 7861                    );
 7862                })
 7863                .ok()
 7864        })
 7865        .detach();
 7866    }
 7867
 7868    fn find_closest_task(
 7869        &mut self,
 7870        cx: &mut Context<Self>,
 7871    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7872        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7873
 7874        let ((buffer_id, row), tasks) = self
 7875            .tasks
 7876            .iter()
 7877            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7878
 7879        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7880        let tasks = Arc::new(tasks.to_owned());
 7881        Some((buffer, *row, tasks))
 7882    }
 7883
 7884    fn find_enclosing_node_task(
 7885        &mut self,
 7886        cx: &mut Context<Self>,
 7887    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7888        let snapshot = self.buffer.read(cx).snapshot(cx);
 7889        let offset = self.selections.newest::<usize>(cx).head();
 7890        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7891        let buffer_id = excerpt.buffer().remote_id();
 7892
 7893        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7894        let mut cursor = layer.node().walk();
 7895
 7896        while cursor.goto_first_child_for_byte(offset).is_some() {
 7897            if cursor.node().end_byte() == offset {
 7898                cursor.goto_next_sibling();
 7899            }
 7900        }
 7901
 7902        // Ascend to the smallest ancestor that contains the range and has a task.
 7903        loop {
 7904            let node = cursor.node();
 7905            let node_range = node.byte_range();
 7906            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7907
 7908            // Check if this node contains our offset
 7909            if node_range.start <= offset && node_range.end >= offset {
 7910                // If it contains offset, check for task
 7911                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7912                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7913                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7914                }
 7915            }
 7916
 7917            if !cursor.goto_parent() {
 7918                break;
 7919            }
 7920        }
 7921        None
 7922    }
 7923
 7924    fn render_run_indicator(
 7925        &self,
 7926        _style: &EditorStyle,
 7927        is_active: bool,
 7928        row: DisplayRow,
 7929        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7930        cx: &mut Context<Self>,
 7931    ) -> IconButton {
 7932        let color = Color::Muted;
 7933        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7934
 7935        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7936            .shape(ui::IconButtonShape::Square)
 7937            .icon_size(IconSize::XSmall)
 7938            .icon_color(color)
 7939            .toggle_state(is_active)
 7940            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7941                let quick_launch = e.down.button == MouseButton::Left;
 7942                window.focus(&editor.focus_handle(cx));
 7943                editor.toggle_code_actions(
 7944                    &ToggleCodeActions {
 7945                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 7946                        quick_launch,
 7947                    },
 7948                    window,
 7949                    cx,
 7950                );
 7951            }))
 7952            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7953                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7954            }))
 7955    }
 7956
 7957    pub fn context_menu_visible(&self) -> bool {
 7958        !self.edit_prediction_preview_is_active()
 7959            && self
 7960                .context_menu
 7961                .borrow()
 7962                .as_ref()
 7963                .map_or(false, |menu| menu.visible())
 7964    }
 7965
 7966    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7967        self.context_menu
 7968            .borrow()
 7969            .as_ref()
 7970            .map(|menu| menu.origin())
 7971    }
 7972
 7973    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7974        self.context_menu_options = Some(options);
 7975    }
 7976
 7977    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7978    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7979
 7980    fn render_edit_prediction_popover(
 7981        &mut self,
 7982        text_bounds: &Bounds<Pixels>,
 7983        content_origin: gpui::Point<Pixels>,
 7984        right_margin: Pixels,
 7985        editor_snapshot: &EditorSnapshot,
 7986        visible_row_range: Range<DisplayRow>,
 7987        scroll_top: f32,
 7988        scroll_bottom: f32,
 7989        line_layouts: &[LineWithInvisibles],
 7990        line_height: Pixels,
 7991        scroll_pixel_position: gpui::Point<Pixels>,
 7992        newest_selection_head: Option<DisplayPoint>,
 7993        editor_width: Pixels,
 7994        style: &EditorStyle,
 7995        window: &mut Window,
 7996        cx: &mut App,
 7997    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7998        if self.mode().is_minimap() {
 7999            return None;
 8000        }
 8001        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8002
 8003        if self.edit_prediction_visible_in_cursor_popover(true) {
 8004            return None;
 8005        }
 8006
 8007        match &active_inline_completion.completion {
 8008            InlineCompletion::Move { target, .. } => {
 8009                let target_display_point = target.to_display_point(editor_snapshot);
 8010
 8011                if self.edit_prediction_requires_modifier() {
 8012                    if !self.edit_prediction_preview_is_active() {
 8013                        return None;
 8014                    }
 8015
 8016                    self.render_edit_prediction_modifier_jump_popover(
 8017                        text_bounds,
 8018                        content_origin,
 8019                        visible_row_range,
 8020                        line_layouts,
 8021                        line_height,
 8022                        scroll_pixel_position,
 8023                        newest_selection_head,
 8024                        target_display_point,
 8025                        window,
 8026                        cx,
 8027                    )
 8028                } else {
 8029                    self.render_edit_prediction_eager_jump_popover(
 8030                        text_bounds,
 8031                        content_origin,
 8032                        editor_snapshot,
 8033                        visible_row_range,
 8034                        scroll_top,
 8035                        scroll_bottom,
 8036                        line_height,
 8037                        scroll_pixel_position,
 8038                        target_display_point,
 8039                        editor_width,
 8040                        window,
 8041                        cx,
 8042                    )
 8043                }
 8044            }
 8045            InlineCompletion::Edit {
 8046                display_mode: EditDisplayMode::Inline,
 8047                ..
 8048            } => None,
 8049            InlineCompletion::Edit {
 8050                display_mode: EditDisplayMode::TabAccept,
 8051                edits,
 8052                ..
 8053            } => {
 8054                let range = &edits.first()?.0;
 8055                let target_display_point = range.end.to_display_point(editor_snapshot);
 8056
 8057                self.render_edit_prediction_end_of_line_popover(
 8058                    "Accept",
 8059                    editor_snapshot,
 8060                    visible_row_range,
 8061                    target_display_point,
 8062                    line_height,
 8063                    scroll_pixel_position,
 8064                    content_origin,
 8065                    editor_width,
 8066                    window,
 8067                    cx,
 8068                )
 8069            }
 8070            InlineCompletion::Edit {
 8071                edits,
 8072                edit_preview,
 8073                display_mode: EditDisplayMode::DiffPopover,
 8074                snapshot,
 8075            } => self.render_edit_prediction_diff_popover(
 8076                text_bounds,
 8077                content_origin,
 8078                right_margin,
 8079                editor_snapshot,
 8080                visible_row_range,
 8081                line_layouts,
 8082                line_height,
 8083                scroll_pixel_position,
 8084                newest_selection_head,
 8085                editor_width,
 8086                style,
 8087                edits,
 8088                edit_preview,
 8089                snapshot,
 8090                window,
 8091                cx,
 8092            ),
 8093        }
 8094    }
 8095
 8096    fn render_edit_prediction_modifier_jump_popover(
 8097        &mut self,
 8098        text_bounds: &Bounds<Pixels>,
 8099        content_origin: gpui::Point<Pixels>,
 8100        visible_row_range: Range<DisplayRow>,
 8101        line_layouts: &[LineWithInvisibles],
 8102        line_height: Pixels,
 8103        scroll_pixel_position: gpui::Point<Pixels>,
 8104        newest_selection_head: Option<DisplayPoint>,
 8105        target_display_point: DisplayPoint,
 8106        window: &mut Window,
 8107        cx: &mut App,
 8108    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8109        let scrolled_content_origin =
 8110            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8111
 8112        const SCROLL_PADDING_Y: Pixels = px(12.);
 8113
 8114        if target_display_point.row() < visible_row_range.start {
 8115            return self.render_edit_prediction_scroll_popover(
 8116                |_| SCROLL_PADDING_Y,
 8117                IconName::ArrowUp,
 8118                visible_row_range,
 8119                line_layouts,
 8120                newest_selection_head,
 8121                scrolled_content_origin,
 8122                window,
 8123                cx,
 8124            );
 8125        } else if target_display_point.row() >= visible_row_range.end {
 8126            return self.render_edit_prediction_scroll_popover(
 8127                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8128                IconName::ArrowDown,
 8129                visible_row_range,
 8130                line_layouts,
 8131                newest_selection_head,
 8132                scrolled_content_origin,
 8133                window,
 8134                cx,
 8135            );
 8136        }
 8137
 8138        const POLE_WIDTH: Pixels = px(2.);
 8139
 8140        let line_layout =
 8141            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8142        let target_column = target_display_point.column() as usize;
 8143
 8144        let target_x = line_layout.x_for_index(target_column);
 8145        let target_y =
 8146            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8147
 8148        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8149
 8150        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8151        border_color.l += 0.001;
 8152
 8153        let mut element = v_flex()
 8154            .items_end()
 8155            .when(flag_on_right, |el| el.items_start())
 8156            .child(if flag_on_right {
 8157                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8158                    .rounded_bl(px(0.))
 8159                    .rounded_tl(px(0.))
 8160                    .border_l_2()
 8161                    .border_color(border_color)
 8162            } else {
 8163                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8164                    .rounded_br(px(0.))
 8165                    .rounded_tr(px(0.))
 8166                    .border_r_2()
 8167                    .border_color(border_color)
 8168            })
 8169            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8170            .into_any();
 8171
 8172        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8173
 8174        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8175            - point(
 8176                if flag_on_right {
 8177                    POLE_WIDTH
 8178                } else {
 8179                    size.width - POLE_WIDTH
 8180                },
 8181                size.height - line_height,
 8182            );
 8183
 8184        origin.x = origin.x.max(content_origin.x);
 8185
 8186        element.prepaint_at(origin, window, cx);
 8187
 8188        Some((element, origin))
 8189    }
 8190
 8191    fn render_edit_prediction_scroll_popover(
 8192        &mut self,
 8193        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8194        scroll_icon: IconName,
 8195        visible_row_range: Range<DisplayRow>,
 8196        line_layouts: &[LineWithInvisibles],
 8197        newest_selection_head: Option<DisplayPoint>,
 8198        scrolled_content_origin: gpui::Point<Pixels>,
 8199        window: &mut Window,
 8200        cx: &mut App,
 8201    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8202        let mut element = self
 8203            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8204            .into_any();
 8205
 8206        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8207
 8208        let cursor = newest_selection_head?;
 8209        let cursor_row_layout =
 8210            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8211        let cursor_column = cursor.column() as usize;
 8212
 8213        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8214
 8215        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8216
 8217        element.prepaint_at(origin, window, cx);
 8218        Some((element, origin))
 8219    }
 8220
 8221    fn render_edit_prediction_eager_jump_popover(
 8222        &mut self,
 8223        text_bounds: &Bounds<Pixels>,
 8224        content_origin: gpui::Point<Pixels>,
 8225        editor_snapshot: &EditorSnapshot,
 8226        visible_row_range: Range<DisplayRow>,
 8227        scroll_top: f32,
 8228        scroll_bottom: f32,
 8229        line_height: Pixels,
 8230        scroll_pixel_position: gpui::Point<Pixels>,
 8231        target_display_point: DisplayPoint,
 8232        editor_width: Pixels,
 8233        window: &mut Window,
 8234        cx: &mut App,
 8235    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8236        if target_display_point.row().as_f32() < scroll_top {
 8237            let mut element = self
 8238                .render_edit_prediction_line_popover(
 8239                    "Jump to Edit",
 8240                    Some(IconName::ArrowUp),
 8241                    window,
 8242                    cx,
 8243                )?
 8244                .into_any();
 8245
 8246            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8247            let offset = point(
 8248                (text_bounds.size.width - size.width) / 2.,
 8249                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8250            );
 8251
 8252            let origin = text_bounds.origin + offset;
 8253            element.prepaint_at(origin, window, cx);
 8254            Some((element, origin))
 8255        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8256            let mut element = self
 8257                .render_edit_prediction_line_popover(
 8258                    "Jump to Edit",
 8259                    Some(IconName::ArrowDown),
 8260                    window,
 8261                    cx,
 8262                )?
 8263                .into_any();
 8264
 8265            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8266            let offset = point(
 8267                (text_bounds.size.width - size.width) / 2.,
 8268                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8269            );
 8270
 8271            let origin = text_bounds.origin + offset;
 8272            element.prepaint_at(origin, window, cx);
 8273            Some((element, origin))
 8274        } else {
 8275            self.render_edit_prediction_end_of_line_popover(
 8276                "Jump to Edit",
 8277                editor_snapshot,
 8278                visible_row_range,
 8279                target_display_point,
 8280                line_height,
 8281                scroll_pixel_position,
 8282                content_origin,
 8283                editor_width,
 8284                window,
 8285                cx,
 8286            )
 8287        }
 8288    }
 8289
 8290    fn render_edit_prediction_end_of_line_popover(
 8291        self: &mut Editor,
 8292        label: &'static str,
 8293        editor_snapshot: &EditorSnapshot,
 8294        visible_row_range: Range<DisplayRow>,
 8295        target_display_point: DisplayPoint,
 8296        line_height: Pixels,
 8297        scroll_pixel_position: gpui::Point<Pixels>,
 8298        content_origin: gpui::Point<Pixels>,
 8299        editor_width: Pixels,
 8300        window: &mut Window,
 8301        cx: &mut App,
 8302    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8303        let target_line_end = DisplayPoint::new(
 8304            target_display_point.row(),
 8305            editor_snapshot.line_len(target_display_point.row()),
 8306        );
 8307
 8308        let mut element = self
 8309            .render_edit_prediction_line_popover(label, None, window, cx)?
 8310            .into_any();
 8311
 8312        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8313
 8314        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8315
 8316        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8317        let mut origin = start_point
 8318            + line_origin
 8319            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8320        origin.x = origin.x.max(content_origin.x);
 8321
 8322        let max_x = content_origin.x + editor_width - size.width;
 8323
 8324        if origin.x > max_x {
 8325            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8326
 8327            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8328                origin.y += offset;
 8329                IconName::ArrowUp
 8330            } else {
 8331                origin.y -= offset;
 8332                IconName::ArrowDown
 8333            };
 8334
 8335            element = self
 8336                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8337                .into_any();
 8338
 8339            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8340
 8341            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8342        }
 8343
 8344        element.prepaint_at(origin, window, cx);
 8345        Some((element, origin))
 8346    }
 8347
 8348    fn render_edit_prediction_diff_popover(
 8349        self: &Editor,
 8350        text_bounds: &Bounds<Pixels>,
 8351        content_origin: gpui::Point<Pixels>,
 8352        right_margin: Pixels,
 8353        editor_snapshot: &EditorSnapshot,
 8354        visible_row_range: Range<DisplayRow>,
 8355        line_layouts: &[LineWithInvisibles],
 8356        line_height: Pixels,
 8357        scroll_pixel_position: gpui::Point<Pixels>,
 8358        newest_selection_head: Option<DisplayPoint>,
 8359        editor_width: Pixels,
 8360        style: &EditorStyle,
 8361        edits: &Vec<(Range<Anchor>, String)>,
 8362        edit_preview: &Option<language::EditPreview>,
 8363        snapshot: &language::BufferSnapshot,
 8364        window: &mut Window,
 8365        cx: &mut App,
 8366    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8367        let edit_start = edits
 8368            .first()
 8369            .unwrap()
 8370            .0
 8371            .start
 8372            .to_display_point(editor_snapshot);
 8373        let edit_end = edits
 8374            .last()
 8375            .unwrap()
 8376            .0
 8377            .end
 8378            .to_display_point(editor_snapshot);
 8379
 8380        let is_visible = visible_row_range.contains(&edit_start.row())
 8381            || visible_row_range.contains(&edit_end.row());
 8382        if !is_visible {
 8383            return None;
 8384        }
 8385
 8386        let highlighted_edits =
 8387            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8388
 8389        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8390        let line_count = highlighted_edits.text.lines().count();
 8391
 8392        const BORDER_WIDTH: Pixels = px(1.);
 8393
 8394        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8395        let has_keybind = keybind.is_some();
 8396
 8397        let mut element = h_flex()
 8398            .items_start()
 8399            .child(
 8400                h_flex()
 8401                    .bg(cx.theme().colors().editor_background)
 8402                    .border(BORDER_WIDTH)
 8403                    .shadow_sm()
 8404                    .border_color(cx.theme().colors().border)
 8405                    .rounded_l_lg()
 8406                    .when(line_count > 1, |el| el.rounded_br_lg())
 8407                    .pr_1()
 8408                    .child(styled_text),
 8409            )
 8410            .child(
 8411                h_flex()
 8412                    .h(line_height + BORDER_WIDTH * 2.)
 8413                    .px_1p5()
 8414                    .gap_1()
 8415                    // Workaround: For some reason, there's a gap if we don't do this
 8416                    .ml(-BORDER_WIDTH)
 8417                    .shadow(vec![gpui::BoxShadow {
 8418                        color: gpui::black().opacity(0.05),
 8419                        offset: point(px(1.), px(1.)),
 8420                        blur_radius: px(2.),
 8421                        spread_radius: px(0.),
 8422                    }])
 8423                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8424                    .border(BORDER_WIDTH)
 8425                    .border_color(cx.theme().colors().border)
 8426                    .rounded_r_lg()
 8427                    .id("edit_prediction_diff_popover_keybind")
 8428                    .when(!has_keybind, |el| {
 8429                        let status_colors = cx.theme().status();
 8430
 8431                        el.bg(status_colors.error_background)
 8432                            .border_color(status_colors.error.opacity(0.6))
 8433                            .child(Icon::new(IconName::Info).color(Color::Error))
 8434                            .cursor_default()
 8435                            .hoverable_tooltip(move |_window, cx| {
 8436                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8437                            })
 8438                    })
 8439                    .children(keybind),
 8440            )
 8441            .into_any();
 8442
 8443        let longest_row =
 8444            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8445        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8446            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8447        } else {
 8448            layout_line(
 8449                longest_row,
 8450                editor_snapshot,
 8451                style,
 8452                editor_width,
 8453                |_| false,
 8454                window,
 8455                cx,
 8456            )
 8457            .width
 8458        };
 8459
 8460        let viewport_bounds =
 8461            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8462                right: -right_margin,
 8463                ..Default::default()
 8464            });
 8465
 8466        let x_after_longest =
 8467            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8468                - scroll_pixel_position.x;
 8469
 8470        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8471
 8472        // Fully visible if it can be displayed within the window (allow overlapping other
 8473        // panes). However, this is only allowed if the popover starts within text_bounds.
 8474        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8475            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8476
 8477        let mut origin = if can_position_to_the_right {
 8478            point(
 8479                x_after_longest,
 8480                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8481                    - scroll_pixel_position.y,
 8482            )
 8483        } else {
 8484            let cursor_row = newest_selection_head.map(|head| head.row());
 8485            let above_edit = edit_start
 8486                .row()
 8487                .0
 8488                .checked_sub(line_count as u32)
 8489                .map(DisplayRow);
 8490            let below_edit = Some(edit_end.row() + 1);
 8491            let above_cursor =
 8492                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8493            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8494
 8495            // Place the edit popover adjacent to the edit if there is a location
 8496            // available that is onscreen and does not obscure the cursor. Otherwise,
 8497            // place it adjacent to the cursor.
 8498            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8499                .into_iter()
 8500                .flatten()
 8501                .find(|&start_row| {
 8502                    let end_row = start_row + line_count as u32;
 8503                    visible_row_range.contains(&start_row)
 8504                        && visible_row_range.contains(&end_row)
 8505                        && cursor_row.map_or(true, |cursor_row| {
 8506                            !((start_row..end_row).contains(&cursor_row))
 8507                        })
 8508                })?;
 8509
 8510            content_origin
 8511                + point(
 8512                    -scroll_pixel_position.x,
 8513                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8514                )
 8515        };
 8516
 8517        origin.x -= BORDER_WIDTH;
 8518
 8519        window.defer_draw(element, origin, 1);
 8520
 8521        // Do not return an element, since it will already be drawn due to defer_draw.
 8522        None
 8523    }
 8524
 8525    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8526        px(30.)
 8527    }
 8528
 8529    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8530        if self.read_only(cx) {
 8531            cx.theme().players().read_only()
 8532        } else {
 8533            self.style.as_ref().unwrap().local_player
 8534        }
 8535    }
 8536
 8537    fn render_edit_prediction_accept_keybind(
 8538        &self,
 8539        window: &mut Window,
 8540        cx: &App,
 8541    ) -> Option<AnyElement> {
 8542        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8543        let accept_keystroke = accept_binding.keystroke()?;
 8544
 8545        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8546
 8547        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8548            Color::Accent
 8549        } else {
 8550            Color::Muted
 8551        };
 8552
 8553        h_flex()
 8554            .px_0p5()
 8555            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8556            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8557            .text_size(TextSize::XSmall.rems(cx))
 8558            .child(h_flex().children(ui::render_modifiers(
 8559                &accept_keystroke.modifiers,
 8560                PlatformStyle::platform(),
 8561                Some(modifiers_color),
 8562                Some(IconSize::XSmall.rems().into()),
 8563                true,
 8564            )))
 8565            .when(is_platform_style_mac, |parent| {
 8566                parent.child(accept_keystroke.key.clone())
 8567            })
 8568            .when(!is_platform_style_mac, |parent| {
 8569                parent.child(
 8570                    Key::new(
 8571                        util::capitalize(&accept_keystroke.key),
 8572                        Some(Color::Default),
 8573                    )
 8574                    .size(Some(IconSize::XSmall.rems().into())),
 8575                )
 8576            })
 8577            .into_any()
 8578            .into()
 8579    }
 8580
 8581    fn render_edit_prediction_line_popover(
 8582        &self,
 8583        label: impl Into<SharedString>,
 8584        icon: Option<IconName>,
 8585        window: &mut Window,
 8586        cx: &App,
 8587    ) -> Option<Stateful<Div>> {
 8588        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8589
 8590        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8591        let has_keybind = keybind.is_some();
 8592
 8593        let result = h_flex()
 8594            .id("ep-line-popover")
 8595            .py_0p5()
 8596            .pl_1()
 8597            .pr(padding_right)
 8598            .gap_1()
 8599            .rounded_md()
 8600            .border_1()
 8601            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8602            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8603            .shadow_sm()
 8604            .when(!has_keybind, |el| {
 8605                let status_colors = cx.theme().status();
 8606
 8607                el.bg(status_colors.error_background)
 8608                    .border_color(status_colors.error.opacity(0.6))
 8609                    .pl_2()
 8610                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8611                    .cursor_default()
 8612                    .hoverable_tooltip(move |_window, cx| {
 8613                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8614                    })
 8615            })
 8616            .children(keybind)
 8617            .child(
 8618                Label::new(label)
 8619                    .size(LabelSize::Small)
 8620                    .when(!has_keybind, |el| {
 8621                        el.color(cx.theme().status().error.into()).strikethrough()
 8622                    }),
 8623            )
 8624            .when(!has_keybind, |el| {
 8625                el.child(
 8626                    h_flex().ml_1().child(
 8627                        Icon::new(IconName::Info)
 8628                            .size(IconSize::Small)
 8629                            .color(cx.theme().status().error.into()),
 8630                    ),
 8631                )
 8632            })
 8633            .when_some(icon, |element, icon| {
 8634                element.child(
 8635                    div()
 8636                        .mt(px(1.5))
 8637                        .child(Icon::new(icon).size(IconSize::Small)),
 8638                )
 8639            });
 8640
 8641        Some(result)
 8642    }
 8643
 8644    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8645        let accent_color = cx.theme().colors().text_accent;
 8646        let editor_bg_color = cx.theme().colors().editor_background;
 8647        editor_bg_color.blend(accent_color.opacity(0.1))
 8648    }
 8649
 8650    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8651        let accent_color = cx.theme().colors().text_accent;
 8652        let editor_bg_color = cx.theme().colors().editor_background;
 8653        editor_bg_color.blend(accent_color.opacity(0.6))
 8654    }
 8655
 8656    fn render_edit_prediction_cursor_popover(
 8657        &self,
 8658        min_width: Pixels,
 8659        max_width: Pixels,
 8660        cursor_point: Point,
 8661        style: &EditorStyle,
 8662        accept_keystroke: Option<&gpui::Keystroke>,
 8663        _window: &Window,
 8664        cx: &mut Context<Editor>,
 8665    ) -> Option<AnyElement> {
 8666        let provider = self.edit_prediction_provider.as_ref()?;
 8667
 8668        if provider.provider.needs_terms_acceptance(cx) {
 8669            return Some(
 8670                h_flex()
 8671                    .min_w(min_width)
 8672                    .flex_1()
 8673                    .px_2()
 8674                    .py_1()
 8675                    .gap_3()
 8676                    .elevation_2(cx)
 8677                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8678                    .id("accept-terms")
 8679                    .cursor_pointer()
 8680                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8681                    .on_click(cx.listener(|this, _event, window, cx| {
 8682                        cx.stop_propagation();
 8683                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8684                        window.dispatch_action(
 8685                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8686                            cx,
 8687                        );
 8688                    }))
 8689                    .child(
 8690                        h_flex()
 8691                            .flex_1()
 8692                            .gap_2()
 8693                            .child(Icon::new(IconName::ZedPredict))
 8694                            .child(Label::new("Accept Terms of Service"))
 8695                            .child(div().w_full())
 8696                            .child(
 8697                                Icon::new(IconName::ArrowUpRight)
 8698                                    .color(Color::Muted)
 8699                                    .size(IconSize::Small),
 8700                            )
 8701                            .into_any_element(),
 8702                    )
 8703                    .into_any(),
 8704            );
 8705        }
 8706
 8707        let is_refreshing = provider.provider.is_refreshing(cx);
 8708
 8709        fn pending_completion_container() -> Div {
 8710            h_flex()
 8711                .h_full()
 8712                .flex_1()
 8713                .gap_2()
 8714                .child(Icon::new(IconName::ZedPredict))
 8715        }
 8716
 8717        let completion = match &self.active_inline_completion {
 8718            Some(prediction) => {
 8719                if !self.has_visible_completions_menu() {
 8720                    const RADIUS: Pixels = px(6.);
 8721                    const BORDER_WIDTH: Pixels = px(1.);
 8722
 8723                    return Some(
 8724                        h_flex()
 8725                            .elevation_2(cx)
 8726                            .border(BORDER_WIDTH)
 8727                            .border_color(cx.theme().colors().border)
 8728                            .when(accept_keystroke.is_none(), |el| {
 8729                                el.border_color(cx.theme().status().error)
 8730                            })
 8731                            .rounded(RADIUS)
 8732                            .rounded_tl(px(0.))
 8733                            .overflow_hidden()
 8734                            .child(div().px_1p5().child(match &prediction.completion {
 8735                                InlineCompletion::Move { target, snapshot } => {
 8736                                    use text::ToPoint as _;
 8737                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8738                                    {
 8739                                        Icon::new(IconName::ZedPredictDown)
 8740                                    } else {
 8741                                        Icon::new(IconName::ZedPredictUp)
 8742                                    }
 8743                                }
 8744                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8745                            }))
 8746                            .child(
 8747                                h_flex()
 8748                                    .gap_1()
 8749                                    .py_1()
 8750                                    .px_2()
 8751                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8752                                    .border_l_1()
 8753                                    .border_color(cx.theme().colors().border)
 8754                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8755                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8756                                        el.child(
 8757                                            Label::new("Hold")
 8758                                                .size(LabelSize::Small)
 8759                                                .when(accept_keystroke.is_none(), |el| {
 8760                                                    el.strikethrough()
 8761                                                })
 8762                                                .line_height_style(LineHeightStyle::UiLabel),
 8763                                        )
 8764                                    })
 8765                                    .id("edit_prediction_cursor_popover_keybind")
 8766                                    .when(accept_keystroke.is_none(), |el| {
 8767                                        let status_colors = cx.theme().status();
 8768
 8769                                        el.bg(status_colors.error_background)
 8770                                            .border_color(status_colors.error.opacity(0.6))
 8771                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8772                                            .cursor_default()
 8773                                            .hoverable_tooltip(move |_window, cx| {
 8774                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8775                                                    .into()
 8776                                            })
 8777                                    })
 8778                                    .when_some(
 8779                                        accept_keystroke.as_ref(),
 8780                                        |el, accept_keystroke| {
 8781                                            el.child(h_flex().children(ui::render_modifiers(
 8782                                                &accept_keystroke.modifiers,
 8783                                                PlatformStyle::platform(),
 8784                                                Some(Color::Default),
 8785                                                Some(IconSize::XSmall.rems().into()),
 8786                                                false,
 8787                                            )))
 8788                                        },
 8789                                    ),
 8790                            )
 8791                            .into_any(),
 8792                    );
 8793                }
 8794
 8795                self.render_edit_prediction_cursor_popover_preview(
 8796                    prediction,
 8797                    cursor_point,
 8798                    style,
 8799                    cx,
 8800                )?
 8801            }
 8802
 8803            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8804                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8805                    stale_completion,
 8806                    cursor_point,
 8807                    style,
 8808                    cx,
 8809                )?,
 8810
 8811                None => {
 8812                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8813                }
 8814            },
 8815
 8816            None => pending_completion_container().child(Label::new("No Prediction")),
 8817        };
 8818
 8819        let completion = if is_refreshing {
 8820            completion
 8821                .with_animation(
 8822                    "loading-completion",
 8823                    Animation::new(Duration::from_secs(2))
 8824                        .repeat()
 8825                        .with_easing(pulsating_between(0.4, 0.8)),
 8826                    |label, delta| label.opacity(delta),
 8827                )
 8828                .into_any_element()
 8829        } else {
 8830            completion.into_any_element()
 8831        };
 8832
 8833        let has_completion = self.active_inline_completion.is_some();
 8834
 8835        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8836        Some(
 8837            h_flex()
 8838                .min_w(min_width)
 8839                .max_w(max_width)
 8840                .flex_1()
 8841                .elevation_2(cx)
 8842                .border_color(cx.theme().colors().border)
 8843                .child(
 8844                    div()
 8845                        .flex_1()
 8846                        .py_1()
 8847                        .px_2()
 8848                        .overflow_hidden()
 8849                        .child(completion),
 8850                )
 8851                .when_some(accept_keystroke, |el, accept_keystroke| {
 8852                    if !accept_keystroke.modifiers.modified() {
 8853                        return el;
 8854                    }
 8855
 8856                    el.child(
 8857                        h_flex()
 8858                            .h_full()
 8859                            .border_l_1()
 8860                            .rounded_r_lg()
 8861                            .border_color(cx.theme().colors().border)
 8862                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8863                            .gap_1()
 8864                            .py_1()
 8865                            .px_2()
 8866                            .child(
 8867                                h_flex()
 8868                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8869                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8870                                    .child(h_flex().children(ui::render_modifiers(
 8871                                        &accept_keystroke.modifiers,
 8872                                        PlatformStyle::platform(),
 8873                                        Some(if !has_completion {
 8874                                            Color::Muted
 8875                                        } else {
 8876                                            Color::Default
 8877                                        }),
 8878                                        None,
 8879                                        false,
 8880                                    ))),
 8881                            )
 8882                            .child(Label::new("Preview").into_any_element())
 8883                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8884                    )
 8885                })
 8886                .into_any(),
 8887        )
 8888    }
 8889
 8890    fn render_edit_prediction_cursor_popover_preview(
 8891        &self,
 8892        completion: &InlineCompletionState,
 8893        cursor_point: Point,
 8894        style: &EditorStyle,
 8895        cx: &mut Context<Editor>,
 8896    ) -> Option<Div> {
 8897        use text::ToPoint as _;
 8898
 8899        fn render_relative_row_jump(
 8900            prefix: impl Into<String>,
 8901            current_row: u32,
 8902            target_row: u32,
 8903        ) -> Div {
 8904            let (row_diff, arrow) = if target_row < current_row {
 8905                (current_row - target_row, IconName::ArrowUp)
 8906            } else {
 8907                (target_row - current_row, IconName::ArrowDown)
 8908            };
 8909
 8910            h_flex()
 8911                .child(
 8912                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8913                        .color(Color::Muted)
 8914                        .size(LabelSize::Small),
 8915                )
 8916                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8917        }
 8918
 8919        match &completion.completion {
 8920            InlineCompletion::Move {
 8921                target, snapshot, ..
 8922            } => Some(
 8923                h_flex()
 8924                    .px_2()
 8925                    .gap_2()
 8926                    .flex_1()
 8927                    .child(
 8928                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8929                            Icon::new(IconName::ZedPredictDown)
 8930                        } else {
 8931                            Icon::new(IconName::ZedPredictUp)
 8932                        },
 8933                    )
 8934                    .child(Label::new("Jump to Edit")),
 8935            ),
 8936
 8937            InlineCompletion::Edit {
 8938                edits,
 8939                edit_preview,
 8940                snapshot,
 8941                display_mode: _,
 8942            } => {
 8943                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8944
 8945                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8946                    &snapshot,
 8947                    &edits,
 8948                    edit_preview.as_ref()?,
 8949                    true,
 8950                    cx,
 8951                )
 8952                .first_line_preview();
 8953
 8954                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8955                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8956
 8957                let preview = h_flex()
 8958                    .gap_1()
 8959                    .min_w_16()
 8960                    .child(styled_text)
 8961                    .when(has_more_lines, |parent| parent.child(""));
 8962
 8963                let left = if first_edit_row != cursor_point.row {
 8964                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8965                        .into_any_element()
 8966                } else {
 8967                    Icon::new(IconName::ZedPredict).into_any_element()
 8968                };
 8969
 8970                Some(
 8971                    h_flex()
 8972                        .h_full()
 8973                        .flex_1()
 8974                        .gap_2()
 8975                        .pr_1()
 8976                        .overflow_x_hidden()
 8977                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8978                        .child(left)
 8979                        .child(preview),
 8980                )
 8981            }
 8982        }
 8983    }
 8984
 8985    pub fn render_context_menu(
 8986        &self,
 8987        style: &EditorStyle,
 8988        max_height_in_lines: u32,
 8989        window: &mut Window,
 8990        cx: &mut Context<Editor>,
 8991    ) -> Option<AnyElement> {
 8992        let menu = self.context_menu.borrow();
 8993        let menu = menu.as_ref()?;
 8994        if !menu.visible() {
 8995            return None;
 8996        };
 8997        Some(menu.render(style, max_height_in_lines, window, cx))
 8998    }
 8999
 9000    fn render_context_menu_aside(
 9001        &mut self,
 9002        max_size: Size<Pixels>,
 9003        window: &mut Window,
 9004        cx: &mut Context<Editor>,
 9005    ) -> Option<AnyElement> {
 9006        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9007            if menu.visible() {
 9008                menu.render_aside(max_size, window, cx)
 9009            } else {
 9010                None
 9011            }
 9012        })
 9013    }
 9014
 9015    fn hide_context_menu(
 9016        &mut self,
 9017        window: &mut Window,
 9018        cx: &mut Context<Self>,
 9019    ) -> Option<CodeContextMenu> {
 9020        cx.notify();
 9021        self.completion_tasks.clear();
 9022        let context_menu = self.context_menu.borrow_mut().take();
 9023        self.stale_inline_completion_in_menu.take();
 9024        self.update_visible_inline_completion(window, cx);
 9025        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9026            if let Some(completion_provider) = &self.completion_provider {
 9027                completion_provider.selection_changed(None, window, cx);
 9028            }
 9029        }
 9030        context_menu
 9031    }
 9032
 9033    fn show_snippet_choices(
 9034        &mut self,
 9035        choices: &Vec<String>,
 9036        selection: Range<Anchor>,
 9037        cx: &mut Context<Self>,
 9038    ) {
 9039        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9040            (Some(a), Some(b)) if a == b => a,
 9041            _ => {
 9042                log::error!("expected anchor range to have matching buffer IDs");
 9043                return;
 9044            }
 9045        };
 9046        let multi_buffer = self.buffer().read(cx);
 9047        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9048            return;
 9049        };
 9050
 9051        let id = post_inc(&mut self.next_completion_id);
 9052        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9053        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9054            CompletionsMenu::new_snippet_choices(
 9055                id,
 9056                true,
 9057                choices,
 9058                selection,
 9059                buffer,
 9060                snippet_sort_order,
 9061            ),
 9062        ));
 9063    }
 9064
 9065    pub fn insert_snippet(
 9066        &mut self,
 9067        insertion_ranges: &[Range<usize>],
 9068        snippet: Snippet,
 9069        window: &mut Window,
 9070        cx: &mut Context<Self>,
 9071    ) -> Result<()> {
 9072        struct Tabstop<T> {
 9073            is_end_tabstop: bool,
 9074            ranges: Vec<Range<T>>,
 9075            choices: Option<Vec<String>>,
 9076        }
 9077
 9078        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9079            let snippet_text: Arc<str> = snippet.text.clone().into();
 9080            let edits = insertion_ranges
 9081                .iter()
 9082                .cloned()
 9083                .map(|range| (range, snippet_text.clone()));
 9084            let autoindent_mode = AutoindentMode::Block {
 9085                original_indent_columns: Vec::new(),
 9086            };
 9087            buffer.edit(edits, Some(autoindent_mode), cx);
 9088
 9089            let snapshot = &*buffer.read(cx);
 9090            let snippet = &snippet;
 9091            snippet
 9092                .tabstops
 9093                .iter()
 9094                .map(|tabstop| {
 9095                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9096                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9097                    });
 9098                    let mut tabstop_ranges = tabstop
 9099                        .ranges
 9100                        .iter()
 9101                        .flat_map(|tabstop_range| {
 9102                            let mut delta = 0_isize;
 9103                            insertion_ranges.iter().map(move |insertion_range| {
 9104                                let insertion_start = insertion_range.start as isize + delta;
 9105                                delta +=
 9106                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9107
 9108                                let start = ((insertion_start + tabstop_range.start) as usize)
 9109                                    .min(snapshot.len());
 9110                                let end = ((insertion_start + tabstop_range.end) as usize)
 9111                                    .min(snapshot.len());
 9112                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9113                            })
 9114                        })
 9115                        .collect::<Vec<_>>();
 9116                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9117
 9118                    Tabstop {
 9119                        is_end_tabstop,
 9120                        ranges: tabstop_ranges,
 9121                        choices: tabstop.choices.clone(),
 9122                    }
 9123                })
 9124                .collect::<Vec<_>>()
 9125        });
 9126        if let Some(tabstop) = tabstops.first() {
 9127            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9128                // Reverse order so that the first range is the newest created selection.
 9129                // Completions will use it and autoscroll will prioritize it.
 9130                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9131            });
 9132
 9133            if let Some(choices) = &tabstop.choices {
 9134                if let Some(selection) = tabstop.ranges.first() {
 9135                    self.show_snippet_choices(choices, selection.clone(), cx)
 9136                }
 9137            }
 9138
 9139            // If we're already at the last tabstop and it's at the end of the snippet,
 9140            // we're done, we don't need to keep the state around.
 9141            if !tabstop.is_end_tabstop {
 9142                let choices = tabstops
 9143                    .iter()
 9144                    .map(|tabstop| tabstop.choices.clone())
 9145                    .collect();
 9146
 9147                let ranges = tabstops
 9148                    .into_iter()
 9149                    .map(|tabstop| tabstop.ranges)
 9150                    .collect::<Vec<_>>();
 9151
 9152                self.snippet_stack.push(SnippetState {
 9153                    active_index: 0,
 9154                    ranges,
 9155                    choices,
 9156                });
 9157            }
 9158
 9159            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9160            if self.autoclose_regions.is_empty() {
 9161                let snapshot = self.buffer.read(cx).snapshot(cx);
 9162                for selection in &mut self.selections.all::<Point>(cx) {
 9163                    let selection_head = selection.head();
 9164                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9165                        continue;
 9166                    };
 9167
 9168                    let mut bracket_pair = None;
 9169                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9170                    let prev_chars = snapshot
 9171                        .reversed_chars_at(selection_head)
 9172                        .collect::<String>();
 9173                    for (pair, enabled) in scope.brackets() {
 9174                        if enabled
 9175                            && pair.close
 9176                            && prev_chars.starts_with(pair.start.as_str())
 9177                            && next_chars.starts_with(pair.end.as_str())
 9178                        {
 9179                            bracket_pair = Some(pair.clone());
 9180                            break;
 9181                        }
 9182                    }
 9183                    if let Some(pair) = bracket_pair {
 9184                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9185                        let autoclose_enabled =
 9186                            self.use_autoclose && snapshot_settings.use_autoclose;
 9187                        if autoclose_enabled {
 9188                            let start = snapshot.anchor_after(selection_head);
 9189                            let end = snapshot.anchor_after(selection_head);
 9190                            self.autoclose_regions.push(AutocloseRegion {
 9191                                selection_id: selection.id,
 9192                                range: start..end,
 9193                                pair,
 9194                            });
 9195                        }
 9196                    }
 9197                }
 9198            }
 9199        }
 9200        Ok(())
 9201    }
 9202
 9203    pub fn move_to_next_snippet_tabstop(
 9204        &mut self,
 9205        window: &mut Window,
 9206        cx: &mut Context<Self>,
 9207    ) -> bool {
 9208        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9209    }
 9210
 9211    pub fn move_to_prev_snippet_tabstop(
 9212        &mut self,
 9213        window: &mut Window,
 9214        cx: &mut Context<Self>,
 9215    ) -> bool {
 9216        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9217    }
 9218
 9219    pub fn move_to_snippet_tabstop(
 9220        &mut self,
 9221        bias: Bias,
 9222        window: &mut Window,
 9223        cx: &mut Context<Self>,
 9224    ) -> bool {
 9225        if let Some(mut snippet) = self.snippet_stack.pop() {
 9226            match bias {
 9227                Bias::Left => {
 9228                    if snippet.active_index > 0 {
 9229                        snippet.active_index -= 1;
 9230                    } else {
 9231                        self.snippet_stack.push(snippet);
 9232                        return false;
 9233                    }
 9234                }
 9235                Bias::Right => {
 9236                    if snippet.active_index + 1 < snippet.ranges.len() {
 9237                        snippet.active_index += 1;
 9238                    } else {
 9239                        self.snippet_stack.push(snippet);
 9240                        return false;
 9241                    }
 9242                }
 9243            }
 9244            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9245                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9246                    // Reverse order so that the first range is the newest created selection.
 9247                    // Completions will use it and autoscroll will prioritize it.
 9248                    s.select_ranges(current_ranges.iter().rev().cloned())
 9249                });
 9250
 9251                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9252                    if let Some(selection) = current_ranges.first() {
 9253                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9254                    }
 9255                }
 9256
 9257                // If snippet state is not at the last tabstop, push it back on the stack
 9258                if snippet.active_index + 1 < snippet.ranges.len() {
 9259                    self.snippet_stack.push(snippet);
 9260                }
 9261                return true;
 9262            }
 9263        }
 9264
 9265        false
 9266    }
 9267
 9268    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9269        self.transact(window, cx, |this, window, cx| {
 9270            this.select_all(&SelectAll, window, cx);
 9271            this.insert("", window, cx);
 9272        });
 9273    }
 9274
 9275    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9276        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9277        self.transact(window, cx, |this, window, cx| {
 9278            this.select_autoclose_pair(window, cx);
 9279            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9280            if !this.linked_edit_ranges.is_empty() {
 9281                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9282                let snapshot = this.buffer.read(cx).snapshot(cx);
 9283
 9284                for selection in selections.iter() {
 9285                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9286                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9287                    if selection_start.buffer_id != selection_end.buffer_id {
 9288                        continue;
 9289                    }
 9290                    if let Some(ranges) =
 9291                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9292                    {
 9293                        for (buffer, entries) in ranges {
 9294                            linked_ranges.entry(buffer).or_default().extend(entries);
 9295                        }
 9296                    }
 9297                }
 9298            }
 9299
 9300            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9301            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9302            for selection in &mut selections {
 9303                if selection.is_empty() {
 9304                    let old_head = selection.head();
 9305                    let mut new_head =
 9306                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9307                            .to_point(&display_map);
 9308                    if let Some((buffer, line_buffer_range)) = display_map
 9309                        .buffer_snapshot
 9310                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9311                    {
 9312                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9313                        let indent_len = match indent_size.kind {
 9314                            IndentKind::Space => {
 9315                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9316                            }
 9317                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9318                        };
 9319                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9320                            let indent_len = indent_len.get();
 9321                            new_head = cmp::min(
 9322                                new_head,
 9323                                MultiBufferPoint::new(
 9324                                    old_head.row,
 9325                                    ((old_head.column - 1) / indent_len) * indent_len,
 9326                                ),
 9327                            );
 9328                        }
 9329                    }
 9330
 9331                    selection.set_head(new_head, SelectionGoal::None);
 9332                }
 9333            }
 9334
 9335            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9336                s.select(selections)
 9337            });
 9338            this.insert("", window, cx);
 9339            let empty_str: Arc<str> = Arc::from("");
 9340            for (buffer, edits) in linked_ranges {
 9341                let snapshot = buffer.read(cx).snapshot();
 9342                use text::ToPoint as TP;
 9343
 9344                let edits = edits
 9345                    .into_iter()
 9346                    .map(|range| {
 9347                        let end_point = TP::to_point(&range.end, &snapshot);
 9348                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9349
 9350                        if end_point == start_point {
 9351                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9352                                .saturating_sub(1);
 9353                            start_point =
 9354                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9355                        };
 9356
 9357                        (start_point..end_point, empty_str.clone())
 9358                    })
 9359                    .sorted_by_key(|(range, _)| range.start)
 9360                    .collect::<Vec<_>>();
 9361                buffer.update(cx, |this, cx| {
 9362                    this.edit(edits, None, cx);
 9363                })
 9364            }
 9365            this.refresh_inline_completion(true, false, window, cx);
 9366            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9367        });
 9368    }
 9369
 9370    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9371        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9372        self.transact(window, cx, |this, window, cx| {
 9373            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9374                s.move_with(|map, selection| {
 9375                    if selection.is_empty() {
 9376                        let cursor = movement::right(map, selection.head());
 9377                        selection.end = cursor;
 9378                        selection.reversed = true;
 9379                        selection.goal = SelectionGoal::None;
 9380                    }
 9381                })
 9382            });
 9383            this.insert("", window, cx);
 9384            this.refresh_inline_completion(true, false, window, cx);
 9385        });
 9386    }
 9387
 9388    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9389        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9390        if self.move_to_prev_snippet_tabstop(window, cx) {
 9391            return;
 9392        }
 9393        self.outdent(&Outdent, window, cx);
 9394    }
 9395
 9396    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9397        if self.move_to_next_snippet_tabstop(window, cx) {
 9398            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9399            return;
 9400        }
 9401        if self.read_only(cx) {
 9402            return;
 9403        }
 9404        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9405        let mut selections = self.selections.all_adjusted(cx);
 9406        let buffer = self.buffer.read(cx);
 9407        let snapshot = buffer.snapshot(cx);
 9408        let rows_iter = selections.iter().map(|s| s.head().row);
 9409        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9410
 9411        let has_some_cursor_in_whitespace = selections
 9412            .iter()
 9413            .filter(|selection| selection.is_empty())
 9414            .any(|selection| {
 9415                let cursor = selection.head();
 9416                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9417                cursor.column < current_indent.len
 9418            });
 9419
 9420        let mut edits = Vec::new();
 9421        let mut prev_edited_row = 0;
 9422        let mut row_delta = 0;
 9423        for selection in &mut selections {
 9424            if selection.start.row != prev_edited_row {
 9425                row_delta = 0;
 9426            }
 9427            prev_edited_row = selection.end.row;
 9428
 9429            // If the selection is non-empty, then increase the indentation of the selected lines.
 9430            if !selection.is_empty() {
 9431                row_delta =
 9432                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9433                continue;
 9434            }
 9435
 9436            let cursor = selection.head();
 9437            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9438            if let Some(suggested_indent) =
 9439                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9440            {
 9441                // Don't do anything if already at suggested indent
 9442                // and there is any other cursor which is not
 9443                if has_some_cursor_in_whitespace
 9444                    && cursor.column == current_indent.len
 9445                    && current_indent.len == suggested_indent.len
 9446                {
 9447                    continue;
 9448                }
 9449
 9450                // Adjust line and move cursor to suggested indent
 9451                // if cursor is not at suggested indent
 9452                if cursor.column < suggested_indent.len
 9453                    && cursor.column <= current_indent.len
 9454                    && current_indent.len <= suggested_indent.len
 9455                {
 9456                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9457                    selection.end = selection.start;
 9458                    if row_delta == 0 {
 9459                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9460                            cursor.row,
 9461                            current_indent,
 9462                            suggested_indent,
 9463                        ));
 9464                        row_delta = suggested_indent.len - current_indent.len;
 9465                    }
 9466                    continue;
 9467                }
 9468
 9469                // If current indent is more than suggested indent
 9470                // only move cursor to current indent and skip indent
 9471                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9472                    selection.start = Point::new(cursor.row, current_indent.len);
 9473                    selection.end = selection.start;
 9474                    continue;
 9475                }
 9476            }
 9477
 9478            // Otherwise, insert a hard or soft tab.
 9479            let settings = buffer.language_settings_at(cursor, cx);
 9480            let tab_size = if settings.hard_tabs {
 9481                IndentSize::tab()
 9482            } else {
 9483                let tab_size = settings.tab_size.get();
 9484                let indent_remainder = snapshot
 9485                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9486                    .flat_map(str::chars)
 9487                    .fold(row_delta % tab_size, |counter: u32, c| {
 9488                        if c == '\t' {
 9489                            0
 9490                        } else {
 9491                            (counter + 1) % tab_size
 9492                        }
 9493                    });
 9494
 9495                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9496                IndentSize::spaces(chars_to_next_tab_stop)
 9497            };
 9498            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9499            selection.end = selection.start;
 9500            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9501            row_delta += tab_size.len;
 9502        }
 9503
 9504        self.transact(window, cx, |this, window, cx| {
 9505            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9506            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9507                s.select(selections)
 9508            });
 9509            this.refresh_inline_completion(true, false, window, cx);
 9510        });
 9511    }
 9512
 9513    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9514        if self.read_only(cx) {
 9515            return;
 9516        }
 9517        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9518        let mut selections = self.selections.all::<Point>(cx);
 9519        let mut prev_edited_row = 0;
 9520        let mut row_delta = 0;
 9521        let mut edits = Vec::new();
 9522        let buffer = self.buffer.read(cx);
 9523        let snapshot = buffer.snapshot(cx);
 9524        for selection in &mut selections {
 9525            if selection.start.row != prev_edited_row {
 9526                row_delta = 0;
 9527            }
 9528            prev_edited_row = selection.end.row;
 9529
 9530            row_delta =
 9531                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9532        }
 9533
 9534        self.transact(window, cx, |this, window, cx| {
 9535            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9536            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9537                s.select(selections)
 9538            });
 9539        });
 9540    }
 9541
 9542    fn indent_selection(
 9543        buffer: &MultiBuffer,
 9544        snapshot: &MultiBufferSnapshot,
 9545        selection: &mut Selection<Point>,
 9546        edits: &mut Vec<(Range<Point>, String)>,
 9547        delta_for_start_row: u32,
 9548        cx: &App,
 9549    ) -> u32 {
 9550        let settings = buffer.language_settings_at(selection.start, cx);
 9551        let tab_size = settings.tab_size.get();
 9552        let indent_kind = if settings.hard_tabs {
 9553            IndentKind::Tab
 9554        } else {
 9555            IndentKind::Space
 9556        };
 9557        let mut start_row = selection.start.row;
 9558        let mut end_row = selection.end.row + 1;
 9559
 9560        // If a selection ends at the beginning of a line, don't indent
 9561        // that last line.
 9562        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9563            end_row -= 1;
 9564        }
 9565
 9566        // Avoid re-indenting a row that has already been indented by a
 9567        // previous selection, but still update this selection's column
 9568        // to reflect that indentation.
 9569        if delta_for_start_row > 0 {
 9570            start_row += 1;
 9571            selection.start.column += delta_for_start_row;
 9572            if selection.end.row == selection.start.row {
 9573                selection.end.column += delta_for_start_row;
 9574            }
 9575        }
 9576
 9577        let mut delta_for_end_row = 0;
 9578        let has_multiple_rows = start_row + 1 != end_row;
 9579        for row in start_row..end_row {
 9580            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9581            let indent_delta = match (current_indent.kind, indent_kind) {
 9582                (IndentKind::Space, IndentKind::Space) => {
 9583                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9584                    IndentSize::spaces(columns_to_next_tab_stop)
 9585                }
 9586                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9587                (_, IndentKind::Tab) => IndentSize::tab(),
 9588            };
 9589
 9590            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9591                0
 9592            } else {
 9593                selection.start.column
 9594            };
 9595            let row_start = Point::new(row, start);
 9596            edits.push((
 9597                row_start..row_start,
 9598                indent_delta.chars().collect::<String>(),
 9599            ));
 9600
 9601            // Update this selection's endpoints to reflect the indentation.
 9602            if row == selection.start.row {
 9603                selection.start.column += indent_delta.len;
 9604            }
 9605            if row == selection.end.row {
 9606                selection.end.column += indent_delta.len;
 9607                delta_for_end_row = indent_delta.len;
 9608            }
 9609        }
 9610
 9611        if selection.start.row == selection.end.row {
 9612            delta_for_start_row + delta_for_end_row
 9613        } else {
 9614            delta_for_end_row
 9615        }
 9616    }
 9617
 9618    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9619        if self.read_only(cx) {
 9620            return;
 9621        }
 9622        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9623        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9624        let selections = self.selections.all::<Point>(cx);
 9625        let mut deletion_ranges = Vec::new();
 9626        let mut last_outdent = None;
 9627        {
 9628            let buffer = self.buffer.read(cx);
 9629            let snapshot = buffer.snapshot(cx);
 9630            for selection in &selections {
 9631                let settings = buffer.language_settings_at(selection.start, cx);
 9632                let tab_size = settings.tab_size.get();
 9633                let mut rows = selection.spanned_rows(false, &display_map);
 9634
 9635                // Avoid re-outdenting a row that has already been outdented by a
 9636                // previous selection.
 9637                if let Some(last_row) = last_outdent {
 9638                    if last_row == rows.start {
 9639                        rows.start = rows.start.next_row();
 9640                    }
 9641                }
 9642                let has_multiple_rows = rows.len() > 1;
 9643                for row in rows.iter_rows() {
 9644                    let indent_size = snapshot.indent_size_for_line(row);
 9645                    if indent_size.len > 0 {
 9646                        let deletion_len = match indent_size.kind {
 9647                            IndentKind::Space => {
 9648                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9649                                if columns_to_prev_tab_stop == 0 {
 9650                                    tab_size
 9651                                } else {
 9652                                    columns_to_prev_tab_stop
 9653                                }
 9654                            }
 9655                            IndentKind::Tab => 1,
 9656                        };
 9657                        let start = if has_multiple_rows
 9658                            || deletion_len > selection.start.column
 9659                            || indent_size.len < selection.start.column
 9660                        {
 9661                            0
 9662                        } else {
 9663                            selection.start.column - deletion_len
 9664                        };
 9665                        deletion_ranges.push(
 9666                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9667                        );
 9668                        last_outdent = Some(row);
 9669                    }
 9670                }
 9671            }
 9672        }
 9673
 9674        self.transact(window, cx, |this, window, cx| {
 9675            this.buffer.update(cx, |buffer, cx| {
 9676                let empty_str: Arc<str> = Arc::default();
 9677                buffer.edit(
 9678                    deletion_ranges
 9679                        .into_iter()
 9680                        .map(|range| (range, empty_str.clone())),
 9681                    None,
 9682                    cx,
 9683                );
 9684            });
 9685            let selections = this.selections.all::<usize>(cx);
 9686            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9687                s.select(selections)
 9688            });
 9689        });
 9690    }
 9691
 9692    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9693        if self.read_only(cx) {
 9694            return;
 9695        }
 9696        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9697        let selections = self
 9698            .selections
 9699            .all::<usize>(cx)
 9700            .into_iter()
 9701            .map(|s| s.range());
 9702
 9703        self.transact(window, cx, |this, window, cx| {
 9704            this.buffer.update(cx, |buffer, cx| {
 9705                buffer.autoindent_ranges(selections, cx);
 9706            });
 9707            let selections = this.selections.all::<usize>(cx);
 9708            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9709                s.select(selections)
 9710            });
 9711        });
 9712    }
 9713
 9714    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9715        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9716        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9717        let selections = self.selections.all::<Point>(cx);
 9718
 9719        let mut new_cursors = Vec::new();
 9720        let mut edit_ranges = Vec::new();
 9721        let mut selections = selections.iter().peekable();
 9722        while let Some(selection) = selections.next() {
 9723            let mut rows = selection.spanned_rows(false, &display_map);
 9724            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9725
 9726            // Accumulate contiguous regions of rows that we want to delete.
 9727            while let Some(next_selection) = selections.peek() {
 9728                let next_rows = next_selection.spanned_rows(false, &display_map);
 9729                if next_rows.start <= rows.end {
 9730                    rows.end = next_rows.end;
 9731                    selections.next().unwrap();
 9732                } else {
 9733                    break;
 9734                }
 9735            }
 9736
 9737            let buffer = &display_map.buffer_snapshot;
 9738            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9739            let edit_end;
 9740            let cursor_buffer_row;
 9741            if buffer.max_point().row >= rows.end.0 {
 9742                // If there's a line after the range, delete the \n from the end of the row range
 9743                // and position the cursor on the next line.
 9744                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9745                cursor_buffer_row = rows.end;
 9746            } else {
 9747                // If there isn't a line after the range, delete the \n from the line before the
 9748                // start of the row range and position the cursor there.
 9749                edit_start = edit_start.saturating_sub(1);
 9750                edit_end = buffer.len();
 9751                cursor_buffer_row = rows.start.previous_row();
 9752            }
 9753
 9754            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9755            *cursor.column_mut() =
 9756                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9757
 9758            new_cursors.push((
 9759                selection.id,
 9760                buffer.anchor_after(cursor.to_point(&display_map)),
 9761            ));
 9762            edit_ranges.push(edit_start..edit_end);
 9763        }
 9764
 9765        self.transact(window, cx, |this, window, cx| {
 9766            let buffer = this.buffer.update(cx, |buffer, cx| {
 9767                let empty_str: Arc<str> = Arc::default();
 9768                buffer.edit(
 9769                    edit_ranges
 9770                        .into_iter()
 9771                        .map(|range| (range, empty_str.clone())),
 9772                    None,
 9773                    cx,
 9774                );
 9775                buffer.snapshot(cx)
 9776            });
 9777            let new_selections = new_cursors
 9778                .into_iter()
 9779                .map(|(id, cursor)| {
 9780                    let cursor = cursor.to_point(&buffer);
 9781                    Selection {
 9782                        id,
 9783                        start: cursor,
 9784                        end: cursor,
 9785                        reversed: false,
 9786                        goal: SelectionGoal::None,
 9787                    }
 9788                })
 9789                .collect();
 9790
 9791            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9792                s.select(new_selections);
 9793            });
 9794        });
 9795    }
 9796
 9797    pub fn join_lines_impl(
 9798        &mut self,
 9799        insert_whitespace: bool,
 9800        window: &mut Window,
 9801        cx: &mut Context<Self>,
 9802    ) {
 9803        if self.read_only(cx) {
 9804            return;
 9805        }
 9806        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9807        for selection in self.selections.all::<Point>(cx) {
 9808            let start = MultiBufferRow(selection.start.row);
 9809            // Treat single line selections as if they include the next line. Otherwise this action
 9810            // would do nothing for single line selections individual cursors.
 9811            let end = if selection.start.row == selection.end.row {
 9812                MultiBufferRow(selection.start.row + 1)
 9813            } else {
 9814                MultiBufferRow(selection.end.row)
 9815            };
 9816
 9817            if let Some(last_row_range) = row_ranges.last_mut() {
 9818                if start <= last_row_range.end {
 9819                    last_row_range.end = end;
 9820                    continue;
 9821                }
 9822            }
 9823            row_ranges.push(start..end);
 9824        }
 9825
 9826        let snapshot = self.buffer.read(cx).snapshot(cx);
 9827        let mut cursor_positions = Vec::new();
 9828        for row_range in &row_ranges {
 9829            let anchor = snapshot.anchor_before(Point::new(
 9830                row_range.end.previous_row().0,
 9831                snapshot.line_len(row_range.end.previous_row()),
 9832            ));
 9833            cursor_positions.push(anchor..anchor);
 9834        }
 9835
 9836        self.transact(window, cx, |this, window, cx| {
 9837            for row_range in row_ranges.into_iter().rev() {
 9838                for row in row_range.iter_rows().rev() {
 9839                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9840                    let next_line_row = row.next_row();
 9841                    let indent = snapshot.indent_size_for_line(next_line_row);
 9842                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9843
 9844                    let replace =
 9845                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9846                            " "
 9847                        } else {
 9848                            ""
 9849                        };
 9850
 9851                    this.buffer.update(cx, |buffer, cx| {
 9852                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9853                    });
 9854                }
 9855            }
 9856
 9857            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9858                s.select_anchor_ranges(cursor_positions)
 9859            });
 9860        });
 9861    }
 9862
 9863    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9864        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9865        self.join_lines_impl(true, window, cx);
 9866    }
 9867
 9868    pub fn sort_lines_case_sensitive(
 9869        &mut self,
 9870        _: &SortLinesCaseSensitive,
 9871        window: &mut Window,
 9872        cx: &mut Context<Self>,
 9873    ) {
 9874        self.manipulate_lines(window, cx, |lines| lines.sort())
 9875    }
 9876
 9877    pub fn sort_lines_case_insensitive(
 9878        &mut self,
 9879        _: &SortLinesCaseInsensitive,
 9880        window: &mut Window,
 9881        cx: &mut Context<Self>,
 9882    ) {
 9883        self.manipulate_lines(window, cx, |lines| {
 9884            lines.sort_by_key(|line| line.to_lowercase())
 9885        })
 9886    }
 9887
 9888    pub fn unique_lines_case_insensitive(
 9889        &mut self,
 9890        _: &UniqueLinesCaseInsensitive,
 9891        window: &mut Window,
 9892        cx: &mut Context<Self>,
 9893    ) {
 9894        self.manipulate_lines(window, cx, |lines| {
 9895            let mut seen = HashSet::default();
 9896            lines.retain(|line| seen.insert(line.to_lowercase()));
 9897        })
 9898    }
 9899
 9900    pub fn unique_lines_case_sensitive(
 9901        &mut self,
 9902        _: &UniqueLinesCaseSensitive,
 9903        window: &mut Window,
 9904        cx: &mut Context<Self>,
 9905    ) {
 9906        self.manipulate_lines(window, cx, |lines| {
 9907            let mut seen = HashSet::default();
 9908            lines.retain(|line| seen.insert(*line));
 9909        })
 9910    }
 9911
 9912    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9913        let Some(project) = self.project.clone() else {
 9914            return;
 9915        };
 9916        self.reload(project, window, cx)
 9917            .detach_and_notify_err(window, cx);
 9918    }
 9919
 9920    pub fn restore_file(
 9921        &mut self,
 9922        _: &::git::RestoreFile,
 9923        window: &mut Window,
 9924        cx: &mut Context<Self>,
 9925    ) {
 9926        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9927        let mut buffer_ids = HashSet::default();
 9928        let snapshot = self.buffer().read(cx).snapshot(cx);
 9929        for selection in self.selections.all::<usize>(cx) {
 9930            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9931        }
 9932
 9933        let buffer = self.buffer().read(cx);
 9934        let ranges = buffer_ids
 9935            .into_iter()
 9936            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9937            .collect::<Vec<_>>();
 9938
 9939        self.restore_hunks_in_ranges(ranges, window, cx);
 9940    }
 9941
 9942    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9943        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9944        let selections = self
 9945            .selections
 9946            .all(cx)
 9947            .into_iter()
 9948            .map(|s| s.range())
 9949            .collect();
 9950        self.restore_hunks_in_ranges(selections, window, cx);
 9951    }
 9952
 9953    pub fn restore_hunks_in_ranges(
 9954        &mut self,
 9955        ranges: Vec<Range<Point>>,
 9956        window: &mut Window,
 9957        cx: &mut Context<Editor>,
 9958    ) {
 9959        let mut revert_changes = HashMap::default();
 9960        let chunk_by = self
 9961            .snapshot(window, cx)
 9962            .hunks_for_ranges(ranges)
 9963            .into_iter()
 9964            .chunk_by(|hunk| hunk.buffer_id);
 9965        for (buffer_id, hunks) in &chunk_by {
 9966            let hunks = hunks.collect::<Vec<_>>();
 9967            for hunk in &hunks {
 9968                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9969            }
 9970            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9971        }
 9972        drop(chunk_by);
 9973        if !revert_changes.is_empty() {
 9974            self.transact(window, cx, |editor, window, cx| {
 9975                editor.restore(revert_changes, window, cx);
 9976            });
 9977        }
 9978    }
 9979
 9980    pub fn open_active_item_in_terminal(
 9981        &mut self,
 9982        _: &OpenInTerminal,
 9983        window: &mut Window,
 9984        cx: &mut Context<Self>,
 9985    ) {
 9986        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9987            let project_path = buffer.read(cx).project_path(cx)?;
 9988            let project = self.project.as_ref()?.read(cx);
 9989            let entry = project.entry_for_path(&project_path, cx)?;
 9990            let parent = match &entry.canonical_path {
 9991                Some(canonical_path) => canonical_path.to_path_buf(),
 9992                None => project.absolute_path(&project_path, cx)?,
 9993            }
 9994            .parent()?
 9995            .to_path_buf();
 9996            Some(parent)
 9997        }) {
 9998            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9999        }
10000    }
10001
10002    fn set_breakpoint_context_menu(
10003        &mut self,
10004        display_row: DisplayRow,
10005        position: Option<Anchor>,
10006        clicked_point: gpui::Point<Pixels>,
10007        window: &mut Window,
10008        cx: &mut Context<Self>,
10009    ) {
10010        if !cx.has_flag::<DebuggerFeatureFlag>() {
10011            return;
10012        }
10013        let source = self
10014            .buffer
10015            .read(cx)
10016            .snapshot(cx)
10017            .anchor_before(Point::new(display_row.0, 0u32));
10018
10019        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10020
10021        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10022            self,
10023            source,
10024            clicked_point,
10025            context_menu,
10026            window,
10027            cx,
10028        );
10029    }
10030
10031    fn add_edit_breakpoint_block(
10032        &mut self,
10033        anchor: Anchor,
10034        breakpoint: &Breakpoint,
10035        edit_action: BreakpointPromptEditAction,
10036        window: &mut Window,
10037        cx: &mut Context<Self>,
10038    ) {
10039        let weak_editor = cx.weak_entity();
10040        let bp_prompt = cx.new(|cx| {
10041            BreakpointPromptEditor::new(
10042                weak_editor,
10043                anchor,
10044                breakpoint.clone(),
10045                edit_action,
10046                window,
10047                cx,
10048            )
10049        });
10050
10051        let height = bp_prompt.update(cx, |this, cx| {
10052            this.prompt
10053                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10054        });
10055        let cloned_prompt = bp_prompt.clone();
10056        let blocks = vec![BlockProperties {
10057            style: BlockStyle::Sticky,
10058            placement: BlockPlacement::Above(anchor),
10059            height: Some(height),
10060            render: Arc::new(move |cx| {
10061                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10062                cloned_prompt.clone().into_any_element()
10063            }),
10064            priority: 0,
10065            render_in_minimap: true,
10066        }];
10067
10068        let focus_handle = bp_prompt.focus_handle(cx);
10069        window.focus(&focus_handle);
10070
10071        let block_ids = self.insert_blocks(blocks, None, cx);
10072        bp_prompt.update(cx, |prompt, _| {
10073            prompt.add_block_ids(block_ids);
10074        });
10075    }
10076
10077    pub(crate) fn breakpoint_at_row(
10078        &self,
10079        row: u32,
10080        window: &mut Window,
10081        cx: &mut Context<Self>,
10082    ) -> Option<(Anchor, Breakpoint)> {
10083        let snapshot = self.snapshot(window, cx);
10084        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10085
10086        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10087    }
10088
10089    pub(crate) fn breakpoint_at_anchor(
10090        &self,
10091        breakpoint_position: Anchor,
10092        snapshot: &EditorSnapshot,
10093        cx: &mut Context<Self>,
10094    ) -> Option<(Anchor, Breakpoint)> {
10095        let project = self.project.clone()?;
10096
10097        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10098            snapshot
10099                .buffer_snapshot
10100                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10101        })?;
10102
10103        let enclosing_excerpt = breakpoint_position.excerpt_id;
10104        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10105        let buffer_snapshot = buffer.read(cx).snapshot();
10106
10107        let row = buffer_snapshot
10108            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10109            .row;
10110
10111        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10112        let anchor_end = snapshot
10113            .buffer_snapshot
10114            .anchor_after(Point::new(row, line_len));
10115
10116        let bp = self
10117            .breakpoint_store
10118            .as_ref()?
10119            .read_with(cx, |breakpoint_store, cx| {
10120                breakpoint_store
10121                    .breakpoints(
10122                        &buffer,
10123                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10124                        &buffer_snapshot,
10125                        cx,
10126                    )
10127                    .next()
10128                    .and_then(|(bp, _)| {
10129                        let breakpoint_row = buffer_snapshot
10130                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10131                            .row;
10132
10133                        if breakpoint_row == row {
10134                            snapshot
10135                                .buffer_snapshot
10136                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10137                                .map(|position| (position, bp.bp.clone()))
10138                        } else {
10139                            None
10140                        }
10141                    })
10142            });
10143        bp
10144    }
10145
10146    pub fn edit_log_breakpoint(
10147        &mut self,
10148        _: &EditLogBreakpoint,
10149        window: &mut Window,
10150        cx: &mut Context<Self>,
10151    ) {
10152        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10153            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10154                message: None,
10155                state: BreakpointState::Enabled,
10156                condition: None,
10157                hit_condition: None,
10158            });
10159
10160            self.add_edit_breakpoint_block(
10161                anchor,
10162                &breakpoint,
10163                BreakpointPromptEditAction::Log,
10164                window,
10165                cx,
10166            );
10167        }
10168    }
10169
10170    fn breakpoints_at_cursors(
10171        &self,
10172        window: &mut Window,
10173        cx: &mut Context<Self>,
10174    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10175        let snapshot = self.snapshot(window, cx);
10176        let cursors = self
10177            .selections
10178            .disjoint_anchors()
10179            .into_iter()
10180            .map(|selection| {
10181                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10182
10183                let breakpoint_position = self
10184                    .breakpoint_at_row(cursor_position.row, window, cx)
10185                    .map(|bp| bp.0)
10186                    .unwrap_or_else(|| {
10187                        snapshot
10188                            .display_snapshot
10189                            .buffer_snapshot
10190                            .anchor_after(Point::new(cursor_position.row, 0))
10191                    });
10192
10193                let breakpoint = self
10194                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10195                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10196
10197                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10198            })
10199            // 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.
10200            .collect::<HashMap<Anchor, _>>();
10201
10202        cursors.into_iter().collect()
10203    }
10204
10205    pub fn enable_breakpoint(
10206        &mut self,
10207        _: &crate::actions::EnableBreakpoint,
10208        window: &mut Window,
10209        cx: &mut Context<Self>,
10210    ) {
10211        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10212            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10213                continue;
10214            };
10215            self.edit_breakpoint_at_anchor(
10216                anchor,
10217                breakpoint,
10218                BreakpointEditAction::InvertState,
10219                cx,
10220            );
10221        }
10222    }
10223
10224    pub fn disable_breakpoint(
10225        &mut self,
10226        _: &crate::actions::DisableBreakpoint,
10227        window: &mut Window,
10228        cx: &mut Context<Self>,
10229    ) {
10230        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10231            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10232                continue;
10233            };
10234            self.edit_breakpoint_at_anchor(
10235                anchor,
10236                breakpoint,
10237                BreakpointEditAction::InvertState,
10238                cx,
10239            );
10240        }
10241    }
10242
10243    pub fn toggle_breakpoint(
10244        &mut self,
10245        _: &crate::actions::ToggleBreakpoint,
10246        window: &mut Window,
10247        cx: &mut Context<Self>,
10248    ) {
10249        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10250            if let Some(breakpoint) = breakpoint {
10251                self.edit_breakpoint_at_anchor(
10252                    anchor,
10253                    breakpoint,
10254                    BreakpointEditAction::Toggle,
10255                    cx,
10256                );
10257            } else {
10258                self.edit_breakpoint_at_anchor(
10259                    anchor,
10260                    Breakpoint::new_standard(),
10261                    BreakpointEditAction::Toggle,
10262                    cx,
10263                );
10264            }
10265        }
10266    }
10267
10268    pub fn edit_breakpoint_at_anchor(
10269        &mut self,
10270        breakpoint_position: Anchor,
10271        breakpoint: Breakpoint,
10272        edit_action: BreakpointEditAction,
10273        cx: &mut Context<Self>,
10274    ) {
10275        let Some(breakpoint_store) = &self.breakpoint_store else {
10276            return;
10277        };
10278
10279        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10280            if breakpoint_position == Anchor::min() {
10281                self.buffer()
10282                    .read(cx)
10283                    .excerpt_buffer_ids()
10284                    .into_iter()
10285                    .next()
10286            } else {
10287                None
10288            }
10289        }) else {
10290            return;
10291        };
10292
10293        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10294            return;
10295        };
10296
10297        breakpoint_store.update(cx, |breakpoint_store, cx| {
10298            breakpoint_store.toggle_breakpoint(
10299                buffer,
10300                BreakpointWithPosition {
10301                    position: breakpoint_position.text_anchor,
10302                    bp: breakpoint,
10303                },
10304                edit_action,
10305                cx,
10306            );
10307        });
10308
10309        cx.notify();
10310    }
10311
10312    #[cfg(any(test, feature = "test-support"))]
10313    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10314        self.breakpoint_store.clone()
10315    }
10316
10317    pub fn prepare_restore_change(
10318        &self,
10319        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10320        hunk: &MultiBufferDiffHunk,
10321        cx: &mut App,
10322    ) -> Option<()> {
10323        if hunk.is_created_file() {
10324            return None;
10325        }
10326        let buffer = self.buffer.read(cx);
10327        let diff = buffer.diff_for(hunk.buffer_id)?;
10328        let buffer = buffer.buffer(hunk.buffer_id)?;
10329        let buffer = buffer.read(cx);
10330        let original_text = diff
10331            .read(cx)
10332            .base_text()
10333            .as_rope()
10334            .slice(hunk.diff_base_byte_range.clone());
10335        let buffer_snapshot = buffer.snapshot();
10336        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10337        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10338            probe
10339                .0
10340                .start
10341                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10342                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10343        }) {
10344            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10345            Some(())
10346        } else {
10347            None
10348        }
10349    }
10350
10351    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10352        self.manipulate_lines(window, cx, |lines| lines.reverse())
10353    }
10354
10355    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10356        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10357    }
10358
10359    fn manipulate_lines<Fn>(
10360        &mut self,
10361        window: &mut Window,
10362        cx: &mut Context<Self>,
10363        mut callback: Fn,
10364    ) where
10365        Fn: FnMut(&mut Vec<&str>),
10366    {
10367        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10368
10369        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10370        let buffer = self.buffer.read(cx).snapshot(cx);
10371
10372        let mut edits = Vec::new();
10373
10374        let selections = self.selections.all::<Point>(cx);
10375        let mut selections = selections.iter().peekable();
10376        let mut contiguous_row_selections = Vec::new();
10377        let mut new_selections = Vec::new();
10378        let mut added_lines = 0;
10379        let mut removed_lines = 0;
10380
10381        while let Some(selection) = selections.next() {
10382            let (start_row, end_row) = consume_contiguous_rows(
10383                &mut contiguous_row_selections,
10384                selection,
10385                &display_map,
10386                &mut selections,
10387            );
10388
10389            let start_point = Point::new(start_row.0, 0);
10390            let end_point = Point::new(
10391                end_row.previous_row().0,
10392                buffer.line_len(end_row.previous_row()),
10393            );
10394            let text = buffer
10395                .text_for_range(start_point..end_point)
10396                .collect::<String>();
10397
10398            let mut lines = text.split('\n').collect_vec();
10399
10400            let lines_before = lines.len();
10401            callback(&mut lines);
10402            let lines_after = lines.len();
10403
10404            edits.push((start_point..end_point, lines.join("\n")));
10405
10406            // Selections must change based on added and removed line count
10407            let start_row =
10408                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10409            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10410            new_selections.push(Selection {
10411                id: selection.id,
10412                start: start_row,
10413                end: end_row,
10414                goal: SelectionGoal::None,
10415                reversed: selection.reversed,
10416            });
10417
10418            if lines_after > lines_before {
10419                added_lines += lines_after - lines_before;
10420            } else if lines_before > lines_after {
10421                removed_lines += lines_before - lines_after;
10422            }
10423        }
10424
10425        self.transact(window, cx, |this, window, cx| {
10426            let buffer = this.buffer.update(cx, |buffer, cx| {
10427                buffer.edit(edits, None, cx);
10428                buffer.snapshot(cx)
10429            });
10430
10431            // Recalculate offsets on newly edited buffer
10432            let new_selections = new_selections
10433                .iter()
10434                .map(|s| {
10435                    let start_point = Point::new(s.start.0, 0);
10436                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10437                    Selection {
10438                        id: s.id,
10439                        start: buffer.point_to_offset(start_point),
10440                        end: buffer.point_to_offset(end_point),
10441                        goal: s.goal,
10442                        reversed: s.reversed,
10443                    }
10444                })
10445                .collect();
10446
10447            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10448                s.select(new_selections);
10449            });
10450
10451            this.request_autoscroll(Autoscroll::fit(), cx);
10452        });
10453    }
10454
10455    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10456        self.manipulate_text(window, cx, |text| {
10457            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10458            if has_upper_case_characters {
10459                text.to_lowercase()
10460            } else {
10461                text.to_uppercase()
10462            }
10463        })
10464    }
10465
10466    pub fn convert_to_upper_case(
10467        &mut self,
10468        _: &ConvertToUpperCase,
10469        window: &mut Window,
10470        cx: &mut Context<Self>,
10471    ) {
10472        self.manipulate_text(window, cx, |text| text.to_uppercase())
10473    }
10474
10475    pub fn convert_to_lower_case(
10476        &mut self,
10477        _: &ConvertToLowerCase,
10478        window: &mut Window,
10479        cx: &mut Context<Self>,
10480    ) {
10481        self.manipulate_text(window, cx, |text| text.to_lowercase())
10482    }
10483
10484    pub fn convert_to_title_case(
10485        &mut self,
10486        _: &ConvertToTitleCase,
10487        window: &mut Window,
10488        cx: &mut Context<Self>,
10489    ) {
10490        self.manipulate_text(window, cx, |text| {
10491            text.split('\n')
10492                .map(|line| line.to_case(Case::Title))
10493                .join("\n")
10494        })
10495    }
10496
10497    pub fn convert_to_snake_case(
10498        &mut self,
10499        _: &ConvertToSnakeCase,
10500        window: &mut Window,
10501        cx: &mut Context<Self>,
10502    ) {
10503        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10504    }
10505
10506    pub fn convert_to_kebab_case(
10507        &mut self,
10508        _: &ConvertToKebabCase,
10509        window: &mut Window,
10510        cx: &mut Context<Self>,
10511    ) {
10512        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10513    }
10514
10515    pub fn convert_to_upper_camel_case(
10516        &mut self,
10517        _: &ConvertToUpperCamelCase,
10518        window: &mut Window,
10519        cx: &mut Context<Self>,
10520    ) {
10521        self.manipulate_text(window, cx, |text| {
10522            text.split('\n')
10523                .map(|line| line.to_case(Case::UpperCamel))
10524                .join("\n")
10525        })
10526    }
10527
10528    pub fn convert_to_lower_camel_case(
10529        &mut self,
10530        _: &ConvertToLowerCamelCase,
10531        window: &mut Window,
10532        cx: &mut Context<Self>,
10533    ) {
10534        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10535    }
10536
10537    pub fn convert_to_opposite_case(
10538        &mut self,
10539        _: &ConvertToOppositeCase,
10540        window: &mut Window,
10541        cx: &mut Context<Self>,
10542    ) {
10543        self.manipulate_text(window, cx, |text| {
10544            text.chars()
10545                .fold(String::with_capacity(text.len()), |mut t, c| {
10546                    if c.is_uppercase() {
10547                        t.extend(c.to_lowercase());
10548                    } else {
10549                        t.extend(c.to_uppercase());
10550                    }
10551                    t
10552                })
10553        })
10554    }
10555
10556    pub fn convert_to_rot13(
10557        &mut self,
10558        _: &ConvertToRot13,
10559        window: &mut Window,
10560        cx: &mut Context<Self>,
10561    ) {
10562        self.manipulate_text(window, cx, |text| {
10563            text.chars()
10564                .map(|c| match c {
10565                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10566                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10567                    _ => c,
10568                })
10569                .collect()
10570        })
10571    }
10572
10573    pub fn convert_to_rot47(
10574        &mut self,
10575        _: &ConvertToRot47,
10576        window: &mut Window,
10577        cx: &mut Context<Self>,
10578    ) {
10579        self.manipulate_text(window, cx, |text| {
10580            text.chars()
10581                .map(|c| {
10582                    let code_point = c as u32;
10583                    if code_point >= 33 && code_point <= 126 {
10584                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10585                    }
10586                    c
10587                })
10588                .collect()
10589        })
10590    }
10591
10592    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10593    where
10594        Fn: FnMut(&str) -> String,
10595    {
10596        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10597        let buffer = self.buffer.read(cx).snapshot(cx);
10598
10599        let mut new_selections = Vec::new();
10600        let mut edits = Vec::new();
10601        let mut selection_adjustment = 0i32;
10602
10603        for selection in self.selections.all::<usize>(cx) {
10604            let selection_is_empty = selection.is_empty();
10605
10606            let (start, end) = if selection_is_empty {
10607                let word_range = movement::surrounding_word(
10608                    &display_map,
10609                    selection.start.to_display_point(&display_map),
10610                );
10611                let start = word_range.start.to_offset(&display_map, Bias::Left);
10612                let end = word_range.end.to_offset(&display_map, Bias::Left);
10613                (start, end)
10614            } else {
10615                (selection.start, selection.end)
10616            };
10617
10618            let text = buffer.text_for_range(start..end).collect::<String>();
10619            let old_length = text.len() as i32;
10620            let text = callback(&text);
10621
10622            new_selections.push(Selection {
10623                start: (start as i32 - selection_adjustment) as usize,
10624                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10625                goal: SelectionGoal::None,
10626                ..selection
10627            });
10628
10629            selection_adjustment += old_length - text.len() as i32;
10630
10631            edits.push((start..end, text));
10632        }
10633
10634        self.transact(window, cx, |this, window, cx| {
10635            this.buffer.update(cx, |buffer, cx| {
10636                buffer.edit(edits, None, cx);
10637            });
10638
10639            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10640                s.select(new_selections);
10641            });
10642
10643            this.request_autoscroll(Autoscroll::fit(), cx);
10644        });
10645    }
10646
10647    pub fn move_selection_on_drop(
10648        &mut self,
10649        selection: &Selection<Anchor>,
10650        target: DisplayPoint,
10651        is_cut: bool,
10652        window: &mut Window,
10653        cx: &mut Context<Self>,
10654    ) {
10655        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10656        let buffer = &display_map.buffer_snapshot;
10657        let mut edits = Vec::new();
10658        let insert_point = display_map
10659            .clip_point(target, Bias::Left)
10660            .to_point(&display_map);
10661        let text = buffer
10662            .text_for_range(selection.start..selection.end)
10663            .collect::<String>();
10664        if is_cut {
10665            edits.push(((selection.start..selection.end), String::new()));
10666        }
10667        let insert_anchor = buffer.anchor_before(insert_point);
10668        edits.push(((insert_anchor..insert_anchor), text));
10669        let last_edit_start = insert_anchor.bias_left(buffer);
10670        let last_edit_end = insert_anchor.bias_right(buffer);
10671        self.transact(window, cx, |this, window, cx| {
10672            this.buffer.update(cx, |buffer, cx| {
10673                buffer.edit(edits, None, cx);
10674            });
10675            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10676                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10677            });
10678        });
10679    }
10680
10681    pub fn clear_selection_drag_state(&mut self) {
10682        self.selection_drag_state = SelectionDragState::None;
10683    }
10684
10685    pub fn duplicate(
10686        &mut self,
10687        upwards: bool,
10688        whole_lines: bool,
10689        window: &mut Window,
10690        cx: &mut Context<Self>,
10691    ) {
10692        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10693
10694        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10695        let buffer = &display_map.buffer_snapshot;
10696        let selections = self.selections.all::<Point>(cx);
10697
10698        let mut edits = Vec::new();
10699        let mut selections_iter = selections.iter().peekable();
10700        while let Some(selection) = selections_iter.next() {
10701            let mut rows = selection.spanned_rows(false, &display_map);
10702            // duplicate line-wise
10703            if whole_lines || selection.start == selection.end {
10704                // Avoid duplicating the same lines twice.
10705                while let Some(next_selection) = selections_iter.peek() {
10706                    let next_rows = next_selection.spanned_rows(false, &display_map);
10707                    if next_rows.start < rows.end {
10708                        rows.end = next_rows.end;
10709                        selections_iter.next().unwrap();
10710                    } else {
10711                        break;
10712                    }
10713                }
10714
10715                // Copy the text from the selected row region and splice it either at the start
10716                // or end of the region.
10717                let start = Point::new(rows.start.0, 0);
10718                let end = Point::new(
10719                    rows.end.previous_row().0,
10720                    buffer.line_len(rows.end.previous_row()),
10721                );
10722                let text = buffer
10723                    .text_for_range(start..end)
10724                    .chain(Some("\n"))
10725                    .collect::<String>();
10726                let insert_location = if upwards {
10727                    Point::new(rows.end.0, 0)
10728                } else {
10729                    start
10730                };
10731                edits.push((insert_location..insert_location, text));
10732            } else {
10733                // duplicate character-wise
10734                let start = selection.start;
10735                let end = selection.end;
10736                let text = buffer.text_for_range(start..end).collect::<String>();
10737                edits.push((selection.end..selection.end, text));
10738            }
10739        }
10740
10741        self.transact(window, cx, |this, _, cx| {
10742            this.buffer.update(cx, |buffer, cx| {
10743                buffer.edit(edits, None, cx);
10744            });
10745
10746            this.request_autoscroll(Autoscroll::fit(), cx);
10747        });
10748    }
10749
10750    pub fn duplicate_line_up(
10751        &mut self,
10752        _: &DuplicateLineUp,
10753        window: &mut Window,
10754        cx: &mut Context<Self>,
10755    ) {
10756        self.duplicate(true, true, window, cx);
10757    }
10758
10759    pub fn duplicate_line_down(
10760        &mut self,
10761        _: &DuplicateLineDown,
10762        window: &mut Window,
10763        cx: &mut Context<Self>,
10764    ) {
10765        self.duplicate(false, true, window, cx);
10766    }
10767
10768    pub fn duplicate_selection(
10769        &mut self,
10770        _: &DuplicateSelection,
10771        window: &mut Window,
10772        cx: &mut Context<Self>,
10773    ) {
10774        self.duplicate(false, false, window, cx);
10775    }
10776
10777    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10778        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10779
10780        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10781        let buffer = self.buffer.read(cx).snapshot(cx);
10782
10783        let mut edits = Vec::new();
10784        let mut unfold_ranges = Vec::new();
10785        let mut refold_creases = Vec::new();
10786
10787        let selections = self.selections.all::<Point>(cx);
10788        let mut selections = selections.iter().peekable();
10789        let mut contiguous_row_selections = Vec::new();
10790        let mut new_selections = Vec::new();
10791
10792        while let Some(selection) = selections.next() {
10793            // Find all the selections that span a contiguous row range
10794            let (start_row, end_row) = consume_contiguous_rows(
10795                &mut contiguous_row_selections,
10796                selection,
10797                &display_map,
10798                &mut selections,
10799            );
10800
10801            // Move the text spanned by the row range to be before the line preceding the row range
10802            if start_row.0 > 0 {
10803                let range_to_move = Point::new(
10804                    start_row.previous_row().0,
10805                    buffer.line_len(start_row.previous_row()),
10806                )
10807                    ..Point::new(
10808                        end_row.previous_row().0,
10809                        buffer.line_len(end_row.previous_row()),
10810                    );
10811                let insertion_point = display_map
10812                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10813                    .0;
10814
10815                // Don't move lines across excerpts
10816                if buffer
10817                    .excerpt_containing(insertion_point..range_to_move.end)
10818                    .is_some()
10819                {
10820                    let text = buffer
10821                        .text_for_range(range_to_move.clone())
10822                        .flat_map(|s| s.chars())
10823                        .skip(1)
10824                        .chain(['\n'])
10825                        .collect::<String>();
10826
10827                    edits.push((
10828                        buffer.anchor_after(range_to_move.start)
10829                            ..buffer.anchor_before(range_to_move.end),
10830                        String::new(),
10831                    ));
10832                    let insertion_anchor = buffer.anchor_after(insertion_point);
10833                    edits.push((insertion_anchor..insertion_anchor, text));
10834
10835                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10836
10837                    // Move selections up
10838                    new_selections.extend(contiguous_row_selections.drain(..).map(
10839                        |mut selection| {
10840                            selection.start.row -= row_delta;
10841                            selection.end.row -= row_delta;
10842                            selection
10843                        },
10844                    ));
10845
10846                    // Move folds up
10847                    unfold_ranges.push(range_to_move.clone());
10848                    for fold in display_map.folds_in_range(
10849                        buffer.anchor_before(range_to_move.start)
10850                            ..buffer.anchor_after(range_to_move.end),
10851                    ) {
10852                        let mut start = fold.range.start.to_point(&buffer);
10853                        let mut end = fold.range.end.to_point(&buffer);
10854                        start.row -= row_delta;
10855                        end.row -= row_delta;
10856                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10857                    }
10858                }
10859            }
10860
10861            // If we didn't move line(s), preserve the existing selections
10862            new_selections.append(&mut contiguous_row_selections);
10863        }
10864
10865        self.transact(window, cx, |this, window, cx| {
10866            this.unfold_ranges(&unfold_ranges, true, true, cx);
10867            this.buffer.update(cx, |buffer, cx| {
10868                for (range, text) in edits {
10869                    buffer.edit([(range, text)], None, cx);
10870                }
10871            });
10872            this.fold_creases(refold_creases, true, window, cx);
10873            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10874                s.select(new_selections);
10875            })
10876        });
10877    }
10878
10879    pub fn move_line_down(
10880        &mut self,
10881        _: &MoveLineDown,
10882        window: &mut Window,
10883        cx: &mut Context<Self>,
10884    ) {
10885        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10886
10887        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10888        let buffer = self.buffer.read(cx).snapshot(cx);
10889
10890        let mut edits = Vec::new();
10891        let mut unfold_ranges = Vec::new();
10892        let mut refold_creases = Vec::new();
10893
10894        let selections = self.selections.all::<Point>(cx);
10895        let mut selections = selections.iter().peekable();
10896        let mut contiguous_row_selections = Vec::new();
10897        let mut new_selections = Vec::new();
10898
10899        while let Some(selection) = selections.next() {
10900            // Find all the selections that span a contiguous row range
10901            let (start_row, end_row) = consume_contiguous_rows(
10902                &mut contiguous_row_selections,
10903                selection,
10904                &display_map,
10905                &mut selections,
10906            );
10907
10908            // Move the text spanned by the row range to be after the last line of the row range
10909            if end_row.0 <= buffer.max_point().row {
10910                let range_to_move =
10911                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10912                let insertion_point = display_map
10913                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10914                    .0;
10915
10916                // Don't move lines across excerpt boundaries
10917                if buffer
10918                    .excerpt_containing(range_to_move.start..insertion_point)
10919                    .is_some()
10920                {
10921                    let mut text = String::from("\n");
10922                    text.extend(buffer.text_for_range(range_to_move.clone()));
10923                    text.pop(); // Drop trailing newline
10924                    edits.push((
10925                        buffer.anchor_after(range_to_move.start)
10926                            ..buffer.anchor_before(range_to_move.end),
10927                        String::new(),
10928                    ));
10929                    let insertion_anchor = buffer.anchor_after(insertion_point);
10930                    edits.push((insertion_anchor..insertion_anchor, text));
10931
10932                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10933
10934                    // Move selections down
10935                    new_selections.extend(contiguous_row_selections.drain(..).map(
10936                        |mut selection| {
10937                            selection.start.row += row_delta;
10938                            selection.end.row += row_delta;
10939                            selection
10940                        },
10941                    ));
10942
10943                    // Move folds down
10944                    unfold_ranges.push(range_to_move.clone());
10945                    for fold in display_map.folds_in_range(
10946                        buffer.anchor_before(range_to_move.start)
10947                            ..buffer.anchor_after(range_to_move.end),
10948                    ) {
10949                        let mut start = fold.range.start.to_point(&buffer);
10950                        let mut end = fold.range.end.to_point(&buffer);
10951                        start.row += row_delta;
10952                        end.row += row_delta;
10953                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10954                    }
10955                }
10956            }
10957
10958            // If we didn't move line(s), preserve the existing selections
10959            new_selections.append(&mut contiguous_row_selections);
10960        }
10961
10962        self.transact(window, cx, |this, window, cx| {
10963            this.unfold_ranges(&unfold_ranges, true, true, cx);
10964            this.buffer.update(cx, |buffer, cx| {
10965                for (range, text) in edits {
10966                    buffer.edit([(range, text)], None, cx);
10967                }
10968            });
10969            this.fold_creases(refold_creases, true, window, cx);
10970            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10971                s.select(new_selections)
10972            });
10973        });
10974    }
10975
10976    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10977        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10978        let text_layout_details = &self.text_layout_details(window);
10979        self.transact(window, cx, |this, window, cx| {
10980            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10981                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10982                s.move_with(|display_map, selection| {
10983                    if !selection.is_empty() {
10984                        return;
10985                    }
10986
10987                    let mut head = selection.head();
10988                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10989                    if head.column() == display_map.line_len(head.row()) {
10990                        transpose_offset = display_map
10991                            .buffer_snapshot
10992                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10993                    }
10994
10995                    if transpose_offset == 0 {
10996                        return;
10997                    }
10998
10999                    *head.column_mut() += 1;
11000                    head = display_map.clip_point(head, Bias::Right);
11001                    let goal = SelectionGoal::HorizontalPosition(
11002                        display_map
11003                            .x_for_display_point(head, text_layout_details)
11004                            .into(),
11005                    );
11006                    selection.collapse_to(head, goal);
11007
11008                    let transpose_start = display_map
11009                        .buffer_snapshot
11010                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11011                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11012                        let transpose_end = display_map
11013                            .buffer_snapshot
11014                            .clip_offset(transpose_offset + 1, Bias::Right);
11015                        if let Some(ch) =
11016                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11017                        {
11018                            edits.push((transpose_start..transpose_offset, String::new()));
11019                            edits.push((transpose_end..transpose_end, ch.to_string()));
11020                        }
11021                    }
11022                });
11023                edits
11024            });
11025            this.buffer
11026                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11027            let selections = this.selections.all::<usize>(cx);
11028            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11029                s.select(selections);
11030            });
11031        });
11032    }
11033
11034    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11035        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11036        self.rewrap_impl(RewrapOptions::default(), cx)
11037    }
11038
11039    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11040        let buffer = self.buffer.read(cx).snapshot(cx);
11041        let selections = self.selections.all::<Point>(cx);
11042
11043        // Shrink and split selections to respect paragraph boundaries.
11044        let ranges = selections.into_iter().flat_map(|selection| {
11045            let language_settings = buffer.language_settings_at(selection.head(), cx);
11046            let language_scope = buffer.language_scope_at(selection.head());
11047
11048            let Some(start_row) = (selection.start.row..=selection.end.row)
11049                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11050            else {
11051                return vec![];
11052            };
11053            let Some(end_row) = (selection.start.row..=selection.end.row)
11054                .rev()
11055                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11056            else {
11057                return vec![];
11058            };
11059
11060            let mut row = start_row;
11061            let mut ranges = Vec::new();
11062            while let Some(blank_row) =
11063                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11064            {
11065                let next_paragraph_start = (blank_row + 1..=end_row)
11066                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11067                    .unwrap();
11068                ranges.push((
11069                    language_settings.clone(),
11070                    language_scope.clone(),
11071                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11072                ));
11073                row = next_paragraph_start;
11074            }
11075            ranges.push((
11076                language_settings.clone(),
11077                language_scope.clone(),
11078                Point::new(row, 0)..Point::new(end_row, 0),
11079            ));
11080
11081            ranges
11082        });
11083
11084        let mut edits = Vec::new();
11085        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11086
11087        for (language_settings, language_scope, range) in ranges {
11088            let mut start_row = range.start.row;
11089            let mut end_row = range.end.row;
11090
11091            // Skip selections that overlap with a range that has already been rewrapped.
11092            let selection_range = start_row..end_row;
11093            if rewrapped_row_ranges
11094                .iter()
11095                .any(|range| range.overlaps(&selection_range))
11096            {
11097                continue;
11098            }
11099
11100            let tab_size = language_settings.tab_size;
11101
11102            // Since not all lines in the selection may be at the same indent
11103            // level, choose the indent size that is the most common between all
11104            // of the lines.
11105            //
11106            // If there is a tie, we use the deepest indent.
11107            let (indent_size, indent_end) = {
11108                let mut indent_size_occurrences = HashMap::default();
11109                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11110
11111                for row in start_row..=end_row {
11112                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11113                    rows_by_indent_size.entry(indent).or_default().push(row);
11114                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11115                }
11116
11117                let indent_size = indent_size_occurrences
11118                    .into_iter()
11119                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11120                    .map(|(indent, _)| indent)
11121                    .unwrap_or_default();
11122                let row = rows_by_indent_size[&indent_size][0];
11123                let indent_end = Point::new(row, indent_size.len);
11124
11125                (indent_size, indent_end)
11126            };
11127
11128            let mut line_prefix = indent_size.chars().collect::<String>();
11129
11130            let mut inside_comment = false;
11131            if let Some(comment_prefix) = language_scope.and_then(|language| {
11132                language
11133                    .line_comment_prefixes()
11134                    .iter()
11135                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11136                    .cloned()
11137            }) {
11138                line_prefix.push_str(&comment_prefix);
11139                inside_comment = true;
11140            }
11141
11142            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11143                RewrapBehavior::InComments => inside_comment,
11144                RewrapBehavior::InSelections => !range.is_empty(),
11145                RewrapBehavior::Anywhere => true,
11146            };
11147
11148            let should_rewrap = options.override_language_settings
11149                || allow_rewrap_based_on_language
11150                || self.hard_wrap.is_some();
11151            if !should_rewrap {
11152                continue;
11153            }
11154
11155            if range.is_empty() {
11156                'expand_upwards: while start_row > 0 {
11157                    let prev_row = start_row - 1;
11158                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11159                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11160                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11161                    {
11162                        start_row = prev_row;
11163                    } else {
11164                        break 'expand_upwards;
11165                    }
11166                }
11167
11168                'expand_downwards: while end_row < buffer.max_point().row {
11169                    let next_row = end_row + 1;
11170                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11171                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11172                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11173                    {
11174                        end_row = next_row;
11175                    } else {
11176                        break 'expand_downwards;
11177                    }
11178                }
11179            }
11180
11181            let start = Point::new(start_row, 0);
11182            let start_offset = start.to_offset(&buffer);
11183            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11184            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11185            let Some(lines_without_prefixes) = selection_text
11186                .lines()
11187                .map(|line| {
11188                    line.strip_prefix(&line_prefix)
11189                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11190                        .with_context(|| {
11191                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11192                        })
11193                })
11194                .collect::<Result<Vec<_>, _>>()
11195                .log_err()
11196            else {
11197                continue;
11198            };
11199
11200            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11201                buffer
11202                    .language_settings_at(Point::new(start_row, 0), cx)
11203                    .preferred_line_length as usize
11204            });
11205            let wrapped_text = wrap_with_prefix(
11206                line_prefix,
11207                lines_without_prefixes.join("\n"),
11208                wrap_column,
11209                tab_size,
11210                options.preserve_existing_whitespace,
11211            );
11212
11213            // TODO: should always use char-based diff while still supporting cursor behavior that
11214            // matches vim.
11215            let mut diff_options = DiffOptions::default();
11216            if options.override_language_settings {
11217                diff_options.max_word_diff_len = 0;
11218                diff_options.max_word_diff_line_count = 0;
11219            } else {
11220                diff_options.max_word_diff_len = usize::MAX;
11221                diff_options.max_word_diff_line_count = usize::MAX;
11222            }
11223
11224            for (old_range, new_text) in
11225                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11226            {
11227                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11228                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11229                edits.push((edit_start..edit_end, new_text));
11230            }
11231
11232            rewrapped_row_ranges.push(start_row..=end_row);
11233        }
11234
11235        self.buffer
11236            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11237    }
11238
11239    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11240        let mut text = String::new();
11241        let buffer = self.buffer.read(cx).snapshot(cx);
11242        let mut selections = self.selections.all::<Point>(cx);
11243        let mut clipboard_selections = Vec::with_capacity(selections.len());
11244        {
11245            let max_point = buffer.max_point();
11246            let mut is_first = true;
11247            for selection in &mut selections {
11248                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11249                if is_entire_line {
11250                    selection.start = Point::new(selection.start.row, 0);
11251                    if !selection.is_empty() && selection.end.column == 0 {
11252                        selection.end = cmp::min(max_point, selection.end);
11253                    } else {
11254                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11255                    }
11256                    selection.goal = SelectionGoal::None;
11257                }
11258                if is_first {
11259                    is_first = false;
11260                } else {
11261                    text += "\n";
11262                }
11263                let mut len = 0;
11264                for chunk in buffer.text_for_range(selection.start..selection.end) {
11265                    text.push_str(chunk);
11266                    len += chunk.len();
11267                }
11268                clipboard_selections.push(ClipboardSelection {
11269                    len,
11270                    is_entire_line,
11271                    first_line_indent: buffer
11272                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11273                        .len,
11274                });
11275            }
11276        }
11277
11278        self.transact(window, cx, |this, window, cx| {
11279            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11280                s.select(selections);
11281            });
11282            this.insert("", window, cx);
11283        });
11284        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11285    }
11286
11287    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11288        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11289        let item = self.cut_common(window, cx);
11290        cx.write_to_clipboard(item);
11291    }
11292
11293    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11294        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11295        self.change_selections(None, window, cx, |s| {
11296            s.move_with(|snapshot, sel| {
11297                if sel.is_empty() {
11298                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11299                }
11300            });
11301        });
11302        let item = self.cut_common(window, cx);
11303        cx.set_global(KillRing(item))
11304    }
11305
11306    pub fn kill_ring_yank(
11307        &mut self,
11308        _: &KillRingYank,
11309        window: &mut Window,
11310        cx: &mut Context<Self>,
11311    ) {
11312        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11313        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11314            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11315                (kill_ring.text().to_string(), kill_ring.metadata_json())
11316            } else {
11317                return;
11318            }
11319        } else {
11320            return;
11321        };
11322        self.do_paste(&text, metadata, false, window, cx);
11323    }
11324
11325    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11326        self.do_copy(true, cx);
11327    }
11328
11329    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11330        self.do_copy(false, cx);
11331    }
11332
11333    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11334        let selections = self.selections.all::<Point>(cx);
11335        let buffer = self.buffer.read(cx).read(cx);
11336        let mut text = String::new();
11337
11338        let mut clipboard_selections = Vec::with_capacity(selections.len());
11339        {
11340            let max_point = buffer.max_point();
11341            let mut is_first = true;
11342            for selection in &selections {
11343                let mut start = selection.start;
11344                let mut end = selection.end;
11345                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11346                if is_entire_line {
11347                    start = Point::new(start.row, 0);
11348                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11349                }
11350
11351                let mut trimmed_selections = Vec::new();
11352                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11353                    let row = MultiBufferRow(start.row);
11354                    let first_indent = buffer.indent_size_for_line(row);
11355                    if first_indent.len == 0 || start.column > first_indent.len {
11356                        trimmed_selections.push(start..end);
11357                    } else {
11358                        trimmed_selections.push(
11359                            Point::new(row.0, first_indent.len)
11360                                ..Point::new(row.0, buffer.line_len(row)),
11361                        );
11362                        for row in start.row + 1..=end.row {
11363                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11364                            if row == end.row {
11365                                line_len = end.column;
11366                            }
11367                            if line_len == 0 {
11368                                trimmed_selections
11369                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11370                                continue;
11371                            }
11372                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11373                            if row_indent_size.len >= first_indent.len {
11374                                trimmed_selections.push(
11375                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11376                                );
11377                            } else {
11378                                trimmed_selections.clear();
11379                                trimmed_selections.push(start..end);
11380                                break;
11381                            }
11382                        }
11383                    }
11384                } else {
11385                    trimmed_selections.push(start..end);
11386                }
11387
11388                for trimmed_range in trimmed_selections {
11389                    if is_first {
11390                        is_first = false;
11391                    } else {
11392                        text += "\n";
11393                    }
11394                    let mut len = 0;
11395                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11396                        text.push_str(chunk);
11397                        len += chunk.len();
11398                    }
11399                    clipboard_selections.push(ClipboardSelection {
11400                        len,
11401                        is_entire_line,
11402                        first_line_indent: buffer
11403                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11404                            .len,
11405                    });
11406                }
11407            }
11408        }
11409
11410        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11411            text,
11412            clipboard_selections,
11413        ));
11414    }
11415
11416    pub fn do_paste(
11417        &mut self,
11418        text: &String,
11419        clipboard_selections: Option<Vec<ClipboardSelection>>,
11420        handle_entire_lines: bool,
11421        window: &mut Window,
11422        cx: &mut Context<Self>,
11423    ) {
11424        if self.read_only(cx) {
11425            return;
11426        }
11427
11428        let clipboard_text = Cow::Borrowed(text);
11429
11430        self.transact(window, cx, |this, window, cx| {
11431            if let Some(mut clipboard_selections) = clipboard_selections {
11432                let old_selections = this.selections.all::<usize>(cx);
11433                let all_selections_were_entire_line =
11434                    clipboard_selections.iter().all(|s| s.is_entire_line);
11435                let first_selection_indent_column =
11436                    clipboard_selections.first().map(|s| s.first_line_indent);
11437                if clipboard_selections.len() != old_selections.len() {
11438                    clipboard_selections.drain(..);
11439                }
11440                let cursor_offset = this.selections.last::<usize>(cx).head();
11441                let mut auto_indent_on_paste = true;
11442
11443                this.buffer.update(cx, |buffer, cx| {
11444                    let snapshot = buffer.read(cx);
11445                    auto_indent_on_paste = snapshot
11446                        .language_settings_at(cursor_offset, cx)
11447                        .auto_indent_on_paste;
11448
11449                    let mut start_offset = 0;
11450                    let mut edits = Vec::new();
11451                    let mut original_indent_columns = Vec::new();
11452                    for (ix, selection) in old_selections.iter().enumerate() {
11453                        let to_insert;
11454                        let entire_line;
11455                        let original_indent_column;
11456                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11457                            let end_offset = start_offset + clipboard_selection.len;
11458                            to_insert = &clipboard_text[start_offset..end_offset];
11459                            entire_line = clipboard_selection.is_entire_line;
11460                            start_offset = end_offset + 1;
11461                            original_indent_column = Some(clipboard_selection.first_line_indent);
11462                        } else {
11463                            to_insert = clipboard_text.as_str();
11464                            entire_line = all_selections_were_entire_line;
11465                            original_indent_column = first_selection_indent_column
11466                        }
11467
11468                        // If the corresponding selection was empty when this slice of the
11469                        // clipboard text was written, then the entire line containing the
11470                        // selection was copied. If this selection is also currently empty,
11471                        // then paste the line before the current line of the buffer.
11472                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11473                            let column = selection.start.to_point(&snapshot).column as usize;
11474                            let line_start = selection.start - column;
11475                            line_start..line_start
11476                        } else {
11477                            selection.range()
11478                        };
11479
11480                        edits.push((range, to_insert));
11481                        original_indent_columns.push(original_indent_column);
11482                    }
11483                    drop(snapshot);
11484
11485                    buffer.edit(
11486                        edits,
11487                        if auto_indent_on_paste {
11488                            Some(AutoindentMode::Block {
11489                                original_indent_columns,
11490                            })
11491                        } else {
11492                            None
11493                        },
11494                        cx,
11495                    );
11496                });
11497
11498                let selections = this.selections.all::<usize>(cx);
11499                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11500                    s.select(selections)
11501                });
11502            } else {
11503                this.insert(&clipboard_text, window, cx);
11504            }
11505        });
11506    }
11507
11508    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11509        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11510        if let Some(item) = cx.read_from_clipboard() {
11511            let entries = item.entries();
11512
11513            match entries.first() {
11514                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11515                // of all the pasted entries.
11516                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11517                    .do_paste(
11518                        clipboard_string.text(),
11519                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11520                        true,
11521                        window,
11522                        cx,
11523                    ),
11524                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11525            }
11526        }
11527    }
11528
11529    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11530        if self.read_only(cx) {
11531            return;
11532        }
11533
11534        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11535
11536        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11537            if let Some((selections, _)) =
11538                self.selection_history.transaction(transaction_id).cloned()
11539            {
11540                self.change_selections(None, window, cx, |s| {
11541                    s.select_anchors(selections.to_vec());
11542                });
11543            } else {
11544                log::error!(
11545                    "No entry in selection_history found for undo. \
11546                     This may correspond to a bug where undo does not update the selection. \
11547                     If this is occurring, please add details to \
11548                     https://github.com/zed-industries/zed/issues/22692"
11549                );
11550            }
11551            self.request_autoscroll(Autoscroll::fit(), cx);
11552            self.unmark_text(window, cx);
11553            self.refresh_inline_completion(true, false, window, cx);
11554            cx.emit(EditorEvent::Edited { transaction_id });
11555            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11556        }
11557    }
11558
11559    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11560        if self.read_only(cx) {
11561            return;
11562        }
11563
11564        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11565
11566        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11567            if let Some((_, Some(selections))) =
11568                self.selection_history.transaction(transaction_id).cloned()
11569            {
11570                self.change_selections(None, window, cx, |s| {
11571                    s.select_anchors(selections.to_vec());
11572                });
11573            } else {
11574                log::error!(
11575                    "No entry in selection_history found for redo. \
11576                     This may correspond to a bug where undo does not update the selection. \
11577                     If this is occurring, please add details to \
11578                     https://github.com/zed-industries/zed/issues/22692"
11579                );
11580            }
11581            self.request_autoscroll(Autoscroll::fit(), cx);
11582            self.unmark_text(window, cx);
11583            self.refresh_inline_completion(true, false, window, cx);
11584            cx.emit(EditorEvent::Edited { transaction_id });
11585        }
11586    }
11587
11588    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11589        self.buffer
11590            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11591    }
11592
11593    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11594        self.buffer
11595            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11596    }
11597
11598    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11599        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11600        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11601            s.move_with(|map, selection| {
11602                let cursor = if selection.is_empty() {
11603                    movement::left(map, selection.start)
11604                } else {
11605                    selection.start
11606                };
11607                selection.collapse_to(cursor, SelectionGoal::None);
11608            });
11609        })
11610    }
11611
11612    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11613        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11614        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11615            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11616        })
11617    }
11618
11619    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11620        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11621        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11622            s.move_with(|map, selection| {
11623                let cursor = if selection.is_empty() {
11624                    movement::right(map, selection.end)
11625                } else {
11626                    selection.end
11627                };
11628                selection.collapse_to(cursor, SelectionGoal::None)
11629            });
11630        })
11631    }
11632
11633    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11634        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11635        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11636            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11637        })
11638    }
11639
11640    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11641        if self.take_rename(true, window, cx).is_some() {
11642            return;
11643        }
11644
11645        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11646            cx.propagate();
11647            return;
11648        }
11649
11650        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11651
11652        let text_layout_details = &self.text_layout_details(window);
11653        let selection_count = self.selections.count();
11654        let first_selection = self.selections.first_anchor();
11655
11656        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11657            s.move_with(|map, selection| {
11658                if !selection.is_empty() {
11659                    selection.goal = SelectionGoal::None;
11660                }
11661                let (cursor, goal) = movement::up(
11662                    map,
11663                    selection.start,
11664                    selection.goal,
11665                    false,
11666                    text_layout_details,
11667                );
11668                selection.collapse_to(cursor, goal);
11669            });
11670        });
11671
11672        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11673        {
11674            cx.propagate();
11675        }
11676    }
11677
11678    pub fn move_up_by_lines(
11679        &mut self,
11680        action: &MoveUpByLines,
11681        window: &mut Window,
11682        cx: &mut Context<Self>,
11683    ) {
11684        if self.take_rename(true, window, cx).is_some() {
11685            return;
11686        }
11687
11688        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11689            cx.propagate();
11690            return;
11691        }
11692
11693        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11694
11695        let text_layout_details = &self.text_layout_details(window);
11696
11697        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11698            s.move_with(|map, selection| {
11699                if !selection.is_empty() {
11700                    selection.goal = SelectionGoal::None;
11701                }
11702                let (cursor, goal) = movement::up_by_rows(
11703                    map,
11704                    selection.start,
11705                    action.lines,
11706                    selection.goal,
11707                    false,
11708                    text_layout_details,
11709                );
11710                selection.collapse_to(cursor, goal);
11711            });
11712        })
11713    }
11714
11715    pub fn move_down_by_lines(
11716        &mut self,
11717        action: &MoveDownByLines,
11718        window: &mut Window,
11719        cx: &mut Context<Self>,
11720    ) {
11721        if self.take_rename(true, window, cx).is_some() {
11722            return;
11723        }
11724
11725        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11726            cx.propagate();
11727            return;
11728        }
11729
11730        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11731
11732        let text_layout_details = &self.text_layout_details(window);
11733
11734        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11735            s.move_with(|map, selection| {
11736                if !selection.is_empty() {
11737                    selection.goal = SelectionGoal::None;
11738                }
11739                let (cursor, goal) = movement::down_by_rows(
11740                    map,
11741                    selection.start,
11742                    action.lines,
11743                    selection.goal,
11744                    false,
11745                    text_layout_details,
11746                );
11747                selection.collapse_to(cursor, goal);
11748            });
11749        })
11750    }
11751
11752    pub fn select_down_by_lines(
11753        &mut self,
11754        action: &SelectDownByLines,
11755        window: &mut Window,
11756        cx: &mut Context<Self>,
11757    ) {
11758        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11759        let text_layout_details = &self.text_layout_details(window);
11760        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11761            s.move_heads_with(|map, head, goal| {
11762                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11763            })
11764        })
11765    }
11766
11767    pub fn select_up_by_lines(
11768        &mut self,
11769        action: &SelectUpByLines,
11770        window: &mut Window,
11771        cx: &mut Context<Self>,
11772    ) {
11773        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11774        let text_layout_details = &self.text_layout_details(window);
11775        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11776            s.move_heads_with(|map, head, goal| {
11777                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11778            })
11779        })
11780    }
11781
11782    pub fn select_page_up(
11783        &mut self,
11784        _: &SelectPageUp,
11785        window: &mut Window,
11786        cx: &mut Context<Self>,
11787    ) {
11788        let Some(row_count) = self.visible_row_count() else {
11789            return;
11790        };
11791
11792        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11793
11794        let text_layout_details = &self.text_layout_details(window);
11795
11796        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11797            s.move_heads_with(|map, head, goal| {
11798                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11799            })
11800        })
11801    }
11802
11803    pub fn move_page_up(
11804        &mut self,
11805        action: &MovePageUp,
11806        window: &mut Window,
11807        cx: &mut Context<Self>,
11808    ) {
11809        if self.take_rename(true, window, cx).is_some() {
11810            return;
11811        }
11812
11813        if self
11814            .context_menu
11815            .borrow_mut()
11816            .as_mut()
11817            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11818            .unwrap_or(false)
11819        {
11820            return;
11821        }
11822
11823        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11824            cx.propagate();
11825            return;
11826        }
11827
11828        let Some(row_count) = self.visible_row_count() else {
11829            return;
11830        };
11831
11832        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11833
11834        let autoscroll = if action.center_cursor {
11835            Autoscroll::center()
11836        } else {
11837            Autoscroll::fit()
11838        };
11839
11840        let text_layout_details = &self.text_layout_details(window);
11841
11842        self.change_selections(Some(autoscroll), window, cx, |s| {
11843            s.move_with(|map, selection| {
11844                if !selection.is_empty() {
11845                    selection.goal = SelectionGoal::None;
11846                }
11847                let (cursor, goal) = movement::up_by_rows(
11848                    map,
11849                    selection.end,
11850                    row_count,
11851                    selection.goal,
11852                    false,
11853                    text_layout_details,
11854                );
11855                selection.collapse_to(cursor, goal);
11856            });
11857        });
11858    }
11859
11860    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11861        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11862        let text_layout_details = &self.text_layout_details(window);
11863        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11864            s.move_heads_with(|map, head, goal| {
11865                movement::up(map, head, goal, false, text_layout_details)
11866            })
11867        })
11868    }
11869
11870    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11871        self.take_rename(true, window, cx);
11872
11873        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11874            cx.propagate();
11875            return;
11876        }
11877
11878        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11879
11880        let text_layout_details = &self.text_layout_details(window);
11881        let selection_count = self.selections.count();
11882        let first_selection = self.selections.first_anchor();
11883
11884        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11885            s.move_with(|map, selection| {
11886                if !selection.is_empty() {
11887                    selection.goal = SelectionGoal::None;
11888                }
11889                let (cursor, goal) = movement::down(
11890                    map,
11891                    selection.end,
11892                    selection.goal,
11893                    false,
11894                    text_layout_details,
11895                );
11896                selection.collapse_to(cursor, goal);
11897            });
11898        });
11899
11900        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11901        {
11902            cx.propagate();
11903        }
11904    }
11905
11906    pub fn select_page_down(
11907        &mut self,
11908        _: &SelectPageDown,
11909        window: &mut Window,
11910        cx: &mut Context<Self>,
11911    ) {
11912        let Some(row_count) = self.visible_row_count() else {
11913            return;
11914        };
11915
11916        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11917
11918        let text_layout_details = &self.text_layout_details(window);
11919
11920        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11921            s.move_heads_with(|map, head, goal| {
11922                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11923            })
11924        })
11925    }
11926
11927    pub fn move_page_down(
11928        &mut self,
11929        action: &MovePageDown,
11930        window: &mut Window,
11931        cx: &mut Context<Self>,
11932    ) {
11933        if self.take_rename(true, window, cx).is_some() {
11934            return;
11935        }
11936
11937        if self
11938            .context_menu
11939            .borrow_mut()
11940            .as_mut()
11941            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11942            .unwrap_or(false)
11943        {
11944            return;
11945        }
11946
11947        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11948            cx.propagate();
11949            return;
11950        }
11951
11952        let Some(row_count) = self.visible_row_count() else {
11953            return;
11954        };
11955
11956        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11957
11958        let autoscroll = if action.center_cursor {
11959            Autoscroll::center()
11960        } else {
11961            Autoscroll::fit()
11962        };
11963
11964        let text_layout_details = &self.text_layout_details(window);
11965        self.change_selections(Some(autoscroll), window, cx, |s| {
11966            s.move_with(|map, selection| {
11967                if !selection.is_empty() {
11968                    selection.goal = SelectionGoal::None;
11969                }
11970                let (cursor, goal) = movement::down_by_rows(
11971                    map,
11972                    selection.end,
11973                    row_count,
11974                    selection.goal,
11975                    false,
11976                    text_layout_details,
11977                );
11978                selection.collapse_to(cursor, goal);
11979            });
11980        });
11981    }
11982
11983    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11984        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11985        let text_layout_details = &self.text_layout_details(window);
11986        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11987            s.move_heads_with(|map, head, goal| {
11988                movement::down(map, head, goal, false, text_layout_details)
11989            })
11990        });
11991    }
11992
11993    pub fn context_menu_first(
11994        &mut self,
11995        _: &ContextMenuFirst,
11996        window: &mut Window,
11997        cx: &mut Context<Self>,
11998    ) {
11999        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12000            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12001        }
12002    }
12003
12004    pub fn context_menu_prev(
12005        &mut self,
12006        _: &ContextMenuPrevious,
12007        window: &mut Window,
12008        cx: &mut Context<Self>,
12009    ) {
12010        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12011            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12012        }
12013    }
12014
12015    pub fn context_menu_next(
12016        &mut self,
12017        _: &ContextMenuNext,
12018        window: &mut Window,
12019        cx: &mut Context<Self>,
12020    ) {
12021        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12022            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12023        }
12024    }
12025
12026    pub fn context_menu_last(
12027        &mut self,
12028        _: &ContextMenuLast,
12029        window: &mut Window,
12030        cx: &mut Context<Self>,
12031    ) {
12032        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12033            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12034        }
12035    }
12036
12037    pub fn move_to_previous_word_start(
12038        &mut self,
12039        _: &MoveToPreviousWordStart,
12040        window: &mut Window,
12041        cx: &mut Context<Self>,
12042    ) {
12043        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12044        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12045            s.move_cursors_with(|map, head, _| {
12046                (
12047                    movement::previous_word_start(map, head),
12048                    SelectionGoal::None,
12049                )
12050            });
12051        })
12052    }
12053
12054    pub fn move_to_previous_subword_start(
12055        &mut self,
12056        _: &MoveToPreviousSubwordStart,
12057        window: &mut Window,
12058        cx: &mut Context<Self>,
12059    ) {
12060        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12061        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12062            s.move_cursors_with(|map, head, _| {
12063                (
12064                    movement::previous_subword_start(map, head),
12065                    SelectionGoal::None,
12066                )
12067            });
12068        })
12069    }
12070
12071    pub fn select_to_previous_word_start(
12072        &mut self,
12073        _: &SelectToPreviousWordStart,
12074        window: &mut Window,
12075        cx: &mut Context<Self>,
12076    ) {
12077        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12078        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12079            s.move_heads_with(|map, head, _| {
12080                (
12081                    movement::previous_word_start(map, head),
12082                    SelectionGoal::None,
12083                )
12084            });
12085        })
12086    }
12087
12088    pub fn select_to_previous_subword_start(
12089        &mut self,
12090        _: &SelectToPreviousSubwordStart,
12091        window: &mut Window,
12092        cx: &mut Context<Self>,
12093    ) {
12094        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12095        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12096            s.move_heads_with(|map, head, _| {
12097                (
12098                    movement::previous_subword_start(map, head),
12099                    SelectionGoal::None,
12100                )
12101            });
12102        })
12103    }
12104
12105    pub fn delete_to_previous_word_start(
12106        &mut self,
12107        action: &DeleteToPreviousWordStart,
12108        window: &mut Window,
12109        cx: &mut Context<Self>,
12110    ) {
12111        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12112        self.transact(window, cx, |this, window, cx| {
12113            this.select_autoclose_pair(window, cx);
12114            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12115                s.move_with(|map, selection| {
12116                    if selection.is_empty() {
12117                        let cursor = if action.ignore_newlines {
12118                            movement::previous_word_start(map, selection.head())
12119                        } else {
12120                            movement::previous_word_start_or_newline(map, selection.head())
12121                        };
12122                        selection.set_head(cursor, SelectionGoal::None);
12123                    }
12124                });
12125            });
12126            this.insert("", window, cx);
12127        });
12128    }
12129
12130    pub fn delete_to_previous_subword_start(
12131        &mut self,
12132        _: &DeleteToPreviousSubwordStart,
12133        window: &mut Window,
12134        cx: &mut Context<Self>,
12135    ) {
12136        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12137        self.transact(window, cx, |this, window, cx| {
12138            this.select_autoclose_pair(window, cx);
12139            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12140                s.move_with(|map, selection| {
12141                    if selection.is_empty() {
12142                        let cursor = movement::previous_subword_start(map, selection.head());
12143                        selection.set_head(cursor, SelectionGoal::None);
12144                    }
12145                });
12146            });
12147            this.insert("", window, cx);
12148        });
12149    }
12150
12151    pub fn move_to_next_word_end(
12152        &mut self,
12153        _: &MoveToNextWordEnd,
12154        window: &mut Window,
12155        cx: &mut Context<Self>,
12156    ) {
12157        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12158        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12159            s.move_cursors_with(|map, head, _| {
12160                (movement::next_word_end(map, head), SelectionGoal::None)
12161            });
12162        })
12163    }
12164
12165    pub fn move_to_next_subword_end(
12166        &mut self,
12167        _: &MoveToNextSubwordEnd,
12168        window: &mut Window,
12169        cx: &mut Context<Self>,
12170    ) {
12171        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12172        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12173            s.move_cursors_with(|map, head, _| {
12174                (movement::next_subword_end(map, head), SelectionGoal::None)
12175            });
12176        })
12177    }
12178
12179    pub fn select_to_next_word_end(
12180        &mut self,
12181        _: &SelectToNextWordEnd,
12182        window: &mut Window,
12183        cx: &mut Context<Self>,
12184    ) {
12185        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12186        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12187            s.move_heads_with(|map, head, _| {
12188                (movement::next_word_end(map, head), SelectionGoal::None)
12189            });
12190        })
12191    }
12192
12193    pub fn select_to_next_subword_end(
12194        &mut self,
12195        _: &SelectToNextSubwordEnd,
12196        window: &mut Window,
12197        cx: &mut Context<Self>,
12198    ) {
12199        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12200        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12201            s.move_heads_with(|map, head, _| {
12202                (movement::next_subword_end(map, head), SelectionGoal::None)
12203            });
12204        })
12205    }
12206
12207    pub fn delete_to_next_word_end(
12208        &mut self,
12209        action: &DeleteToNextWordEnd,
12210        window: &mut Window,
12211        cx: &mut Context<Self>,
12212    ) {
12213        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12214        self.transact(window, cx, |this, window, cx| {
12215            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12216                s.move_with(|map, selection| {
12217                    if selection.is_empty() {
12218                        let cursor = if action.ignore_newlines {
12219                            movement::next_word_end(map, selection.head())
12220                        } else {
12221                            movement::next_word_end_or_newline(map, selection.head())
12222                        };
12223                        selection.set_head(cursor, SelectionGoal::None);
12224                    }
12225                });
12226            });
12227            this.insert("", window, cx);
12228        });
12229    }
12230
12231    pub fn delete_to_next_subword_end(
12232        &mut self,
12233        _: &DeleteToNextSubwordEnd,
12234        window: &mut Window,
12235        cx: &mut Context<Self>,
12236    ) {
12237        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12238        self.transact(window, cx, |this, window, cx| {
12239            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12240                s.move_with(|map, selection| {
12241                    if selection.is_empty() {
12242                        let cursor = movement::next_subword_end(map, selection.head());
12243                        selection.set_head(cursor, SelectionGoal::None);
12244                    }
12245                });
12246            });
12247            this.insert("", window, cx);
12248        });
12249    }
12250
12251    pub fn move_to_beginning_of_line(
12252        &mut self,
12253        action: &MoveToBeginningOfLine,
12254        window: &mut Window,
12255        cx: &mut Context<Self>,
12256    ) {
12257        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12258        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12259            s.move_cursors_with(|map, head, _| {
12260                (
12261                    movement::indented_line_beginning(
12262                        map,
12263                        head,
12264                        action.stop_at_soft_wraps,
12265                        action.stop_at_indent,
12266                    ),
12267                    SelectionGoal::None,
12268                )
12269            });
12270        })
12271    }
12272
12273    pub fn select_to_beginning_of_line(
12274        &mut self,
12275        action: &SelectToBeginningOfLine,
12276        window: &mut Window,
12277        cx: &mut Context<Self>,
12278    ) {
12279        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12280        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12281            s.move_heads_with(|map, head, _| {
12282                (
12283                    movement::indented_line_beginning(
12284                        map,
12285                        head,
12286                        action.stop_at_soft_wraps,
12287                        action.stop_at_indent,
12288                    ),
12289                    SelectionGoal::None,
12290                )
12291            });
12292        });
12293    }
12294
12295    pub fn delete_to_beginning_of_line(
12296        &mut self,
12297        action: &DeleteToBeginningOfLine,
12298        window: &mut Window,
12299        cx: &mut Context<Self>,
12300    ) {
12301        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12302        self.transact(window, cx, |this, window, cx| {
12303            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12304                s.move_with(|_, selection| {
12305                    selection.reversed = true;
12306                });
12307            });
12308
12309            this.select_to_beginning_of_line(
12310                &SelectToBeginningOfLine {
12311                    stop_at_soft_wraps: false,
12312                    stop_at_indent: action.stop_at_indent,
12313                },
12314                window,
12315                cx,
12316            );
12317            this.backspace(&Backspace, window, cx);
12318        });
12319    }
12320
12321    pub fn move_to_end_of_line(
12322        &mut self,
12323        action: &MoveToEndOfLine,
12324        window: &mut Window,
12325        cx: &mut Context<Self>,
12326    ) {
12327        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12328        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12329            s.move_cursors_with(|map, head, _| {
12330                (
12331                    movement::line_end(map, head, action.stop_at_soft_wraps),
12332                    SelectionGoal::None,
12333                )
12334            });
12335        })
12336    }
12337
12338    pub fn select_to_end_of_line(
12339        &mut self,
12340        action: &SelectToEndOfLine,
12341        window: &mut Window,
12342        cx: &mut Context<Self>,
12343    ) {
12344        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12345        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12346            s.move_heads_with(|map, head, _| {
12347                (
12348                    movement::line_end(map, head, action.stop_at_soft_wraps),
12349                    SelectionGoal::None,
12350                )
12351            });
12352        })
12353    }
12354
12355    pub fn delete_to_end_of_line(
12356        &mut self,
12357        _: &DeleteToEndOfLine,
12358        window: &mut Window,
12359        cx: &mut Context<Self>,
12360    ) {
12361        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12362        self.transact(window, cx, |this, window, cx| {
12363            this.select_to_end_of_line(
12364                &SelectToEndOfLine {
12365                    stop_at_soft_wraps: false,
12366                },
12367                window,
12368                cx,
12369            );
12370            this.delete(&Delete, window, cx);
12371        });
12372    }
12373
12374    pub fn cut_to_end_of_line(
12375        &mut self,
12376        _: &CutToEndOfLine,
12377        window: &mut Window,
12378        cx: &mut Context<Self>,
12379    ) {
12380        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12381        self.transact(window, cx, |this, window, cx| {
12382            this.select_to_end_of_line(
12383                &SelectToEndOfLine {
12384                    stop_at_soft_wraps: false,
12385                },
12386                window,
12387                cx,
12388            );
12389            this.cut(&Cut, window, cx);
12390        });
12391    }
12392
12393    pub fn move_to_start_of_paragraph(
12394        &mut self,
12395        _: &MoveToStartOfParagraph,
12396        window: &mut Window,
12397        cx: &mut Context<Self>,
12398    ) {
12399        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12400            cx.propagate();
12401            return;
12402        }
12403        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12404        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12405            s.move_with(|map, selection| {
12406                selection.collapse_to(
12407                    movement::start_of_paragraph(map, selection.head(), 1),
12408                    SelectionGoal::None,
12409                )
12410            });
12411        })
12412    }
12413
12414    pub fn move_to_end_of_paragraph(
12415        &mut self,
12416        _: &MoveToEndOfParagraph,
12417        window: &mut Window,
12418        cx: &mut Context<Self>,
12419    ) {
12420        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12421            cx.propagate();
12422            return;
12423        }
12424        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12425        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12426            s.move_with(|map, selection| {
12427                selection.collapse_to(
12428                    movement::end_of_paragraph(map, selection.head(), 1),
12429                    SelectionGoal::None,
12430                )
12431            });
12432        })
12433    }
12434
12435    pub fn select_to_start_of_paragraph(
12436        &mut self,
12437        _: &SelectToStartOfParagraph,
12438        window: &mut Window,
12439        cx: &mut Context<Self>,
12440    ) {
12441        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12442            cx.propagate();
12443            return;
12444        }
12445        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12446        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12447            s.move_heads_with(|map, head, _| {
12448                (
12449                    movement::start_of_paragraph(map, head, 1),
12450                    SelectionGoal::None,
12451                )
12452            });
12453        })
12454    }
12455
12456    pub fn select_to_end_of_paragraph(
12457        &mut self,
12458        _: &SelectToEndOfParagraph,
12459        window: &mut Window,
12460        cx: &mut Context<Self>,
12461    ) {
12462        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12463            cx.propagate();
12464            return;
12465        }
12466        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12467        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12468            s.move_heads_with(|map, head, _| {
12469                (
12470                    movement::end_of_paragraph(map, head, 1),
12471                    SelectionGoal::None,
12472                )
12473            });
12474        })
12475    }
12476
12477    pub fn move_to_start_of_excerpt(
12478        &mut self,
12479        _: &MoveToStartOfExcerpt,
12480        window: &mut Window,
12481        cx: &mut Context<Self>,
12482    ) {
12483        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12484            cx.propagate();
12485            return;
12486        }
12487        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12488        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12489            s.move_with(|map, selection| {
12490                selection.collapse_to(
12491                    movement::start_of_excerpt(
12492                        map,
12493                        selection.head(),
12494                        workspace::searchable::Direction::Prev,
12495                    ),
12496                    SelectionGoal::None,
12497                )
12498            });
12499        })
12500    }
12501
12502    pub fn move_to_start_of_next_excerpt(
12503        &mut self,
12504        _: &MoveToStartOfNextExcerpt,
12505        window: &mut Window,
12506        cx: &mut Context<Self>,
12507    ) {
12508        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12509            cx.propagate();
12510            return;
12511        }
12512
12513        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12514            s.move_with(|map, selection| {
12515                selection.collapse_to(
12516                    movement::start_of_excerpt(
12517                        map,
12518                        selection.head(),
12519                        workspace::searchable::Direction::Next,
12520                    ),
12521                    SelectionGoal::None,
12522                )
12523            });
12524        })
12525    }
12526
12527    pub fn move_to_end_of_excerpt(
12528        &mut self,
12529        _: &MoveToEndOfExcerpt,
12530        window: &mut Window,
12531        cx: &mut Context<Self>,
12532    ) {
12533        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12534            cx.propagate();
12535            return;
12536        }
12537        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12538        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12539            s.move_with(|map, selection| {
12540                selection.collapse_to(
12541                    movement::end_of_excerpt(
12542                        map,
12543                        selection.head(),
12544                        workspace::searchable::Direction::Next,
12545                    ),
12546                    SelectionGoal::None,
12547                )
12548            });
12549        })
12550    }
12551
12552    pub fn move_to_end_of_previous_excerpt(
12553        &mut self,
12554        _: &MoveToEndOfPreviousExcerpt,
12555        window: &mut Window,
12556        cx: &mut Context<Self>,
12557    ) {
12558        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12559            cx.propagate();
12560            return;
12561        }
12562        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12563        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12564            s.move_with(|map, selection| {
12565                selection.collapse_to(
12566                    movement::end_of_excerpt(
12567                        map,
12568                        selection.head(),
12569                        workspace::searchable::Direction::Prev,
12570                    ),
12571                    SelectionGoal::None,
12572                )
12573            });
12574        })
12575    }
12576
12577    pub fn select_to_start_of_excerpt(
12578        &mut self,
12579        _: &SelectToStartOfExcerpt,
12580        window: &mut Window,
12581        cx: &mut Context<Self>,
12582    ) {
12583        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12584            cx.propagate();
12585            return;
12586        }
12587        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12588        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12589            s.move_heads_with(|map, head, _| {
12590                (
12591                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12592                    SelectionGoal::None,
12593                )
12594            });
12595        })
12596    }
12597
12598    pub fn select_to_start_of_next_excerpt(
12599        &mut self,
12600        _: &SelectToStartOfNextExcerpt,
12601        window: &mut Window,
12602        cx: &mut Context<Self>,
12603    ) {
12604        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12605            cx.propagate();
12606            return;
12607        }
12608        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12609        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12610            s.move_heads_with(|map, head, _| {
12611                (
12612                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12613                    SelectionGoal::None,
12614                )
12615            });
12616        })
12617    }
12618
12619    pub fn select_to_end_of_excerpt(
12620        &mut self,
12621        _: &SelectToEndOfExcerpt,
12622        window: &mut Window,
12623        cx: &mut Context<Self>,
12624    ) {
12625        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12626            cx.propagate();
12627            return;
12628        }
12629        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12630        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12631            s.move_heads_with(|map, head, _| {
12632                (
12633                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12634                    SelectionGoal::None,
12635                )
12636            });
12637        })
12638    }
12639
12640    pub fn select_to_end_of_previous_excerpt(
12641        &mut self,
12642        _: &SelectToEndOfPreviousExcerpt,
12643        window: &mut Window,
12644        cx: &mut Context<Self>,
12645    ) {
12646        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12647            cx.propagate();
12648            return;
12649        }
12650        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12651        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12652            s.move_heads_with(|map, head, _| {
12653                (
12654                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12655                    SelectionGoal::None,
12656                )
12657            });
12658        })
12659    }
12660
12661    pub fn move_to_beginning(
12662        &mut self,
12663        _: &MoveToBeginning,
12664        window: &mut Window,
12665        cx: &mut Context<Self>,
12666    ) {
12667        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12668            cx.propagate();
12669            return;
12670        }
12671        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12672        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12673            s.select_ranges(vec![0..0]);
12674        });
12675    }
12676
12677    pub fn select_to_beginning(
12678        &mut self,
12679        _: &SelectToBeginning,
12680        window: &mut Window,
12681        cx: &mut Context<Self>,
12682    ) {
12683        let mut selection = self.selections.last::<Point>(cx);
12684        selection.set_head(Point::zero(), SelectionGoal::None);
12685        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12686        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12687            s.select(vec![selection]);
12688        });
12689    }
12690
12691    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12692        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12693            cx.propagate();
12694            return;
12695        }
12696        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12697        let cursor = self.buffer.read(cx).read(cx).len();
12698        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12699            s.select_ranges(vec![cursor..cursor])
12700        });
12701    }
12702
12703    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12704        self.nav_history = nav_history;
12705    }
12706
12707    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12708        self.nav_history.as_ref()
12709    }
12710
12711    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12712        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12713    }
12714
12715    fn push_to_nav_history(
12716        &mut self,
12717        cursor_anchor: Anchor,
12718        new_position: Option<Point>,
12719        is_deactivate: bool,
12720        cx: &mut Context<Self>,
12721    ) {
12722        if let Some(nav_history) = self.nav_history.as_mut() {
12723            let buffer = self.buffer.read(cx).read(cx);
12724            let cursor_position = cursor_anchor.to_point(&buffer);
12725            let scroll_state = self.scroll_manager.anchor();
12726            let scroll_top_row = scroll_state.top_row(&buffer);
12727            drop(buffer);
12728
12729            if let Some(new_position) = new_position {
12730                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12731                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12732                    return;
12733                }
12734            }
12735
12736            nav_history.push(
12737                Some(NavigationData {
12738                    cursor_anchor,
12739                    cursor_position,
12740                    scroll_anchor: scroll_state,
12741                    scroll_top_row,
12742                }),
12743                cx,
12744            );
12745            cx.emit(EditorEvent::PushedToNavHistory {
12746                anchor: cursor_anchor,
12747                is_deactivate,
12748            })
12749        }
12750    }
12751
12752    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12753        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12754        let buffer = self.buffer.read(cx).snapshot(cx);
12755        let mut selection = self.selections.first::<usize>(cx);
12756        selection.set_head(buffer.len(), SelectionGoal::None);
12757        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12758            s.select(vec![selection]);
12759        });
12760    }
12761
12762    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12763        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12764        let end = self.buffer.read(cx).read(cx).len();
12765        self.change_selections(None, window, cx, |s| {
12766            s.select_ranges(vec![0..end]);
12767        });
12768    }
12769
12770    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12771        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12772        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12773        let mut selections = self.selections.all::<Point>(cx);
12774        let max_point = display_map.buffer_snapshot.max_point();
12775        for selection in &mut selections {
12776            let rows = selection.spanned_rows(true, &display_map);
12777            selection.start = Point::new(rows.start.0, 0);
12778            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12779            selection.reversed = false;
12780        }
12781        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12782            s.select(selections);
12783        });
12784    }
12785
12786    pub fn split_selection_into_lines(
12787        &mut self,
12788        _: &SplitSelectionIntoLines,
12789        window: &mut Window,
12790        cx: &mut Context<Self>,
12791    ) {
12792        let selections = self
12793            .selections
12794            .all::<Point>(cx)
12795            .into_iter()
12796            .map(|selection| selection.start..selection.end)
12797            .collect::<Vec<_>>();
12798        self.unfold_ranges(&selections, true, true, cx);
12799
12800        let mut new_selection_ranges = Vec::new();
12801        {
12802            let buffer = self.buffer.read(cx).read(cx);
12803            for selection in selections {
12804                for row in selection.start.row..selection.end.row {
12805                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12806                    new_selection_ranges.push(cursor..cursor);
12807                }
12808
12809                let is_multiline_selection = selection.start.row != selection.end.row;
12810                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12811                // so this action feels more ergonomic when paired with other selection operations
12812                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12813                if !should_skip_last {
12814                    new_selection_ranges.push(selection.end..selection.end);
12815                }
12816            }
12817        }
12818        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12819            s.select_ranges(new_selection_ranges);
12820        });
12821    }
12822
12823    pub fn add_selection_above(
12824        &mut self,
12825        _: &AddSelectionAbove,
12826        window: &mut Window,
12827        cx: &mut Context<Self>,
12828    ) {
12829        self.add_selection(true, window, cx);
12830    }
12831
12832    pub fn add_selection_below(
12833        &mut self,
12834        _: &AddSelectionBelow,
12835        window: &mut Window,
12836        cx: &mut Context<Self>,
12837    ) {
12838        self.add_selection(false, window, cx);
12839    }
12840
12841    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12842        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12843
12844        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12845        let all_selections = self.selections.all::<Point>(cx);
12846        let text_layout_details = self.text_layout_details(window);
12847
12848        let (mut columnar_selections, new_selections_to_columnarize) = {
12849            if let Some(state) = self.add_selections_state.as_ref() {
12850                let columnar_selection_ids: HashSet<_> = state
12851                    .groups
12852                    .iter()
12853                    .flat_map(|group| group.stack.iter())
12854                    .copied()
12855                    .collect();
12856
12857                all_selections
12858                    .into_iter()
12859                    .partition(|s| columnar_selection_ids.contains(&s.id))
12860            } else {
12861                (Vec::new(), all_selections)
12862            }
12863        };
12864
12865        let mut state = self
12866            .add_selections_state
12867            .take()
12868            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12869
12870        for selection in new_selections_to_columnarize {
12871            let range = selection.display_range(&display_map).sorted();
12872            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12873            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12874            let positions = start_x.min(end_x)..start_x.max(end_x);
12875            let mut stack = Vec::new();
12876            for row in range.start.row().0..=range.end.row().0 {
12877                if let Some(selection) = self.selections.build_columnar_selection(
12878                    &display_map,
12879                    DisplayRow(row),
12880                    &positions,
12881                    selection.reversed,
12882                    &text_layout_details,
12883                ) {
12884                    stack.push(selection.id);
12885                    columnar_selections.push(selection);
12886                }
12887            }
12888            if !stack.is_empty() {
12889                if above {
12890                    stack.reverse();
12891                }
12892                state.groups.push(AddSelectionsGroup { above, stack });
12893            }
12894        }
12895
12896        let mut final_selections = Vec::new();
12897        let end_row = if above {
12898            DisplayRow(0)
12899        } else {
12900            display_map.max_point().row()
12901        };
12902
12903        let mut last_added_item_per_group = HashMap::default();
12904        for group in state.groups.iter_mut() {
12905            if let Some(last_id) = group.stack.last() {
12906                last_added_item_per_group.insert(*last_id, group);
12907            }
12908        }
12909
12910        for selection in columnar_selections {
12911            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
12912                if above == group.above {
12913                    let range = selection.display_range(&display_map).sorted();
12914                    debug_assert_eq!(range.start.row(), range.end.row());
12915                    let mut row = range.start.row();
12916                    let positions =
12917                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12918                            px(start)..px(end)
12919                        } else {
12920                            let start_x =
12921                                display_map.x_for_display_point(range.start, &text_layout_details);
12922                            let end_x =
12923                                display_map.x_for_display_point(range.end, &text_layout_details);
12924                            start_x.min(end_x)..start_x.max(end_x)
12925                        };
12926
12927                    let mut maybe_new_selection = None;
12928                    while row != end_row {
12929                        if above {
12930                            row.0 -= 1;
12931                        } else {
12932                            row.0 += 1;
12933                        }
12934                        if let Some(new_selection) = self.selections.build_columnar_selection(
12935                            &display_map,
12936                            row,
12937                            &positions,
12938                            selection.reversed,
12939                            &text_layout_details,
12940                        ) {
12941                            maybe_new_selection = Some(new_selection);
12942                            break;
12943                        }
12944                    }
12945
12946                    if let Some(new_selection) = maybe_new_selection {
12947                        group.stack.push(new_selection.id);
12948                        if above {
12949                            final_selections.push(new_selection);
12950                            final_selections.push(selection);
12951                        } else {
12952                            final_selections.push(selection);
12953                            final_selections.push(new_selection);
12954                        }
12955                    } else {
12956                        final_selections.push(selection);
12957                    }
12958                } else {
12959                    group.stack.pop();
12960                }
12961            } else {
12962                final_selections.push(selection);
12963            }
12964        }
12965
12966        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12967            s.select(final_selections);
12968        });
12969
12970        let final_selection_ids: HashSet<_> = self
12971            .selections
12972            .all::<Point>(cx)
12973            .iter()
12974            .map(|s| s.id)
12975            .collect();
12976        state.groups.retain_mut(|group| {
12977            // selections might get merged above so we remove invalid items from stacks
12978            group.stack.retain(|id| final_selection_ids.contains(id));
12979
12980            // single selection in stack can be treated as initial state
12981            group.stack.len() > 1
12982        });
12983
12984        if !state.groups.is_empty() {
12985            self.add_selections_state = Some(state);
12986        }
12987    }
12988
12989    fn select_match_ranges(
12990        &mut self,
12991        range: Range<usize>,
12992        reversed: bool,
12993        replace_newest: bool,
12994        auto_scroll: Option<Autoscroll>,
12995        window: &mut Window,
12996        cx: &mut Context<Editor>,
12997    ) {
12998        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12999        self.change_selections(auto_scroll, window, cx, |s| {
13000            if replace_newest {
13001                s.delete(s.newest_anchor().id);
13002            }
13003            if reversed {
13004                s.insert_range(range.end..range.start);
13005            } else {
13006                s.insert_range(range);
13007            }
13008        });
13009    }
13010
13011    pub fn select_next_match_internal(
13012        &mut self,
13013        display_map: &DisplaySnapshot,
13014        replace_newest: bool,
13015        autoscroll: Option<Autoscroll>,
13016        window: &mut Window,
13017        cx: &mut Context<Self>,
13018    ) -> Result<()> {
13019        let buffer = &display_map.buffer_snapshot;
13020        let mut selections = self.selections.all::<usize>(cx);
13021        if let Some(mut select_next_state) = self.select_next_state.take() {
13022            let query = &select_next_state.query;
13023            if !select_next_state.done {
13024                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13025                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13026                let mut next_selected_range = None;
13027
13028                let bytes_after_last_selection =
13029                    buffer.bytes_in_range(last_selection.end..buffer.len());
13030                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13031                let query_matches = query
13032                    .stream_find_iter(bytes_after_last_selection)
13033                    .map(|result| (last_selection.end, result))
13034                    .chain(
13035                        query
13036                            .stream_find_iter(bytes_before_first_selection)
13037                            .map(|result| (0, result)),
13038                    );
13039
13040                for (start_offset, query_match) in query_matches {
13041                    let query_match = query_match.unwrap(); // can only fail due to I/O
13042                    let offset_range =
13043                        start_offset + query_match.start()..start_offset + query_match.end();
13044                    let display_range = offset_range.start.to_display_point(display_map)
13045                        ..offset_range.end.to_display_point(display_map);
13046
13047                    if !select_next_state.wordwise
13048                        || (!movement::is_inside_word(display_map, display_range.start)
13049                            && !movement::is_inside_word(display_map, display_range.end))
13050                    {
13051                        // TODO: This is n^2, because we might check all the selections
13052                        if !selections
13053                            .iter()
13054                            .any(|selection| selection.range().overlaps(&offset_range))
13055                        {
13056                            next_selected_range = Some(offset_range);
13057                            break;
13058                        }
13059                    }
13060                }
13061
13062                if let Some(next_selected_range) = next_selected_range {
13063                    self.select_match_ranges(
13064                        next_selected_range,
13065                        last_selection.reversed,
13066                        replace_newest,
13067                        autoscroll,
13068                        window,
13069                        cx,
13070                    );
13071                } else {
13072                    select_next_state.done = true;
13073                }
13074            }
13075
13076            self.select_next_state = Some(select_next_state);
13077        } else {
13078            let mut only_carets = true;
13079            let mut same_text_selected = true;
13080            let mut selected_text = None;
13081
13082            let mut selections_iter = selections.iter().peekable();
13083            while let Some(selection) = selections_iter.next() {
13084                if selection.start != selection.end {
13085                    only_carets = false;
13086                }
13087
13088                if same_text_selected {
13089                    if selected_text.is_none() {
13090                        selected_text =
13091                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13092                    }
13093
13094                    if let Some(next_selection) = selections_iter.peek() {
13095                        if next_selection.range().len() == selection.range().len() {
13096                            let next_selected_text = buffer
13097                                .text_for_range(next_selection.range())
13098                                .collect::<String>();
13099                            if Some(next_selected_text) != selected_text {
13100                                same_text_selected = false;
13101                                selected_text = None;
13102                            }
13103                        } else {
13104                            same_text_selected = false;
13105                            selected_text = None;
13106                        }
13107                    }
13108                }
13109            }
13110
13111            if only_carets {
13112                for selection in &mut selections {
13113                    let word_range = movement::surrounding_word(
13114                        display_map,
13115                        selection.start.to_display_point(display_map),
13116                    );
13117                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13118                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13119                    selection.goal = SelectionGoal::None;
13120                    selection.reversed = false;
13121                    self.select_match_ranges(
13122                        selection.start..selection.end,
13123                        selection.reversed,
13124                        replace_newest,
13125                        autoscroll,
13126                        window,
13127                        cx,
13128                    );
13129                }
13130
13131                if selections.len() == 1 {
13132                    let selection = selections
13133                        .last()
13134                        .expect("ensured that there's only one selection");
13135                    let query = buffer
13136                        .text_for_range(selection.start..selection.end)
13137                        .collect::<String>();
13138                    let is_empty = query.is_empty();
13139                    let select_state = SelectNextState {
13140                        query: AhoCorasick::new(&[query])?,
13141                        wordwise: true,
13142                        done: is_empty,
13143                    };
13144                    self.select_next_state = Some(select_state);
13145                } else {
13146                    self.select_next_state = None;
13147                }
13148            } else if let Some(selected_text) = selected_text {
13149                self.select_next_state = Some(SelectNextState {
13150                    query: AhoCorasick::new(&[selected_text])?,
13151                    wordwise: false,
13152                    done: false,
13153                });
13154                self.select_next_match_internal(
13155                    display_map,
13156                    replace_newest,
13157                    autoscroll,
13158                    window,
13159                    cx,
13160                )?;
13161            }
13162        }
13163        Ok(())
13164    }
13165
13166    pub fn select_all_matches(
13167        &mut self,
13168        _action: &SelectAllMatches,
13169        window: &mut Window,
13170        cx: &mut Context<Self>,
13171    ) -> Result<()> {
13172        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13173
13174        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13175
13176        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13177        let Some(select_next_state) = self.select_next_state.as_mut() else {
13178            return Ok(());
13179        };
13180        if select_next_state.done {
13181            return Ok(());
13182        }
13183
13184        let mut new_selections = Vec::new();
13185
13186        let reversed = self.selections.oldest::<usize>(cx).reversed;
13187        let buffer = &display_map.buffer_snapshot;
13188        let query_matches = select_next_state
13189            .query
13190            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13191
13192        for query_match in query_matches.into_iter() {
13193            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13194            let offset_range = if reversed {
13195                query_match.end()..query_match.start()
13196            } else {
13197                query_match.start()..query_match.end()
13198            };
13199            let display_range = offset_range.start.to_display_point(&display_map)
13200                ..offset_range.end.to_display_point(&display_map);
13201
13202            if !select_next_state.wordwise
13203                || (!movement::is_inside_word(&display_map, display_range.start)
13204                    && !movement::is_inside_word(&display_map, display_range.end))
13205            {
13206                new_selections.push(offset_range.start..offset_range.end);
13207            }
13208        }
13209
13210        select_next_state.done = true;
13211        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13212        self.change_selections(None, window, cx, |selections| {
13213            selections.select_ranges(new_selections)
13214        });
13215
13216        Ok(())
13217    }
13218
13219    pub fn select_next(
13220        &mut self,
13221        action: &SelectNext,
13222        window: &mut Window,
13223        cx: &mut Context<Self>,
13224    ) -> Result<()> {
13225        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13226        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13227        self.select_next_match_internal(
13228            &display_map,
13229            action.replace_newest,
13230            Some(Autoscroll::newest()),
13231            window,
13232            cx,
13233        )?;
13234        Ok(())
13235    }
13236
13237    pub fn select_previous(
13238        &mut self,
13239        action: &SelectPrevious,
13240        window: &mut Window,
13241        cx: &mut Context<Self>,
13242    ) -> Result<()> {
13243        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13244        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13245        let buffer = &display_map.buffer_snapshot;
13246        let mut selections = self.selections.all::<usize>(cx);
13247        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13248            let query = &select_prev_state.query;
13249            if !select_prev_state.done {
13250                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13251                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13252                let mut next_selected_range = None;
13253                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13254                let bytes_before_last_selection =
13255                    buffer.reversed_bytes_in_range(0..last_selection.start);
13256                let bytes_after_first_selection =
13257                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13258                let query_matches = query
13259                    .stream_find_iter(bytes_before_last_selection)
13260                    .map(|result| (last_selection.start, result))
13261                    .chain(
13262                        query
13263                            .stream_find_iter(bytes_after_first_selection)
13264                            .map(|result| (buffer.len(), result)),
13265                    );
13266                for (end_offset, query_match) in query_matches {
13267                    let query_match = query_match.unwrap(); // can only fail due to I/O
13268                    let offset_range =
13269                        end_offset - query_match.end()..end_offset - query_match.start();
13270                    let display_range = offset_range.start.to_display_point(&display_map)
13271                        ..offset_range.end.to_display_point(&display_map);
13272
13273                    if !select_prev_state.wordwise
13274                        || (!movement::is_inside_word(&display_map, display_range.start)
13275                            && !movement::is_inside_word(&display_map, display_range.end))
13276                    {
13277                        next_selected_range = Some(offset_range);
13278                        break;
13279                    }
13280                }
13281
13282                if let Some(next_selected_range) = next_selected_range {
13283                    self.select_match_ranges(
13284                        next_selected_range,
13285                        last_selection.reversed,
13286                        action.replace_newest,
13287                        Some(Autoscroll::newest()),
13288                        window,
13289                        cx,
13290                    );
13291                } else {
13292                    select_prev_state.done = true;
13293                }
13294            }
13295
13296            self.select_prev_state = Some(select_prev_state);
13297        } else {
13298            let mut only_carets = true;
13299            let mut same_text_selected = true;
13300            let mut selected_text = None;
13301
13302            let mut selections_iter = selections.iter().peekable();
13303            while let Some(selection) = selections_iter.next() {
13304                if selection.start != selection.end {
13305                    only_carets = false;
13306                }
13307
13308                if same_text_selected {
13309                    if selected_text.is_none() {
13310                        selected_text =
13311                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13312                    }
13313
13314                    if let Some(next_selection) = selections_iter.peek() {
13315                        if next_selection.range().len() == selection.range().len() {
13316                            let next_selected_text = buffer
13317                                .text_for_range(next_selection.range())
13318                                .collect::<String>();
13319                            if Some(next_selected_text) != selected_text {
13320                                same_text_selected = false;
13321                                selected_text = None;
13322                            }
13323                        } else {
13324                            same_text_selected = false;
13325                            selected_text = None;
13326                        }
13327                    }
13328                }
13329            }
13330
13331            if only_carets {
13332                for selection in &mut selections {
13333                    let word_range = movement::surrounding_word(
13334                        &display_map,
13335                        selection.start.to_display_point(&display_map),
13336                    );
13337                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13338                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13339                    selection.goal = SelectionGoal::None;
13340                    selection.reversed = false;
13341                    self.select_match_ranges(
13342                        selection.start..selection.end,
13343                        selection.reversed,
13344                        action.replace_newest,
13345                        Some(Autoscroll::newest()),
13346                        window,
13347                        cx,
13348                    );
13349                }
13350                if selections.len() == 1 {
13351                    let selection = selections
13352                        .last()
13353                        .expect("ensured that there's only one selection");
13354                    let query = buffer
13355                        .text_for_range(selection.start..selection.end)
13356                        .collect::<String>();
13357                    let is_empty = query.is_empty();
13358                    let select_state = SelectNextState {
13359                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13360                        wordwise: true,
13361                        done: is_empty,
13362                    };
13363                    self.select_prev_state = Some(select_state);
13364                } else {
13365                    self.select_prev_state = None;
13366                }
13367            } else if let Some(selected_text) = selected_text {
13368                self.select_prev_state = Some(SelectNextState {
13369                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13370                    wordwise: false,
13371                    done: false,
13372                });
13373                self.select_previous(action, window, cx)?;
13374            }
13375        }
13376        Ok(())
13377    }
13378
13379    pub fn find_next_match(
13380        &mut self,
13381        _: &FindNextMatch,
13382        window: &mut Window,
13383        cx: &mut Context<Self>,
13384    ) -> Result<()> {
13385        let selections = self.selections.disjoint_anchors();
13386        match selections.first() {
13387            Some(first) if selections.len() >= 2 => {
13388                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13389                    s.select_ranges([first.range()]);
13390                });
13391            }
13392            _ => self.select_next(
13393                &SelectNext {
13394                    replace_newest: true,
13395                },
13396                window,
13397                cx,
13398            )?,
13399        }
13400        Ok(())
13401    }
13402
13403    pub fn find_previous_match(
13404        &mut self,
13405        _: &FindPreviousMatch,
13406        window: &mut Window,
13407        cx: &mut Context<Self>,
13408    ) -> Result<()> {
13409        let selections = self.selections.disjoint_anchors();
13410        match selections.last() {
13411            Some(last) if selections.len() >= 2 => {
13412                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13413                    s.select_ranges([last.range()]);
13414                });
13415            }
13416            _ => self.select_previous(
13417                &SelectPrevious {
13418                    replace_newest: true,
13419                },
13420                window,
13421                cx,
13422            )?,
13423        }
13424        Ok(())
13425    }
13426
13427    pub fn toggle_comments(
13428        &mut self,
13429        action: &ToggleComments,
13430        window: &mut Window,
13431        cx: &mut Context<Self>,
13432    ) {
13433        if self.read_only(cx) {
13434            return;
13435        }
13436        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13437        let text_layout_details = &self.text_layout_details(window);
13438        self.transact(window, cx, |this, window, cx| {
13439            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13440            let mut edits = Vec::new();
13441            let mut selection_edit_ranges = Vec::new();
13442            let mut last_toggled_row = None;
13443            let snapshot = this.buffer.read(cx).read(cx);
13444            let empty_str: Arc<str> = Arc::default();
13445            let mut suffixes_inserted = Vec::new();
13446            let ignore_indent = action.ignore_indent;
13447
13448            fn comment_prefix_range(
13449                snapshot: &MultiBufferSnapshot,
13450                row: MultiBufferRow,
13451                comment_prefix: &str,
13452                comment_prefix_whitespace: &str,
13453                ignore_indent: bool,
13454            ) -> Range<Point> {
13455                let indent_size = if ignore_indent {
13456                    0
13457                } else {
13458                    snapshot.indent_size_for_line(row).len
13459                };
13460
13461                let start = Point::new(row.0, indent_size);
13462
13463                let mut line_bytes = snapshot
13464                    .bytes_in_range(start..snapshot.max_point())
13465                    .flatten()
13466                    .copied();
13467
13468                // If this line currently begins with the line comment prefix, then record
13469                // the range containing the prefix.
13470                if line_bytes
13471                    .by_ref()
13472                    .take(comment_prefix.len())
13473                    .eq(comment_prefix.bytes())
13474                {
13475                    // Include any whitespace that matches the comment prefix.
13476                    let matching_whitespace_len = line_bytes
13477                        .zip(comment_prefix_whitespace.bytes())
13478                        .take_while(|(a, b)| a == b)
13479                        .count() as u32;
13480                    let end = Point::new(
13481                        start.row,
13482                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13483                    );
13484                    start..end
13485                } else {
13486                    start..start
13487                }
13488            }
13489
13490            fn comment_suffix_range(
13491                snapshot: &MultiBufferSnapshot,
13492                row: MultiBufferRow,
13493                comment_suffix: &str,
13494                comment_suffix_has_leading_space: bool,
13495            ) -> Range<Point> {
13496                let end = Point::new(row.0, snapshot.line_len(row));
13497                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13498
13499                let mut line_end_bytes = snapshot
13500                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13501                    .flatten()
13502                    .copied();
13503
13504                let leading_space_len = if suffix_start_column > 0
13505                    && line_end_bytes.next() == Some(b' ')
13506                    && comment_suffix_has_leading_space
13507                {
13508                    1
13509                } else {
13510                    0
13511                };
13512
13513                // If this line currently begins with the line comment prefix, then record
13514                // the range containing the prefix.
13515                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13516                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13517                    start..end
13518                } else {
13519                    end..end
13520                }
13521            }
13522
13523            // TODO: Handle selections that cross excerpts
13524            for selection in &mut selections {
13525                let start_column = snapshot
13526                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13527                    .len;
13528                let language = if let Some(language) =
13529                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13530                {
13531                    language
13532                } else {
13533                    continue;
13534                };
13535
13536                selection_edit_ranges.clear();
13537
13538                // If multiple selections contain a given row, avoid processing that
13539                // row more than once.
13540                let mut start_row = MultiBufferRow(selection.start.row);
13541                if last_toggled_row == Some(start_row) {
13542                    start_row = start_row.next_row();
13543                }
13544                let end_row =
13545                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13546                        MultiBufferRow(selection.end.row - 1)
13547                    } else {
13548                        MultiBufferRow(selection.end.row)
13549                    };
13550                last_toggled_row = Some(end_row);
13551
13552                if start_row > end_row {
13553                    continue;
13554                }
13555
13556                // If the language has line comments, toggle those.
13557                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13558
13559                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13560                if ignore_indent {
13561                    full_comment_prefixes = full_comment_prefixes
13562                        .into_iter()
13563                        .map(|s| Arc::from(s.trim_end()))
13564                        .collect();
13565                }
13566
13567                if !full_comment_prefixes.is_empty() {
13568                    let first_prefix = full_comment_prefixes
13569                        .first()
13570                        .expect("prefixes is non-empty");
13571                    let prefix_trimmed_lengths = full_comment_prefixes
13572                        .iter()
13573                        .map(|p| p.trim_end_matches(' ').len())
13574                        .collect::<SmallVec<[usize; 4]>>();
13575
13576                    let mut all_selection_lines_are_comments = true;
13577
13578                    for row in start_row.0..=end_row.0 {
13579                        let row = MultiBufferRow(row);
13580                        if start_row < end_row && snapshot.is_line_blank(row) {
13581                            continue;
13582                        }
13583
13584                        let prefix_range = full_comment_prefixes
13585                            .iter()
13586                            .zip(prefix_trimmed_lengths.iter().copied())
13587                            .map(|(prefix, trimmed_prefix_len)| {
13588                                comment_prefix_range(
13589                                    snapshot.deref(),
13590                                    row,
13591                                    &prefix[..trimmed_prefix_len],
13592                                    &prefix[trimmed_prefix_len..],
13593                                    ignore_indent,
13594                                )
13595                            })
13596                            .max_by_key(|range| range.end.column - range.start.column)
13597                            .expect("prefixes is non-empty");
13598
13599                        if prefix_range.is_empty() {
13600                            all_selection_lines_are_comments = false;
13601                        }
13602
13603                        selection_edit_ranges.push(prefix_range);
13604                    }
13605
13606                    if all_selection_lines_are_comments {
13607                        edits.extend(
13608                            selection_edit_ranges
13609                                .iter()
13610                                .cloned()
13611                                .map(|range| (range, empty_str.clone())),
13612                        );
13613                    } else {
13614                        let min_column = selection_edit_ranges
13615                            .iter()
13616                            .map(|range| range.start.column)
13617                            .min()
13618                            .unwrap_or(0);
13619                        edits.extend(selection_edit_ranges.iter().map(|range| {
13620                            let position = Point::new(range.start.row, min_column);
13621                            (position..position, first_prefix.clone())
13622                        }));
13623                    }
13624                } else if let Some((full_comment_prefix, comment_suffix)) =
13625                    language.block_comment_delimiters()
13626                {
13627                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13628                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13629                    let prefix_range = comment_prefix_range(
13630                        snapshot.deref(),
13631                        start_row,
13632                        comment_prefix,
13633                        comment_prefix_whitespace,
13634                        ignore_indent,
13635                    );
13636                    let suffix_range = comment_suffix_range(
13637                        snapshot.deref(),
13638                        end_row,
13639                        comment_suffix.trim_start_matches(' '),
13640                        comment_suffix.starts_with(' '),
13641                    );
13642
13643                    if prefix_range.is_empty() || suffix_range.is_empty() {
13644                        edits.push((
13645                            prefix_range.start..prefix_range.start,
13646                            full_comment_prefix.clone(),
13647                        ));
13648                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13649                        suffixes_inserted.push((end_row, comment_suffix.len()));
13650                    } else {
13651                        edits.push((prefix_range, empty_str.clone()));
13652                        edits.push((suffix_range, empty_str.clone()));
13653                    }
13654                } else {
13655                    continue;
13656                }
13657            }
13658
13659            drop(snapshot);
13660            this.buffer.update(cx, |buffer, cx| {
13661                buffer.edit(edits, None, cx);
13662            });
13663
13664            // Adjust selections so that they end before any comment suffixes that
13665            // were inserted.
13666            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13667            let mut selections = this.selections.all::<Point>(cx);
13668            let snapshot = this.buffer.read(cx).read(cx);
13669            for selection in &mut selections {
13670                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13671                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13672                        Ordering::Less => {
13673                            suffixes_inserted.next();
13674                            continue;
13675                        }
13676                        Ordering::Greater => break,
13677                        Ordering::Equal => {
13678                            if selection.end.column == snapshot.line_len(row) {
13679                                if selection.is_empty() {
13680                                    selection.start.column -= suffix_len as u32;
13681                                }
13682                                selection.end.column -= suffix_len as u32;
13683                            }
13684                            break;
13685                        }
13686                    }
13687                }
13688            }
13689
13690            drop(snapshot);
13691            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13692                s.select(selections)
13693            });
13694
13695            let selections = this.selections.all::<Point>(cx);
13696            let selections_on_single_row = selections.windows(2).all(|selections| {
13697                selections[0].start.row == selections[1].start.row
13698                    && selections[0].end.row == selections[1].end.row
13699                    && selections[0].start.row == selections[0].end.row
13700            });
13701            let selections_selecting = selections
13702                .iter()
13703                .any(|selection| selection.start != selection.end);
13704            let advance_downwards = action.advance_downwards
13705                && selections_on_single_row
13706                && !selections_selecting
13707                && !matches!(this.mode, EditorMode::SingleLine { .. });
13708
13709            if advance_downwards {
13710                let snapshot = this.buffer.read(cx).snapshot(cx);
13711
13712                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13713                    s.move_cursors_with(|display_snapshot, display_point, _| {
13714                        let mut point = display_point.to_point(display_snapshot);
13715                        point.row += 1;
13716                        point = snapshot.clip_point(point, Bias::Left);
13717                        let display_point = point.to_display_point(display_snapshot);
13718                        let goal = SelectionGoal::HorizontalPosition(
13719                            display_snapshot
13720                                .x_for_display_point(display_point, text_layout_details)
13721                                .into(),
13722                        );
13723                        (display_point, goal)
13724                    })
13725                });
13726            }
13727        });
13728    }
13729
13730    pub fn select_enclosing_symbol(
13731        &mut self,
13732        _: &SelectEnclosingSymbol,
13733        window: &mut Window,
13734        cx: &mut Context<Self>,
13735    ) {
13736        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13737
13738        let buffer = self.buffer.read(cx).snapshot(cx);
13739        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13740
13741        fn update_selection(
13742            selection: &Selection<usize>,
13743            buffer_snap: &MultiBufferSnapshot,
13744        ) -> Option<Selection<usize>> {
13745            let cursor = selection.head();
13746            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13747            for symbol in symbols.iter().rev() {
13748                let start = symbol.range.start.to_offset(buffer_snap);
13749                let end = symbol.range.end.to_offset(buffer_snap);
13750                let new_range = start..end;
13751                if start < selection.start || end > selection.end {
13752                    return Some(Selection {
13753                        id: selection.id,
13754                        start: new_range.start,
13755                        end: new_range.end,
13756                        goal: SelectionGoal::None,
13757                        reversed: selection.reversed,
13758                    });
13759                }
13760            }
13761            None
13762        }
13763
13764        let mut selected_larger_symbol = false;
13765        let new_selections = old_selections
13766            .iter()
13767            .map(|selection| match update_selection(selection, &buffer) {
13768                Some(new_selection) => {
13769                    if new_selection.range() != selection.range() {
13770                        selected_larger_symbol = true;
13771                    }
13772                    new_selection
13773                }
13774                None => selection.clone(),
13775            })
13776            .collect::<Vec<_>>();
13777
13778        if selected_larger_symbol {
13779            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13780                s.select(new_selections);
13781            });
13782        }
13783    }
13784
13785    pub fn select_larger_syntax_node(
13786        &mut self,
13787        _: &SelectLargerSyntaxNode,
13788        window: &mut Window,
13789        cx: &mut Context<Self>,
13790    ) {
13791        let Some(visible_row_count) = self.visible_row_count() else {
13792            return;
13793        };
13794        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13795        if old_selections.is_empty() {
13796            return;
13797        }
13798
13799        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13800
13801        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13802        let buffer = self.buffer.read(cx).snapshot(cx);
13803
13804        let mut selected_larger_node = false;
13805        let mut new_selections = old_selections
13806            .iter()
13807            .map(|selection| {
13808                let old_range = selection.start..selection.end;
13809
13810                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13811                    // manually select word at selection
13812                    if ["string_content", "inline"].contains(&node.kind()) {
13813                        let word_range = {
13814                            let display_point = buffer
13815                                .offset_to_point(old_range.start)
13816                                .to_display_point(&display_map);
13817                            let Range { start, end } =
13818                                movement::surrounding_word(&display_map, display_point);
13819                            start.to_point(&display_map).to_offset(&buffer)
13820                                ..end.to_point(&display_map).to_offset(&buffer)
13821                        };
13822                        // ignore if word is already selected
13823                        if !word_range.is_empty() && old_range != word_range {
13824                            let last_word_range = {
13825                                let display_point = buffer
13826                                    .offset_to_point(old_range.end)
13827                                    .to_display_point(&display_map);
13828                                let Range { start, end } =
13829                                    movement::surrounding_word(&display_map, display_point);
13830                                start.to_point(&display_map).to_offset(&buffer)
13831                                    ..end.to_point(&display_map).to_offset(&buffer)
13832                            };
13833                            // only select word if start and end point belongs to same word
13834                            if word_range == last_word_range {
13835                                selected_larger_node = true;
13836                                return Selection {
13837                                    id: selection.id,
13838                                    start: word_range.start,
13839                                    end: word_range.end,
13840                                    goal: SelectionGoal::None,
13841                                    reversed: selection.reversed,
13842                                };
13843                            }
13844                        }
13845                    }
13846                }
13847
13848                let mut new_range = old_range.clone();
13849                while let Some((_node, containing_range)) =
13850                    buffer.syntax_ancestor(new_range.clone())
13851                {
13852                    new_range = match containing_range {
13853                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13854                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13855                    };
13856                    if !display_map.intersects_fold(new_range.start)
13857                        && !display_map.intersects_fold(new_range.end)
13858                    {
13859                        break;
13860                    }
13861                }
13862
13863                selected_larger_node |= new_range != old_range;
13864                Selection {
13865                    id: selection.id,
13866                    start: new_range.start,
13867                    end: new_range.end,
13868                    goal: SelectionGoal::None,
13869                    reversed: selection.reversed,
13870                }
13871            })
13872            .collect::<Vec<_>>();
13873
13874        if !selected_larger_node {
13875            return; // don't put this call in the history
13876        }
13877
13878        // scroll based on transformation done to the last selection created by the user
13879        let (last_old, last_new) = old_selections
13880            .last()
13881            .zip(new_selections.last().cloned())
13882            .expect("old_selections isn't empty");
13883
13884        // revert selection
13885        let is_selection_reversed = {
13886            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13887            new_selections.last_mut().expect("checked above").reversed =
13888                should_newest_selection_be_reversed;
13889            should_newest_selection_be_reversed
13890        };
13891
13892        if selected_larger_node {
13893            self.select_syntax_node_history.disable_clearing = true;
13894            self.change_selections(None, window, cx, |s| {
13895                s.select(new_selections.clone());
13896            });
13897            self.select_syntax_node_history.disable_clearing = false;
13898        }
13899
13900        let start_row = last_new.start.to_display_point(&display_map).row().0;
13901        let end_row = last_new.end.to_display_point(&display_map).row().0;
13902        let selection_height = end_row - start_row + 1;
13903        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13904
13905        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13906        let scroll_behavior = if fits_on_the_screen {
13907            self.request_autoscroll(Autoscroll::fit(), cx);
13908            SelectSyntaxNodeScrollBehavior::FitSelection
13909        } else if is_selection_reversed {
13910            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13911            SelectSyntaxNodeScrollBehavior::CursorTop
13912        } else {
13913            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13914            SelectSyntaxNodeScrollBehavior::CursorBottom
13915        };
13916
13917        self.select_syntax_node_history.push((
13918            old_selections,
13919            scroll_behavior,
13920            is_selection_reversed,
13921        ));
13922    }
13923
13924    pub fn select_smaller_syntax_node(
13925        &mut self,
13926        _: &SelectSmallerSyntaxNode,
13927        window: &mut Window,
13928        cx: &mut Context<Self>,
13929    ) {
13930        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13931
13932        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13933            self.select_syntax_node_history.pop()
13934        {
13935            if let Some(selection) = selections.last_mut() {
13936                selection.reversed = is_selection_reversed;
13937            }
13938
13939            self.select_syntax_node_history.disable_clearing = true;
13940            self.change_selections(None, window, cx, |s| {
13941                s.select(selections.to_vec());
13942            });
13943            self.select_syntax_node_history.disable_clearing = false;
13944
13945            match scroll_behavior {
13946                SelectSyntaxNodeScrollBehavior::CursorTop => {
13947                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13948                }
13949                SelectSyntaxNodeScrollBehavior::FitSelection => {
13950                    self.request_autoscroll(Autoscroll::fit(), cx);
13951                }
13952                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13953                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13954                }
13955            }
13956        }
13957    }
13958
13959    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13960        if !EditorSettings::get_global(cx).gutter.runnables {
13961            self.clear_tasks();
13962            return Task::ready(());
13963        }
13964        let project = self.project.as_ref().map(Entity::downgrade);
13965        let task_sources = self.lsp_task_sources(cx);
13966        let multi_buffer = self.buffer.downgrade();
13967        cx.spawn_in(window, async move |editor, cx| {
13968            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13969            let Some(project) = project.and_then(|p| p.upgrade()) else {
13970                return;
13971            };
13972            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13973                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13974            }) else {
13975                return;
13976            };
13977
13978            let hide_runnables = project
13979                .update(cx, |project, cx| {
13980                    // Do not display any test indicators in non-dev server remote projects.
13981                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13982                })
13983                .unwrap_or(true);
13984            if hide_runnables {
13985                return;
13986            }
13987            let new_rows =
13988                cx.background_spawn({
13989                    let snapshot = display_snapshot.clone();
13990                    async move {
13991                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13992                    }
13993                })
13994                    .await;
13995            let Ok(lsp_tasks) =
13996                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13997            else {
13998                return;
13999            };
14000            let lsp_tasks = lsp_tasks.await;
14001
14002            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14003                lsp_tasks
14004                    .into_iter()
14005                    .flat_map(|(kind, tasks)| {
14006                        tasks.into_iter().filter_map(move |(location, task)| {
14007                            Some((kind.clone(), location?, task))
14008                        })
14009                    })
14010                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14011                        let buffer = location.target.buffer;
14012                        let buffer_snapshot = buffer.read(cx).snapshot();
14013                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14014                            |(excerpt_id, snapshot, _)| {
14015                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14016                                    display_snapshot
14017                                        .buffer_snapshot
14018                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14019                                } else {
14020                                    None
14021                                }
14022                            },
14023                        );
14024                        if let Some(offset) = offset {
14025                            let task_buffer_range =
14026                                location.target.range.to_point(&buffer_snapshot);
14027                            let context_buffer_range =
14028                                task_buffer_range.to_offset(&buffer_snapshot);
14029                            let context_range = BufferOffset(context_buffer_range.start)
14030                                ..BufferOffset(context_buffer_range.end);
14031
14032                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14033                                .or_insert_with(|| RunnableTasks {
14034                                    templates: Vec::new(),
14035                                    offset,
14036                                    column: task_buffer_range.start.column,
14037                                    extra_variables: HashMap::default(),
14038                                    context_range,
14039                                })
14040                                .templates
14041                                .push((kind, task.original_task().clone()));
14042                        }
14043
14044                        acc
14045                    })
14046            }) else {
14047                return;
14048            };
14049
14050            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14051                buffer.language_settings(cx).tasks.prefer_lsp
14052            }) else {
14053                return;
14054            };
14055
14056            let rows = Self::runnable_rows(
14057                project,
14058                display_snapshot,
14059                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14060                new_rows,
14061                cx.clone(),
14062            )
14063            .await;
14064            editor
14065                .update(cx, |editor, _| {
14066                    editor.clear_tasks();
14067                    for (key, mut value) in rows {
14068                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14069                            value.templates.extend(lsp_tasks.templates);
14070                        }
14071
14072                        editor.insert_tasks(key, value);
14073                    }
14074                    for (key, value) in lsp_tasks_by_rows {
14075                        editor.insert_tasks(key, value);
14076                    }
14077                })
14078                .ok();
14079        })
14080    }
14081    fn fetch_runnable_ranges(
14082        snapshot: &DisplaySnapshot,
14083        range: Range<Anchor>,
14084    ) -> Vec<language::RunnableRange> {
14085        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14086    }
14087
14088    fn runnable_rows(
14089        project: Entity<Project>,
14090        snapshot: DisplaySnapshot,
14091        prefer_lsp: bool,
14092        runnable_ranges: Vec<RunnableRange>,
14093        cx: AsyncWindowContext,
14094    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14095        cx.spawn(async move |cx| {
14096            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14097            for mut runnable in runnable_ranges {
14098                let Some(tasks) = cx
14099                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14100                    .ok()
14101                else {
14102                    continue;
14103                };
14104                let mut tasks = tasks.await;
14105
14106                if prefer_lsp {
14107                    tasks.retain(|(task_kind, _)| {
14108                        !matches!(task_kind, TaskSourceKind::Language { .. })
14109                    });
14110                }
14111                if tasks.is_empty() {
14112                    continue;
14113                }
14114
14115                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14116                let Some(row) = snapshot
14117                    .buffer_snapshot
14118                    .buffer_line_for_row(MultiBufferRow(point.row))
14119                    .map(|(_, range)| range.start.row)
14120                else {
14121                    continue;
14122                };
14123
14124                let context_range =
14125                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14126                runnable_rows.push((
14127                    (runnable.buffer_id, row),
14128                    RunnableTasks {
14129                        templates: tasks,
14130                        offset: snapshot
14131                            .buffer_snapshot
14132                            .anchor_before(runnable.run_range.start),
14133                        context_range,
14134                        column: point.column,
14135                        extra_variables: runnable.extra_captures,
14136                    },
14137                ));
14138            }
14139            runnable_rows
14140        })
14141    }
14142
14143    fn templates_with_tags(
14144        project: &Entity<Project>,
14145        runnable: &mut Runnable,
14146        cx: &mut App,
14147    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14148        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14149            let (worktree_id, file) = project
14150                .buffer_for_id(runnable.buffer, cx)
14151                .and_then(|buffer| buffer.read(cx).file())
14152                .map(|file| (file.worktree_id(cx), file.clone()))
14153                .unzip();
14154
14155            (
14156                project.task_store().read(cx).task_inventory().cloned(),
14157                worktree_id,
14158                file,
14159            )
14160        });
14161
14162        let tags = mem::take(&mut runnable.tags);
14163        let language = runnable.language.clone();
14164        cx.spawn(async move |cx| {
14165            let mut templates_with_tags = Vec::new();
14166            if let Some(inventory) = inventory {
14167                for RunnableTag(tag) in tags {
14168                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14169                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14170                    }) else {
14171                        return templates_with_tags;
14172                    };
14173                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14174                        move |(_, template)| {
14175                            template.tags.iter().any(|source_tag| source_tag == &tag)
14176                        },
14177                    ));
14178                }
14179            }
14180            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14181
14182            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14183                // Strongest source wins; if we have worktree tag binding, prefer that to
14184                // global and language bindings;
14185                // if we have a global binding, prefer that to language binding.
14186                let first_mismatch = templates_with_tags
14187                    .iter()
14188                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14189                if let Some(index) = first_mismatch {
14190                    templates_with_tags.truncate(index);
14191                }
14192            }
14193
14194            templates_with_tags
14195        })
14196    }
14197
14198    pub fn move_to_enclosing_bracket(
14199        &mut self,
14200        _: &MoveToEnclosingBracket,
14201        window: &mut Window,
14202        cx: &mut Context<Self>,
14203    ) {
14204        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14205        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14206            s.move_offsets_with(|snapshot, selection| {
14207                let Some(enclosing_bracket_ranges) =
14208                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14209                else {
14210                    return;
14211                };
14212
14213                let mut best_length = usize::MAX;
14214                let mut best_inside = false;
14215                let mut best_in_bracket_range = false;
14216                let mut best_destination = None;
14217                for (open, close) in enclosing_bracket_ranges {
14218                    let close = close.to_inclusive();
14219                    let length = close.end() - open.start;
14220                    let inside = selection.start >= open.end && selection.end <= *close.start();
14221                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14222                        || close.contains(&selection.head());
14223
14224                    // If best is next to a bracket and current isn't, skip
14225                    if !in_bracket_range && best_in_bracket_range {
14226                        continue;
14227                    }
14228
14229                    // Prefer smaller lengths unless best is inside and current isn't
14230                    if length > best_length && (best_inside || !inside) {
14231                        continue;
14232                    }
14233
14234                    best_length = length;
14235                    best_inside = inside;
14236                    best_in_bracket_range = in_bracket_range;
14237                    best_destination = Some(
14238                        if close.contains(&selection.start) && close.contains(&selection.end) {
14239                            if inside { open.end } else { open.start }
14240                        } else if inside {
14241                            *close.start()
14242                        } else {
14243                            *close.end()
14244                        },
14245                    );
14246                }
14247
14248                if let Some(destination) = best_destination {
14249                    selection.collapse_to(destination, SelectionGoal::None);
14250                }
14251            })
14252        });
14253    }
14254
14255    pub fn undo_selection(
14256        &mut self,
14257        _: &UndoSelection,
14258        window: &mut Window,
14259        cx: &mut Context<Self>,
14260    ) {
14261        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14262        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14263            self.selection_history.mode = SelectionHistoryMode::Undoing;
14264            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14265                this.end_selection(window, cx);
14266                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14267                    s.select_anchors(entry.selections.to_vec())
14268                });
14269            });
14270            self.selection_history.mode = SelectionHistoryMode::Normal;
14271
14272            self.select_next_state = entry.select_next_state;
14273            self.select_prev_state = entry.select_prev_state;
14274            self.add_selections_state = entry.add_selections_state;
14275        }
14276    }
14277
14278    pub fn redo_selection(
14279        &mut self,
14280        _: &RedoSelection,
14281        window: &mut Window,
14282        cx: &mut Context<Self>,
14283    ) {
14284        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14285        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14286            self.selection_history.mode = SelectionHistoryMode::Redoing;
14287            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14288                this.end_selection(window, cx);
14289                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14290                    s.select_anchors(entry.selections.to_vec())
14291                });
14292            });
14293            self.selection_history.mode = SelectionHistoryMode::Normal;
14294
14295            self.select_next_state = entry.select_next_state;
14296            self.select_prev_state = entry.select_prev_state;
14297            self.add_selections_state = entry.add_selections_state;
14298        }
14299    }
14300
14301    pub fn expand_excerpts(
14302        &mut self,
14303        action: &ExpandExcerpts,
14304        _: &mut Window,
14305        cx: &mut Context<Self>,
14306    ) {
14307        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14308    }
14309
14310    pub fn expand_excerpts_down(
14311        &mut self,
14312        action: &ExpandExcerptsDown,
14313        _: &mut Window,
14314        cx: &mut Context<Self>,
14315    ) {
14316        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14317    }
14318
14319    pub fn expand_excerpts_up(
14320        &mut self,
14321        action: &ExpandExcerptsUp,
14322        _: &mut Window,
14323        cx: &mut Context<Self>,
14324    ) {
14325        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14326    }
14327
14328    pub fn expand_excerpts_for_direction(
14329        &mut self,
14330        lines: u32,
14331        direction: ExpandExcerptDirection,
14332
14333        cx: &mut Context<Self>,
14334    ) {
14335        let selections = self.selections.disjoint_anchors();
14336
14337        let lines = if lines == 0 {
14338            EditorSettings::get_global(cx).expand_excerpt_lines
14339        } else {
14340            lines
14341        };
14342
14343        self.buffer.update(cx, |buffer, cx| {
14344            let snapshot = buffer.snapshot(cx);
14345            let mut excerpt_ids = selections
14346                .iter()
14347                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14348                .collect::<Vec<_>>();
14349            excerpt_ids.sort();
14350            excerpt_ids.dedup();
14351            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14352        })
14353    }
14354
14355    pub fn expand_excerpt(
14356        &mut self,
14357        excerpt: ExcerptId,
14358        direction: ExpandExcerptDirection,
14359        window: &mut Window,
14360        cx: &mut Context<Self>,
14361    ) {
14362        let current_scroll_position = self.scroll_position(cx);
14363        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14364        let mut should_scroll_up = false;
14365
14366        if direction == ExpandExcerptDirection::Down {
14367            let multi_buffer = self.buffer.read(cx);
14368            let snapshot = multi_buffer.snapshot(cx);
14369            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14370                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14371                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14372                        let buffer_snapshot = buffer.read(cx).snapshot();
14373                        let excerpt_end_row =
14374                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14375                        let last_row = buffer_snapshot.max_point().row;
14376                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14377                        should_scroll_up = lines_below >= lines_to_expand;
14378                    }
14379                }
14380            }
14381        }
14382
14383        self.buffer.update(cx, |buffer, cx| {
14384            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14385        });
14386
14387        if should_scroll_up {
14388            let new_scroll_position =
14389                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14390            self.set_scroll_position(new_scroll_position, window, cx);
14391        }
14392    }
14393
14394    pub fn go_to_singleton_buffer_point(
14395        &mut self,
14396        point: Point,
14397        window: &mut Window,
14398        cx: &mut Context<Self>,
14399    ) {
14400        self.go_to_singleton_buffer_range(point..point, window, cx);
14401    }
14402
14403    pub fn go_to_singleton_buffer_range(
14404        &mut self,
14405        range: Range<Point>,
14406        window: &mut Window,
14407        cx: &mut Context<Self>,
14408    ) {
14409        let multibuffer = self.buffer().read(cx);
14410        let Some(buffer) = multibuffer.as_singleton() else {
14411            return;
14412        };
14413        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14414            return;
14415        };
14416        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14417            return;
14418        };
14419        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14420            s.select_anchor_ranges([start..end])
14421        });
14422    }
14423
14424    pub fn go_to_diagnostic(
14425        &mut self,
14426        _: &GoToDiagnostic,
14427        window: &mut Window,
14428        cx: &mut Context<Self>,
14429    ) {
14430        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14431        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14432    }
14433
14434    pub fn go_to_prev_diagnostic(
14435        &mut self,
14436        _: &GoToPreviousDiagnostic,
14437        window: &mut Window,
14438        cx: &mut Context<Self>,
14439    ) {
14440        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14441        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14442    }
14443
14444    pub fn go_to_diagnostic_impl(
14445        &mut self,
14446        direction: Direction,
14447        window: &mut Window,
14448        cx: &mut Context<Self>,
14449    ) {
14450        let buffer = self.buffer.read(cx).snapshot(cx);
14451        let selection = self.selections.newest::<usize>(cx);
14452
14453        let mut active_group_id = None;
14454        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14455            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14456                active_group_id = Some(active_group.group_id);
14457            }
14458        }
14459
14460        fn filtered(
14461            snapshot: EditorSnapshot,
14462            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14463        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14464            diagnostics
14465                .filter(|entry| entry.range.start != entry.range.end)
14466                .filter(|entry| !entry.diagnostic.is_unnecessary)
14467                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14468        }
14469
14470        let snapshot = self.snapshot(window, cx);
14471        let before = filtered(
14472            snapshot.clone(),
14473            buffer
14474                .diagnostics_in_range(0..selection.start)
14475                .filter(|entry| entry.range.start <= selection.start),
14476        );
14477        let after = filtered(
14478            snapshot,
14479            buffer
14480                .diagnostics_in_range(selection.start..buffer.len())
14481                .filter(|entry| entry.range.start >= selection.start),
14482        );
14483
14484        let mut found: Option<DiagnosticEntry<usize>> = None;
14485        if direction == Direction::Prev {
14486            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14487            {
14488                for diagnostic in prev_diagnostics.into_iter().rev() {
14489                    if diagnostic.range.start != selection.start
14490                        || active_group_id
14491                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14492                    {
14493                        found = Some(diagnostic);
14494                        break 'outer;
14495                    }
14496                }
14497            }
14498        } else {
14499            for diagnostic in after.chain(before) {
14500                if diagnostic.range.start != selection.start
14501                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14502                {
14503                    found = Some(diagnostic);
14504                    break;
14505                }
14506            }
14507        }
14508        let Some(next_diagnostic) = found else {
14509            return;
14510        };
14511
14512        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14513            return;
14514        };
14515        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14516            s.select_ranges(vec![
14517                next_diagnostic.range.start..next_diagnostic.range.start,
14518            ])
14519        });
14520        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14521        self.refresh_inline_completion(false, true, window, cx);
14522    }
14523
14524    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14525        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14526        let snapshot = self.snapshot(window, cx);
14527        let selection = self.selections.newest::<Point>(cx);
14528        self.go_to_hunk_before_or_after_position(
14529            &snapshot,
14530            selection.head(),
14531            Direction::Next,
14532            window,
14533            cx,
14534        );
14535    }
14536
14537    pub fn go_to_hunk_before_or_after_position(
14538        &mut self,
14539        snapshot: &EditorSnapshot,
14540        position: Point,
14541        direction: Direction,
14542        window: &mut Window,
14543        cx: &mut Context<Editor>,
14544    ) {
14545        let row = if direction == Direction::Next {
14546            self.hunk_after_position(snapshot, position)
14547                .map(|hunk| hunk.row_range.start)
14548        } else {
14549            self.hunk_before_position(snapshot, position)
14550        };
14551
14552        if let Some(row) = row {
14553            let destination = Point::new(row.0, 0);
14554            let autoscroll = Autoscroll::center();
14555
14556            self.unfold_ranges(&[destination..destination], false, false, cx);
14557            self.change_selections(Some(autoscroll), window, cx, |s| {
14558                s.select_ranges([destination..destination]);
14559            });
14560        }
14561    }
14562
14563    fn hunk_after_position(
14564        &mut self,
14565        snapshot: &EditorSnapshot,
14566        position: Point,
14567    ) -> Option<MultiBufferDiffHunk> {
14568        snapshot
14569            .buffer_snapshot
14570            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14571            .find(|hunk| hunk.row_range.start.0 > position.row)
14572            .or_else(|| {
14573                snapshot
14574                    .buffer_snapshot
14575                    .diff_hunks_in_range(Point::zero()..position)
14576                    .find(|hunk| hunk.row_range.end.0 < position.row)
14577            })
14578    }
14579
14580    fn go_to_prev_hunk(
14581        &mut self,
14582        _: &GoToPreviousHunk,
14583        window: &mut Window,
14584        cx: &mut Context<Self>,
14585    ) {
14586        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14587        let snapshot = self.snapshot(window, cx);
14588        let selection = self.selections.newest::<Point>(cx);
14589        self.go_to_hunk_before_or_after_position(
14590            &snapshot,
14591            selection.head(),
14592            Direction::Prev,
14593            window,
14594            cx,
14595        );
14596    }
14597
14598    fn hunk_before_position(
14599        &mut self,
14600        snapshot: &EditorSnapshot,
14601        position: Point,
14602    ) -> Option<MultiBufferRow> {
14603        snapshot
14604            .buffer_snapshot
14605            .diff_hunk_before(position)
14606            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14607    }
14608
14609    fn go_to_next_change(
14610        &mut self,
14611        _: &GoToNextChange,
14612        window: &mut Window,
14613        cx: &mut Context<Self>,
14614    ) {
14615        if let Some(selections) = self
14616            .change_list
14617            .next_change(1, Direction::Next)
14618            .map(|s| s.to_vec())
14619        {
14620            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14621                let map = s.display_map();
14622                s.select_display_ranges(selections.iter().map(|a| {
14623                    let point = a.to_display_point(&map);
14624                    point..point
14625                }))
14626            })
14627        }
14628    }
14629
14630    fn go_to_previous_change(
14631        &mut self,
14632        _: &GoToPreviousChange,
14633        window: &mut Window,
14634        cx: &mut Context<Self>,
14635    ) {
14636        if let Some(selections) = self
14637            .change_list
14638            .next_change(1, Direction::Prev)
14639            .map(|s| s.to_vec())
14640        {
14641            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14642                let map = s.display_map();
14643                s.select_display_ranges(selections.iter().map(|a| {
14644                    let point = a.to_display_point(&map);
14645                    point..point
14646                }))
14647            })
14648        }
14649    }
14650
14651    fn go_to_line<T: 'static>(
14652        &mut self,
14653        position: Anchor,
14654        highlight_color: Option<Hsla>,
14655        window: &mut Window,
14656        cx: &mut Context<Self>,
14657    ) {
14658        let snapshot = self.snapshot(window, cx).display_snapshot;
14659        let position = position.to_point(&snapshot.buffer_snapshot);
14660        let start = snapshot
14661            .buffer_snapshot
14662            .clip_point(Point::new(position.row, 0), Bias::Left);
14663        let end = start + Point::new(1, 0);
14664        let start = snapshot.buffer_snapshot.anchor_before(start);
14665        let end = snapshot.buffer_snapshot.anchor_before(end);
14666
14667        self.highlight_rows::<T>(
14668            start..end,
14669            highlight_color
14670                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14671            Default::default(),
14672            cx,
14673        );
14674
14675        if self.buffer.read(cx).is_singleton() {
14676            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14677        }
14678    }
14679
14680    pub fn go_to_definition(
14681        &mut self,
14682        _: &GoToDefinition,
14683        window: &mut Window,
14684        cx: &mut Context<Self>,
14685    ) -> Task<Result<Navigated>> {
14686        let definition =
14687            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14688        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14689        cx.spawn_in(window, async move |editor, cx| {
14690            if definition.await? == Navigated::Yes {
14691                return Ok(Navigated::Yes);
14692            }
14693            match fallback_strategy {
14694                GoToDefinitionFallback::None => Ok(Navigated::No),
14695                GoToDefinitionFallback::FindAllReferences => {
14696                    match editor.update_in(cx, |editor, window, cx| {
14697                        editor.find_all_references(&FindAllReferences, window, cx)
14698                    })? {
14699                        Some(references) => references.await,
14700                        None => Ok(Navigated::No),
14701                    }
14702                }
14703            }
14704        })
14705    }
14706
14707    pub fn go_to_declaration(
14708        &mut self,
14709        _: &GoToDeclaration,
14710        window: &mut Window,
14711        cx: &mut Context<Self>,
14712    ) -> Task<Result<Navigated>> {
14713        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14714    }
14715
14716    pub fn go_to_declaration_split(
14717        &mut self,
14718        _: &GoToDeclaration,
14719        window: &mut Window,
14720        cx: &mut Context<Self>,
14721    ) -> Task<Result<Navigated>> {
14722        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14723    }
14724
14725    pub fn go_to_implementation(
14726        &mut self,
14727        _: &GoToImplementation,
14728        window: &mut Window,
14729        cx: &mut Context<Self>,
14730    ) -> Task<Result<Navigated>> {
14731        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14732    }
14733
14734    pub fn go_to_implementation_split(
14735        &mut self,
14736        _: &GoToImplementationSplit,
14737        window: &mut Window,
14738        cx: &mut Context<Self>,
14739    ) -> Task<Result<Navigated>> {
14740        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14741    }
14742
14743    pub fn go_to_type_definition(
14744        &mut self,
14745        _: &GoToTypeDefinition,
14746        window: &mut Window,
14747        cx: &mut Context<Self>,
14748    ) -> Task<Result<Navigated>> {
14749        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14750    }
14751
14752    pub fn go_to_definition_split(
14753        &mut self,
14754        _: &GoToDefinitionSplit,
14755        window: &mut Window,
14756        cx: &mut Context<Self>,
14757    ) -> Task<Result<Navigated>> {
14758        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14759    }
14760
14761    pub fn go_to_type_definition_split(
14762        &mut self,
14763        _: &GoToTypeDefinitionSplit,
14764        window: &mut Window,
14765        cx: &mut Context<Self>,
14766    ) -> Task<Result<Navigated>> {
14767        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14768    }
14769
14770    fn go_to_definition_of_kind(
14771        &mut self,
14772        kind: GotoDefinitionKind,
14773        split: bool,
14774        window: &mut Window,
14775        cx: &mut Context<Self>,
14776    ) -> Task<Result<Navigated>> {
14777        let Some(provider) = self.semantics_provider.clone() else {
14778            return Task::ready(Ok(Navigated::No));
14779        };
14780        let head = self.selections.newest::<usize>(cx).head();
14781        let buffer = self.buffer.read(cx);
14782        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14783            text_anchor
14784        } else {
14785            return Task::ready(Ok(Navigated::No));
14786        };
14787
14788        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14789            return Task::ready(Ok(Navigated::No));
14790        };
14791
14792        cx.spawn_in(window, async move |editor, cx| {
14793            let definitions = definitions.await?;
14794            let navigated = editor
14795                .update_in(cx, |editor, window, cx| {
14796                    editor.navigate_to_hover_links(
14797                        Some(kind),
14798                        definitions
14799                            .into_iter()
14800                            .filter(|location| {
14801                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14802                            })
14803                            .map(HoverLink::Text)
14804                            .collect::<Vec<_>>(),
14805                        split,
14806                        window,
14807                        cx,
14808                    )
14809                })?
14810                .await?;
14811            anyhow::Ok(navigated)
14812        })
14813    }
14814
14815    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14816        let selection = self.selections.newest_anchor();
14817        let head = selection.head();
14818        let tail = selection.tail();
14819
14820        let Some((buffer, start_position)) =
14821            self.buffer.read(cx).text_anchor_for_position(head, cx)
14822        else {
14823            return;
14824        };
14825
14826        let end_position = if head != tail {
14827            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14828                return;
14829            };
14830            Some(pos)
14831        } else {
14832            None
14833        };
14834
14835        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14836            let url = if let Some(end_pos) = end_position {
14837                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14838            } else {
14839                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14840            };
14841
14842            if let Some(url) = url {
14843                editor.update(cx, |_, cx| {
14844                    cx.open_url(&url);
14845                })
14846            } else {
14847                Ok(())
14848            }
14849        });
14850
14851        url_finder.detach();
14852    }
14853
14854    pub fn open_selected_filename(
14855        &mut self,
14856        _: &OpenSelectedFilename,
14857        window: &mut Window,
14858        cx: &mut Context<Self>,
14859    ) {
14860        let Some(workspace) = self.workspace() else {
14861            return;
14862        };
14863
14864        let position = self.selections.newest_anchor().head();
14865
14866        let Some((buffer, buffer_position)) =
14867            self.buffer.read(cx).text_anchor_for_position(position, cx)
14868        else {
14869            return;
14870        };
14871
14872        let project = self.project.clone();
14873
14874        cx.spawn_in(window, async move |_, cx| {
14875            let result = find_file(&buffer, project, buffer_position, cx).await;
14876
14877            if let Some((_, path)) = result {
14878                workspace
14879                    .update_in(cx, |workspace, window, cx| {
14880                        workspace.open_resolved_path(path, window, cx)
14881                    })?
14882                    .await?;
14883            }
14884            anyhow::Ok(())
14885        })
14886        .detach();
14887    }
14888
14889    pub(crate) fn navigate_to_hover_links(
14890        &mut self,
14891        kind: Option<GotoDefinitionKind>,
14892        mut definitions: Vec<HoverLink>,
14893        split: bool,
14894        window: &mut Window,
14895        cx: &mut Context<Editor>,
14896    ) -> Task<Result<Navigated>> {
14897        // If there is one definition, just open it directly
14898        if definitions.len() == 1 {
14899            let definition = definitions.pop().unwrap();
14900
14901            enum TargetTaskResult {
14902                Location(Option<Location>),
14903                AlreadyNavigated,
14904            }
14905
14906            let target_task = match definition {
14907                HoverLink::Text(link) => {
14908                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14909                }
14910                HoverLink::InlayHint(lsp_location, server_id) => {
14911                    let computation =
14912                        self.compute_target_location(lsp_location, server_id, window, cx);
14913                    cx.background_spawn(async move {
14914                        let location = computation.await?;
14915                        Ok(TargetTaskResult::Location(location))
14916                    })
14917                }
14918                HoverLink::Url(url) => {
14919                    cx.open_url(&url);
14920                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14921                }
14922                HoverLink::File(path) => {
14923                    if let Some(workspace) = self.workspace() {
14924                        cx.spawn_in(window, async move |_, cx| {
14925                            workspace
14926                                .update_in(cx, |workspace, window, cx| {
14927                                    workspace.open_resolved_path(path, window, cx)
14928                                })?
14929                                .await
14930                                .map(|_| TargetTaskResult::AlreadyNavigated)
14931                        })
14932                    } else {
14933                        Task::ready(Ok(TargetTaskResult::Location(None)))
14934                    }
14935                }
14936            };
14937            cx.spawn_in(window, async move |editor, cx| {
14938                let target = match target_task.await.context("target resolution task")? {
14939                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14940                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14941                    TargetTaskResult::Location(Some(target)) => target,
14942                };
14943
14944                editor.update_in(cx, |editor, window, cx| {
14945                    let Some(workspace) = editor.workspace() else {
14946                        return Navigated::No;
14947                    };
14948                    let pane = workspace.read(cx).active_pane().clone();
14949
14950                    let range = target.range.to_point(target.buffer.read(cx));
14951                    let range = editor.range_for_match(&range);
14952                    let range = collapse_multiline_range(range);
14953
14954                    if !split
14955                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14956                    {
14957                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14958                    } else {
14959                        window.defer(cx, move |window, cx| {
14960                            let target_editor: Entity<Self> =
14961                                workspace.update(cx, |workspace, cx| {
14962                                    let pane = if split {
14963                                        workspace.adjacent_pane(window, cx)
14964                                    } else {
14965                                        workspace.active_pane().clone()
14966                                    };
14967
14968                                    workspace.open_project_item(
14969                                        pane,
14970                                        target.buffer.clone(),
14971                                        true,
14972                                        true,
14973                                        window,
14974                                        cx,
14975                                    )
14976                                });
14977                            target_editor.update(cx, |target_editor, cx| {
14978                                // When selecting a definition in a different buffer, disable the nav history
14979                                // to avoid creating a history entry at the previous cursor location.
14980                                pane.update(cx, |pane, _| pane.disable_history());
14981                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14982                                pane.update(cx, |pane, _| pane.enable_history());
14983                            });
14984                        });
14985                    }
14986                    Navigated::Yes
14987                })
14988            })
14989        } else if !definitions.is_empty() {
14990            cx.spawn_in(window, async move |editor, cx| {
14991                let (title, location_tasks, workspace) = editor
14992                    .update_in(cx, |editor, window, cx| {
14993                        let tab_kind = match kind {
14994                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14995                            _ => "Definitions",
14996                        };
14997                        let title = definitions
14998                            .iter()
14999                            .find_map(|definition| match definition {
15000                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15001                                    let buffer = origin.buffer.read(cx);
15002                                    format!(
15003                                        "{} for {}",
15004                                        tab_kind,
15005                                        buffer
15006                                            .text_for_range(origin.range.clone())
15007                                            .collect::<String>()
15008                                    )
15009                                }),
15010                                HoverLink::InlayHint(_, _) => None,
15011                                HoverLink::Url(_) => None,
15012                                HoverLink::File(_) => None,
15013                            })
15014                            .unwrap_or(tab_kind.to_string());
15015                        let location_tasks = definitions
15016                            .into_iter()
15017                            .map(|definition| match definition {
15018                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15019                                HoverLink::InlayHint(lsp_location, server_id) => editor
15020                                    .compute_target_location(lsp_location, server_id, window, cx),
15021                                HoverLink::Url(_) => Task::ready(Ok(None)),
15022                                HoverLink::File(_) => Task::ready(Ok(None)),
15023                            })
15024                            .collect::<Vec<_>>();
15025                        (title, location_tasks, editor.workspace().clone())
15026                    })
15027                    .context("location tasks preparation")?;
15028
15029                let locations = future::join_all(location_tasks)
15030                    .await
15031                    .into_iter()
15032                    .filter_map(|location| location.transpose())
15033                    .collect::<Result<_>>()
15034                    .context("location tasks")?;
15035
15036                let Some(workspace) = workspace else {
15037                    return Ok(Navigated::No);
15038                };
15039                let opened = workspace
15040                    .update_in(cx, |workspace, window, cx| {
15041                        Self::open_locations_in_multibuffer(
15042                            workspace,
15043                            locations,
15044                            title,
15045                            split,
15046                            MultibufferSelectionMode::First,
15047                            window,
15048                            cx,
15049                        )
15050                    })
15051                    .ok();
15052
15053                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15054            })
15055        } else {
15056            Task::ready(Ok(Navigated::No))
15057        }
15058    }
15059
15060    fn compute_target_location(
15061        &self,
15062        lsp_location: lsp::Location,
15063        server_id: LanguageServerId,
15064        window: &mut Window,
15065        cx: &mut Context<Self>,
15066    ) -> Task<anyhow::Result<Option<Location>>> {
15067        let Some(project) = self.project.clone() else {
15068            return Task::ready(Ok(None));
15069        };
15070
15071        cx.spawn_in(window, async move |editor, cx| {
15072            let location_task = editor.update(cx, |_, cx| {
15073                project.update(cx, |project, cx| {
15074                    let language_server_name = project
15075                        .language_server_statuses(cx)
15076                        .find(|(id, _)| server_id == *id)
15077                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15078                    language_server_name.map(|language_server_name| {
15079                        project.open_local_buffer_via_lsp(
15080                            lsp_location.uri.clone(),
15081                            server_id,
15082                            language_server_name,
15083                            cx,
15084                        )
15085                    })
15086                })
15087            })?;
15088            let location = match location_task {
15089                Some(task) => Some({
15090                    let target_buffer_handle = task.await.context("open local buffer")?;
15091                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15092                        let target_start = target_buffer
15093                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15094                        let target_end = target_buffer
15095                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15096                        target_buffer.anchor_after(target_start)
15097                            ..target_buffer.anchor_before(target_end)
15098                    })?;
15099                    Location {
15100                        buffer: target_buffer_handle,
15101                        range,
15102                    }
15103                }),
15104                None => None,
15105            };
15106            Ok(location)
15107        })
15108    }
15109
15110    pub fn find_all_references(
15111        &mut self,
15112        _: &FindAllReferences,
15113        window: &mut Window,
15114        cx: &mut Context<Self>,
15115    ) -> Option<Task<Result<Navigated>>> {
15116        let selection = self.selections.newest::<usize>(cx);
15117        let multi_buffer = self.buffer.read(cx);
15118        let head = selection.head();
15119
15120        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15121        let head_anchor = multi_buffer_snapshot.anchor_at(
15122            head,
15123            if head < selection.tail() {
15124                Bias::Right
15125            } else {
15126                Bias::Left
15127            },
15128        );
15129
15130        match self
15131            .find_all_references_task_sources
15132            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15133        {
15134            Ok(_) => {
15135                log::info!(
15136                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15137                );
15138                return None;
15139            }
15140            Err(i) => {
15141                self.find_all_references_task_sources.insert(i, head_anchor);
15142            }
15143        }
15144
15145        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15146        let workspace = self.workspace()?;
15147        let project = workspace.read(cx).project().clone();
15148        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15149        Some(cx.spawn_in(window, async move |editor, cx| {
15150            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15151                if let Ok(i) = editor
15152                    .find_all_references_task_sources
15153                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15154                {
15155                    editor.find_all_references_task_sources.remove(i);
15156                }
15157            });
15158
15159            let locations = references.await?;
15160            if locations.is_empty() {
15161                return anyhow::Ok(Navigated::No);
15162            }
15163
15164            workspace.update_in(cx, |workspace, window, cx| {
15165                let title = locations
15166                    .first()
15167                    .as_ref()
15168                    .map(|location| {
15169                        let buffer = location.buffer.read(cx);
15170                        format!(
15171                            "References to `{}`",
15172                            buffer
15173                                .text_for_range(location.range.clone())
15174                                .collect::<String>()
15175                        )
15176                    })
15177                    .unwrap();
15178                Self::open_locations_in_multibuffer(
15179                    workspace,
15180                    locations,
15181                    title,
15182                    false,
15183                    MultibufferSelectionMode::First,
15184                    window,
15185                    cx,
15186                );
15187                Navigated::Yes
15188            })
15189        }))
15190    }
15191
15192    /// Opens a multibuffer with the given project locations in it
15193    pub fn open_locations_in_multibuffer(
15194        workspace: &mut Workspace,
15195        mut locations: Vec<Location>,
15196        title: String,
15197        split: bool,
15198        multibuffer_selection_mode: MultibufferSelectionMode,
15199        window: &mut Window,
15200        cx: &mut Context<Workspace>,
15201    ) {
15202        // If there are multiple definitions, open them in a multibuffer
15203        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15204        let mut locations = locations.into_iter().peekable();
15205        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15206        let capability = workspace.project().read(cx).capability();
15207
15208        let excerpt_buffer = cx.new(|cx| {
15209            let mut multibuffer = MultiBuffer::new(capability);
15210            while let Some(location) = locations.next() {
15211                let buffer = location.buffer.read(cx);
15212                let mut ranges_for_buffer = Vec::new();
15213                let range = location.range.to_point(buffer);
15214                ranges_for_buffer.push(range.clone());
15215
15216                while let Some(next_location) = locations.peek() {
15217                    if next_location.buffer == location.buffer {
15218                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15219                        locations.next();
15220                    } else {
15221                        break;
15222                    }
15223                }
15224
15225                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15226                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15227                    PathKey::for_buffer(&location.buffer, cx),
15228                    location.buffer.clone(),
15229                    ranges_for_buffer,
15230                    DEFAULT_MULTIBUFFER_CONTEXT,
15231                    cx,
15232                );
15233                ranges.extend(new_ranges)
15234            }
15235
15236            multibuffer.with_title(title)
15237        });
15238
15239        let editor = cx.new(|cx| {
15240            Editor::for_multibuffer(
15241                excerpt_buffer,
15242                Some(workspace.project().clone()),
15243                window,
15244                cx,
15245            )
15246        });
15247        editor.update(cx, |editor, cx| {
15248            match multibuffer_selection_mode {
15249                MultibufferSelectionMode::First => {
15250                    if let Some(first_range) = ranges.first() {
15251                        editor.change_selections(None, window, cx, |selections| {
15252                            selections.clear_disjoint();
15253                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15254                        });
15255                    }
15256                    editor.highlight_background::<Self>(
15257                        &ranges,
15258                        |theme| theme.editor_highlighted_line_background,
15259                        cx,
15260                    );
15261                }
15262                MultibufferSelectionMode::All => {
15263                    editor.change_selections(None, window, cx, |selections| {
15264                        selections.clear_disjoint();
15265                        selections.select_anchor_ranges(ranges);
15266                    });
15267                }
15268            }
15269            editor.register_buffers_with_language_servers(cx);
15270        });
15271
15272        let item = Box::new(editor);
15273        let item_id = item.item_id();
15274
15275        if split {
15276            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15277        } else {
15278            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15279                let (preview_item_id, preview_item_idx) =
15280                    workspace.active_pane().read_with(cx, |pane, _| {
15281                        (pane.preview_item_id(), pane.preview_item_idx())
15282                    });
15283
15284                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15285
15286                if let Some(preview_item_id) = preview_item_id {
15287                    workspace.active_pane().update(cx, |pane, cx| {
15288                        pane.remove_item(preview_item_id, false, false, window, cx);
15289                    });
15290                }
15291            } else {
15292                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15293            }
15294        }
15295        workspace.active_pane().update(cx, |pane, cx| {
15296            pane.set_preview_item_id(Some(item_id), cx);
15297        });
15298    }
15299
15300    pub fn rename(
15301        &mut self,
15302        _: &Rename,
15303        window: &mut Window,
15304        cx: &mut Context<Self>,
15305    ) -> Option<Task<Result<()>>> {
15306        use language::ToOffset as _;
15307
15308        let provider = self.semantics_provider.clone()?;
15309        let selection = self.selections.newest_anchor().clone();
15310        let (cursor_buffer, cursor_buffer_position) = self
15311            .buffer
15312            .read(cx)
15313            .text_anchor_for_position(selection.head(), cx)?;
15314        let (tail_buffer, cursor_buffer_position_end) = self
15315            .buffer
15316            .read(cx)
15317            .text_anchor_for_position(selection.tail(), cx)?;
15318        if tail_buffer != cursor_buffer {
15319            return None;
15320        }
15321
15322        let snapshot = cursor_buffer.read(cx).snapshot();
15323        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15324        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15325        let prepare_rename = provider
15326            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15327            .unwrap_or_else(|| Task::ready(Ok(None)));
15328        drop(snapshot);
15329
15330        Some(cx.spawn_in(window, async move |this, cx| {
15331            let rename_range = if let Some(range) = prepare_rename.await? {
15332                Some(range)
15333            } else {
15334                this.update(cx, |this, cx| {
15335                    let buffer = this.buffer.read(cx).snapshot(cx);
15336                    let mut buffer_highlights = this
15337                        .document_highlights_for_position(selection.head(), &buffer)
15338                        .filter(|highlight| {
15339                            highlight.start.excerpt_id == selection.head().excerpt_id
15340                                && highlight.end.excerpt_id == selection.head().excerpt_id
15341                        });
15342                    buffer_highlights
15343                        .next()
15344                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15345                })?
15346            };
15347            if let Some(rename_range) = rename_range {
15348                this.update_in(cx, |this, window, cx| {
15349                    let snapshot = cursor_buffer.read(cx).snapshot();
15350                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15351                    let cursor_offset_in_rename_range =
15352                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15353                    let cursor_offset_in_rename_range_end =
15354                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15355
15356                    this.take_rename(false, window, cx);
15357                    let buffer = this.buffer.read(cx).read(cx);
15358                    let cursor_offset = selection.head().to_offset(&buffer);
15359                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15360                    let rename_end = rename_start + rename_buffer_range.len();
15361                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15362                    let mut old_highlight_id = None;
15363                    let old_name: Arc<str> = buffer
15364                        .chunks(rename_start..rename_end, true)
15365                        .map(|chunk| {
15366                            if old_highlight_id.is_none() {
15367                                old_highlight_id = chunk.syntax_highlight_id;
15368                            }
15369                            chunk.text
15370                        })
15371                        .collect::<String>()
15372                        .into();
15373
15374                    drop(buffer);
15375
15376                    // Position the selection in the rename editor so that it matches the current selection.
15377                    this.show_local_selections = false;
15378                    let rename_editor = cx.new(|cx| {
15379                        let mut editor = Editor::single_line(window, cx);
15380                        editor.buffer.update(cx, |buffer, cx| {
15381                            buffer.edit([(0..0, old_name.clone())], None, cx)
15382                        });
15383                        let rename_selection_range = match cursor_offset_in_rename_range
15384                            .cmp(&cursor_offset_in_rename_range_end)
15385                        {
15386                            Ordering::Equal => {
15387                                editor.select_all(&SelectAll, window, cx);
15388                                return editor;
15389                            }
15390                            Ordering::Less => {
15391                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15392                            }
15393                            Ordering::Greater => {
15394                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15395                            }
15396                        };
15397                        if rename_selection_range.end > old_name.len() {
15398                            editor.select_all(&SelectAll, window, cx);
15399                        } else {
15400                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15401                                s.select_ranges([rename_selection_range]);
15402                            });
15403                        }
15404                        editor
15405                    });
15406                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15407                        if e == &EditorEvent::Focused {
15408                            cx.emit(EditorEvent::FocusedIn)
15409                        }
15410                    })
15411                    .detach();
15412
15413                    let write_highlights =
15414                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15415                    let read_highlights =
15416                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15417                    let ranges = write_highlights
15418                        .iter()
15419                        .flat_map(|(_, ranges)| ranges.iter())
15420                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15421                        .cloned()
15422                        .collect();
15423
15424                    this.highlight_text::<Rename>(
15425                        ranges,
15426                        HighlightStyle {
15427                            fade_out: Some(0.6),
15428                            ..Default::default()
15429                        },
15430                        cx,
15431                    );
15432                    let rename_focus_handle = rename_editor.focus_handle(cx);
15433                    window.focus(&rename_focus_handle);
15434                    let block_id = this.insert_blocks(
15435                        [BlockProperties {
15436                            style: BlockStyle::Flex,
15437                            placement: BlockPlacement::Below(range.start),
15438                            height: Some(1),
15439                            render: Arc::new({
15440                                let rename_editor = rename_editor.clone();
15441                                move |cx: &mut BlockContext| {
15442                                    let mut text_style = cx.editor_style.text.clone();
15443                                    if let Some(highlight_style) = old_highlight_id
15444                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15445                                    {
15446                                        text_style = text_style.highlight(highlight_style);
15447                                    }
15448                                    div()
15449                                        .block_mouse_except_scroll()
15450                                        .pl(cx.anchor_x)
15451                                        .child(EditorElement::new(
15452                                            &rename_editor,
15453                                            EditorStyle {
15454                                                background: cx.theme().system().transparent,
15455                                                local_player: cx.editor_style.local_player,
15456                                                text: text_style,
15457                                                scrollbar_width: cx.editor_style.scrollbar_width,
15458                                                syntax: cx.editor_style.syntax.clone(),
15459                                                status: cx.editor_style.status.clone(),
15460                                                inlay_hints_style: HighlightStyle {
15461                                                    font_weight: Some(FontWeight::BOLD),
15462                                                    ..make_inlay_hints_style(cx.app)
15463                                                },
15464                                                inline_completion_styles: make_suggestion_styles(
15465                                                    cx.app,
15466                                                ),
15467                                                ..EditorStyle::default()
15468                                            },
15469                                        ))
15470                                        .into_any_element()
15471                                }
15472                            }),
15473                            priority: 0,
15474                            render_in_minimap: true,
15475                        }],
15476                        Some(Autoscroll::fit()),
15477                        cx,
15478                    )[0];
15479                    this.pending_rename = Some(RenameState {
15480                        range,
15481                        old_name,
15482                        editor: rename_editor,
15483                        block_id,
15484                    });
15485                })?;
15486            }
15487
15488            Ok(())
15489        }))
15490    }
15491
15492    pub fn confirm_rename(
15493        &mut self,
15494        _: &ConfirmRename,
15495        window: &mut Window,
15496        cx: &mut Context<Self>,
15497    ) -> Option<Task<Result<()>>> {
15498        let rename = self.take_rename(false, window, cx)?;
15499        let workspace = self.workspace()?.downgrade();
15500        let (buffer, start) = self
15501            .buffer
15502            .read(cx)
15503            .text_anchor_for_position(rename.range.start, cx)?;
15504        let (end_buffer, _) = self
15505            .buffer
15506            .read(cx)
15507            .text_anchor_for_position(rename.range.end, cx)?;
15508        if buffer != end_buffer {
15509            return None;
15510        }
15511
15512        let old_name = rename.old_name;
15513        let new_name = rename.editor.read(cx).text(cx);
15514
15515        let rename = self.semantics_provider.as_ref()?.perform_rename(
15516            &buffer,
15517            start,
15518            new_name.clone(),
15519            cx,
15520        )?;
15521
15522        Some(cx.spawn_in(window, async move |editor, cx| {
15523            let project_transaction = rename.await?;
15524            Self::open_project_transaction(
15525                &editor,
15526                workspace,
15527                project_transaction,
15528                format!("Rename: {}{}", old_name, new_name),
15529                cx,
15530            )
15531            .await?;
15532
15533            editor.update(cx, |editor, cx| {
15534                editor.refresh_document_highlights(cx);
15535            })?;
15536            Ok(())
15537        }))
15538    }
15539
15540    fn take_rename(
15541        &mut self,
15542        moving_cursor: bool,
15543        window: &mut Window,
15544        cx: &mut Context<Self>,
15545    ) -> Option<RenameState> {
15546        let rename = self.pending_rename.take()?;
15547        if rename.editor.focus_handle(cx).is_focused(window) {
15548            window.focus(&self.focus_handle);
15549        }
15550
15551        self.remove_blocks(
15552            [rename.block_id].into_iter().collect(),
15553            Some(Autoscroll::fit()),
15554            cx,
15555        );
15556        self.clear_highlights::<Rename>(cx);
15557        self.show_local_selections = true;
15558
15559        if moving_cursor {
15560            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15561                editor.selections.newest::<usize>(cx).head()
15562            });
15563
15564            // Update the selection to match the position of the selection inside
15565            // the rename editor.
15566            let snapshot = self.buffer.read(cx).read(cx);
15567            let rename_range = rename.range.to_offset(&snapshot);
15568            let cursor_in_editor = snapshot
15569                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15570                .min(rename_range.end);
15571            drop(snapshot);
15572
15573            self.change_selections(None, window, cx, |s| {
15574                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15575            });
15576        } else {
15577            self.refresh_document_highlights(cx);
15578        }
15579
15580        Some(rename)
15581    }
15582
15583    pub fn pending_rename(&self) -> Option<&RenameState> {
15584        self.pending_rename.as_ref()
15585    }
15586
15587    fn format(
15588        &mut self,
15589        _: &Format,
15590        window: &mut Window,
15591        cx: &mut Context<Self>,
15592    ) -> Option<Task<Result<()>>> {
15593        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15594
15595        let project = match &self.project {
15596            Some(project) => project.clone(),
15597            None => return None,
15598        };
15599
15600        Some(self.perform_format(
15601            project,
15602            FormatTrigger::Manual,
15603            FormatTarget::Buffers,
15604            window,
15605            cx,
15606        ))
15607    }
15608
15609    fn format_selections(
15610        &mut self,
15611        _: &FormatSelections,
15612        window: &mut Window,
15613        cx: &mut Context<Self>,
15614    ) -> Option<Task<Result<()>>> {
15615        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15616
15617        let project = match &self.project {
15618            Some(project) => project.clone(),
15619            None => return None,
15620        };
15621
15622        let ranges = self
15623            .selections
15624            .all_adjusted(cx)
15625            .into_iter()
15626            .map(|selection| selection.range())
15627            .collect_vec();
15628
15629        Some(self.perform_format(
15630            project,
15631            FormatTrigger::Manual,
15632            FormatTarget::Ranges(ranges),
15633            window,
15634            cx,
15635        ))
15636    }
15637
15638    fn perform_format(
15639        &mut self,
15640        project: Entity<Project>,
15641        trigger: FormatTrigger,
15642        target: FormatTarget,
15643        window: &mut Window,
15644        cx: &mut Context<Self>,
15645    ) -> Task<Result<()>> {
15646        let buffer = self.buffer.clone();
15647        let (buffers, target) = match target {
15648            FormatTarget::Buffers => {
15649                let mut buffers = buffer.read(cx).all_buffers();
15650                if trigger == FormatTrigger::Save {
15651                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15652                }
15653                (buffers, LspFormatTarget::Buffers)
15654            }
15655            FormatTarget::Ranges(selection_ranges) => {
15656                let multi_buffer = buffer.read(cx);
15657                let snapshot = multi_buffer.read(cx);
15658                let mut buffers = HashSet::default();
15659                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15660                    BTreeMap::new();
15661                for selection_range in selection_ranges {
15662                    for (buffer, buffer_range, _) in
15663                        snapshot.range_to_buffer_ranges(selection_range)
15664                    {
15665                        let buffer_id = buffer.remote_id();
15666                        let start = buffer.anchor_before(buffer_range.start);
15667                        let end = buffer.anchor_after(buffer_range.end);
15668                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15669                        buffer_id_to_ranges
15670                            .entry(buffer_id)
15671                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15672                            .or_insert_with(|| vec![start..end]);
15673                    }
15674                }
15675                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15676            }
15677        };
15678
15679        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15680        let selections_prev = transaction_id_prev
15681            .and_then(|transaction_id_prev| {
15682                // default to selections as they were after the last edit, if we have them,
15683                // instead of how they are now.
15684                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15685                // will take you back to where you made the last edit, instead of staying where you scrolled
15686                self.selection_history
15687                    .transaction(transaction_id_prev)
15688                    .map(|t| t.0.clone())
15689            })
15690            .unwrap_or_else(|| {
15691                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15692                self.selections.disjoint_anchors()
15693            });
15694
15695        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15696        let format = project.update(cx, |project, cx| {
15697            project.format(buffers, target, true, trigger, cx)
15698        });
15699
15700        cx.spawn_in(window, async move |editor, cx| {
15701            let transaction = futures::select_biased! {
15702                transaction = format.log_err().fuse() => transaction,
15703                () = timeout => {
15704                    log::warn!("timed out waiting for formatting");
15705                    None
15706                }
15707            };
15708
15709            buffer
15710                .update(cx, |buffer, cx| {
15711                    if let Some(transaction) = transaction {
15712                        if !buffer.is_singleton() {
15713                            buffer.push_transaction(&transaction.0, cx);
15714                        }
15715                    }
15716                    cx.notify();
15717                })
15718                .ok();
15719
15720            if let Some(transaction_id_now) =
15721                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15722            {
15723                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15724                if has_new_transaction {
15725                    _ = editor.update(cx, |editor, _| {
15726                        editor
15727                            .selection_history
15728                            .insert_transaction(transaction_id_now, selections_prev);
15729                    });
15730                }
15731            }
15732
15733            Ok(())
15734        })
15735    }
15736
15737    fn organize_imports(
15738        &mut self,
15739        _: &OrganizeImports,
15740        window: &mut Window,
15741        cx: &mut Context<Self>,
15742    ) -> Option<Task<Result<()>>> {
15743        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15744        let project = match &self.project {
15745            Some(project) => project.clone(),
15746            None => return None,
15747        };
15748        Some(self.perform_code_action_kind(
15749            project,
15750            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15751            window,
15752            cx,
15753        ))
15754    }
15755
15756    fn perform_code_action_kind(
15757        &mut self,
15758        project: Entity<Project>,
15759        kind: CodeActionKind,
15760        window: &mut Window,
15761        cx: &mut Context<Self>,
15762    ) -> Task<Result<()>> {
15763        let buffer = self.buffer.clone();
15764        let buffers = buffer.read(cx).all_buffers();
15765        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15766        let apply_action = project.update(cx, |project, cx| {
15767            project.apply_code_action_kind(buffers, kind, true, cx)
15768        });
15769        cx.spawn_in(window, async move |_, cx| {
15770            let transaction = futures::select_biased! {
15771                () = timeout => {
15772                    log::warn!("timed out waiting for executing code action");
15773                    None
15774                }
15775                transaction = apply_action.log_err().fuse() => transaction,
15776            };
15777            buffer
15778                .update(cx, |buffer, cx| {
15779                    // check if we need this
15780                    if let Some(transaction) = transaction {
15781                        if !buffer.is_singleton() {
15782                            buffer.push_transaction(&transaction.0, cx);
15783                        }
15784                    }
15785                    cx.notify();
15786                })
15787                .ok();
15788            Ok(())
15789        })
15790    }
15791
15792    fn restart_language_server(
15793        &mut self,
15794        _: &RestartLanguageServer,
15795        _: &mut Window,
15796        cx: &mut Context<Self>,
15797    ) {
15798        if let Some(project) = self.project.clone() {
15799            self.buffer.update(cx, |multi_buffer, cx| {
15800                project.update(cx, |project, cx| {
15801                    project.restart_language_servers_for_buffers(
15802                        multi_buffer.all_buffers().into_iter().collect(),
15803                        cx,
15804                    );
15805                });
15806            })
15807        }
15808    }
15809
15810    fn stop_language_server(
15811        &mut self,
15812        _: &StopLanguageServer,
15813        _: &mut Window,
15814        cx: &mut Context<Self>,
15815    ) {
15816        if let Some(project) = self.project.clone() {
15817            self.buffer.update(cx, |multi_buffer, cx| {
15818                project.update(cx, |project, cx| {
15819                    project.stop_language_servers_for_buffers(
15820                        multi_buffer.all_buffers().into_iter().collect(),
15821                        cx,
15822                    );
15823                    cx.emit(project::Event::RefreshInlayHints);
15824                });
15825            });
15826        }
15827    }
15828
15829    fn cancel_language_server_work(
15830        workspace: &mut Workspace,
15831        _: &actions::CancelLanguageServerWork,
15832        _: &mut Window,
15833        cx: &mut Context<Workspace>,
15834    ) {
15835        let project = workspace.project();
15836        let buffers = workspace
15837            .active_item(cx)
15838            .and_then(|item| item.act_as::<Editor>(cx))
15839            .map_or(HashSet::default(), |editor| {
15840                editor.read(cx).buffer.read(cx).all_buffers()
15841            });
15842        project.update(cx, |project, cx| {
15843            project.cancel_language_server_work_for_buffers(buffers, cx);
15844        });
15845    }
15846
15847    fn show_character_palette(
15848        &mut self,
15849        _: &ShowCharacterPalette,
15850        window: &mut Window,
15851        _: &mut Context<Self>,
15852    ) {
15853        window.show_character_palette();
15854    }
15855
15856    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15857        if self.mode.is_minimap() {
15858            return;
15859        }
15860
15861        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15862            let buffer = self.buffer.read(cx).snapshot(cx);
15863            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15864            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15865            let is_valid = buffer
15866                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15867                .any(|entry| {
15868                    entry.diagnostic.is_primary
15869                        && !entry.range.is_empty()
15870                        && entry.range.start == primary_range_start
15871                        && entry.diagnostic.message == active_diagnostics.active_message
15872                });
15873
15874            if !is_valid {
15875                self.dismiss_diagnostics(cx);
15876            }
15877        }
15878    }
15879
15880    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15881        match &self.active_diagnostics {
15882            ActiveDiagnostic::Group(group) => Some(group),
15883            _ => None,
15884        }
15885    }
15886
15887    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15888        self.dismiss_diagnostics(cx);
15889        self.active_diagnostics = ActiveDiagnostic::All;
15890    }
15891
15892    fn activate_diagnostics(
15893        &mut self,
15894        buffer_id: BufferId,
15895        diagnostic: DiagnosticEntry<usize>,
15896        window: &mut Window,
15897        cx: &mut Context<Self>,
15898    ) {
15899        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15900            return;
15901        }
15902        self.dismiss_diagnostics(cx);
15903        let snapshot = self.snapshot(window, cx);
15904        let buffer = self.buffer.read(cx).snapshot(cx);
15905        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15906            return;
15907        };
15908
15909        let diagnostic_group = buffer
15910            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15911            .collect::<Vec<_>>();
15912
15913        let blocks =
15914            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15915
15916        let blocks = self.display_map.update(cx, |display_map, cx| {
15917            display_map.insert_blocks(blocks, cx).into_iter().collect()
15918        });
15919        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15920            active_range: buffer.anchor_before(diagnostic.range.start)
15921                ..buffer.anchor_after(diagnostic.range.end),
15922            active_message: diagnostic.diagnostic.message.clone(),
15923            group_id: diagnostic.diagnostic.group_id,
15924            blocks,
15925        });
15926        cx.notify();
15927    }
15928
15929    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15930        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15931            return;
15932        };
15933
15934        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15935        if let ActiveDiagnostic::Group(group) = prev {
15936            self.display_map.update(cx, |display_map, cx| {
15937                display_map.remove_blocks(group.blocks, cx);
15938            });
15939            cx.notify();
15940        }
15941    }
15942
15943    /// Disable inline diagnostics rendering for this editor.
15944    pub fn disable_inline_diagnostics(&mut self) {
15945        self.inline_diagnostics_enabled = false;
15946        self.inline_diagnostics_update = Task::ready(());
15947        self.inline_diagnostics.clear();
15948    }
15949
15950    pub fn diagnostics_enabled(&self) -> bool {
15951        self.mode.is_full()
15952    }
15953
15954    pub fn inline_diagnostics_enabled(&self) -> bool {
15955        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15956    }
15957
15958    pub fn show_inline_diagnostics(&self) -> bool {
15959        self.show_inline_diagnostics
15960    }
15961
15962    pub fn toggle_inline_diagnostics(
15963        &mut self,
15964        _: &ToggleInlineDiagnostics,
15965        window: &mut Window,
15966        cx: &mut Context<Editor>,
15967    ) {
15968        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15969        self.refresh_inline_diagnostics(false, window, cx);
15970    }
15971
15972    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15973        self.diagnostics_max_severity = severity;
15974        self.display_map.update(cx, |display_map, _| {
15975            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15976        });
15977    }
15978
15979    pub fn toggle_diagnostics(
15980        &mut self,
15981        _: &ToggleDiagnostics,
15982        window: &mut Window,
15983        cx: &mut Context<Editor>,
15984    ) {
15985        if !self.diagnostics_enabled() {
15986            return;
15987        }
15988
15989        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15990            EditorSettings::get_global(cx)
15991                .diagnostics_max_severity
15992                .filter(|severity| severity != &DiagnosticSeverity::Off)
15993                .unwrap_or(DiagnosticSeverity::Hint)
15994        } else {
15995            DiagnosticSeverity::Off
15996        };
15997        self.set_max_diagnostics_severity(new_severity, cx);
15998        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15999            self.active_diagnostics = ActiveDiagnostic::None;
16000            self.inline_diagnostics_update = Task::ready(());
16001            self.inline_diagnostics.clear();
16002        } else {
16003            self.refresh_inline_diagnostics(false, window, cx);
16004        }
16005
16006        cx.notify();
16007    }
16008
16009    pub fn toggle_minimap(
16010        &mut self,
16011        _: &ToggleMinimap,
16012        window: &mut Window,
16013        cx: &mut Context<Editor>,
16014    ) {
16015        if self.supports_minimap(cx) {
16016            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16017        }
16018    }
16019
16020    fn refresh_inline_diagnostics(
16021        &mut self,
16022        debounce: bool,
16023        window: &mut Window,
16024        cx: &mut Context<Self>,
16025    ) {
16026        let max_severity = ProjectSettings::get_global(cx)
16027            .diagnostics
16028            .inline
16029            .max_severity
16030            .unwrap_or(self.diagnostics_max_severity);
16031
16032        if !self.inline_diagnostics_enabled()
16033            || !self.show_inline_diagnostics
16034            || max_severity == DiagnosticSeverity::Off
16035        {
16036            self.inline_diagnostics_update = Task::ready(());
16037            self.inline_diagnostics.clear();
16038            return;
16039        }
16040
16041        let debounce_ms = ProjectSettings::get_global(cx)
16042            .diagnostics
16043            .inline
16044            .update_debounce_ms;
16045        let debounce = if debounce && debounce_ms > 0 {
16046            Some(Duration::from_millis(debounce_ms))
16047        } else {
16048            None
16049        };
16050        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16051            if let Some(debounce) = debounce {
16052                cx.background_executor().timer(debounce).await;
16053            }
16054            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16055                editor
16056                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16057                    .ok()
16058            }) else {
16059                return;
16060            };
16061
16062            let new_inline_diagnostics = cx
16063                .background_spawn(async move {
16064                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16065                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16066                        let message = diagnostic_entry
16067                            .diagnostic
16068                            .message
16069                            .split_once('\n')
16070                            .map(|(line, _)| line)
16071                            .map(SharedString::new)
16072                            .unwrap_or_else(|| {
16073                                SharedString::from(diagnostic_entry.diagnostic.message)
16074                            });
16075                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16076                        let (Ok(i) | Err(i)) = inline_diagnostics
16077                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16078                        inline_diagnostics.insert(
16079                            i,
16080                            (
16081                                start_anchor,
16082                                InlineDiagnostic {
16083                                    message,
16084                                    group_id: diagnostic_entry.diagnostic.group_id,
16085                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16086                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16087                                    severity: diagnostic_entry.diagnostic.severity,
16088                                },
16089                            ),
16090                        );
16091                    }
16092                    inline_diagnostics
16093                })
16094                .await;
16095
16096            editor
16097                .update(cx, |editor, cx| {
16098                    editor.inline_diagnostics = new_inline_diagnostics;
16099                    cx.notify();
16100                })
16101                .ok();
16102        });
16103    }
16104
16105    fn pull_diagnostics(
16106        &mut self,
16107        buffer_id: Option<BufferId>,
16108        window: &Window,
16109        cx: &mut Context<Self>,
16110    ) -> Option<()> {
16111        if !self.mode().is_full() {
16112            return None;
16113        }
16114        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16115            .diagnostics
16116            .lsp_pull_diagnostics;
16117        if !pull_diagnostics_settings.enabled {
16118            return None;
16119        }
16120        let project = self.project.as_ref()?.downgrade();
16121        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16122        let mut buffers = self.buffer.read(cx).all_buffers();
16123        if let Some(buffer_id) = buffer_id {
16124            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16125        }
16126
16127        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16128            cx.background_executor().timer(debounce).await;
16129
16130            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16131                buffers
16132                    .into_iter()
16133                    .flat_map(|buffer| {
16134                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16135                    })
16136                    .collect::<FuturesUnordered<_>>()
16137            }) else {
16138                return;
16139            };
16140
16141            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16142                match pull_task {
16143                    Ok(()) => {
16144                        if editor
16145                            .update_in(cx, |editor, window, cx| {
16146                                editor.update_diagnostics_state(window, cx);
16147                            })
16148                            .is_err()
16149                        {
16150                            return;
16151                        }
16152                    }
16153                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16154                }
16155            }
16156        });
16157
16158        Some(())
16159    }
16160
16161    pub fn set_selections_from_remote(
16162        &mut self,
16163        selections: Vec<Selection<Anchor>>,
16164        pending_selection: Option<Selection<Anchor>>,
16165        window: &mut Window,
16166        cx: &mut Context<Self>,
16167    ) {
16168        let old_cursor_position = self.selections.newest_anchor().head();
16169        self.selections.change_with(cx, |s| {
16170            s.select_anchors(selections);
16171            if let Some(pending_selection) = pending_selection {
16172                s.set_pending(pending_selection, SelectMode::Character);
16173            } else {
16174                s.clear_pending();
16175            }
16176        });
16177        self.selections_did_change(false, &old_cursor_position, true, window, cx);
16178    }
16179
16180    pub fn transact(
16181        &mut self,
16182        window: &mut Window,
16183        cx: &mut Context<Self>,
16184        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16185    ) -> Option<TransactionId> {
16186        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16187            this.start_transaction_at(Instant::now(), window, cx);
16188            update(this, window, cx);
16189            this.end_transaction_at(Instant::now(), cx)
16190        })
16191    }
16192
16193    pub fn start_transaction_at(
16194        &mut self,
16195        now: Instant,
16196        window: &mut Window,
16197        cx: &mut Context<Self>,
16198    ) {
16199        self.end_selection(window, cx);
16200        if let Some(tx_id) = self
16201            .buffer
16202            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16203        {
16204            self.selection_history
16205                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16206            cx.emit(EditorEvent::TransactionBegun {
16207                transaction_id: tx_id,
16208            })
16209        }
16210    }
16211
16212    pub fn end_transaction_at(
16213        &mut self,
16214        now: Instant,
16215        cx: &mut Context<Self>,
16216    ) -> Option<TransactionId> {
16217        if let Some(transaction_id) = self
16218            .buffer
16219            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16220        {
16221            if let Some((_, end_selections)) =
16222                self.selection_history.transaction_mut(transaction_id)
16223            {
16224                *end_selections = Some(self.selections.disjoint_anchors());
16225            } else {
16226                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16227            }
16228
16229            cx.emit(EditorEvent::Edited { transaction_id });
16230            Some(transaction_id)
16231        } else {
16232            None
16233        }
16234    }
16235
16236    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16237        if self.selection_mark_mode {
16238            self.change_selections(None, window, cx, |s| {
16239                s.move_with(|_, sel| {
16240                    sel.collapse_to(sel.head(), SelectionGoal::None);
16241                });
16242            })
16243        }
16244        self.selection_mark_mode = true;
16245        cx.notify();
16246    }
16247
16248    pub fn swap_selection_ends(
16249        &mut self,
16250        _: &actions::SwapSelectionEnds,
16251        window: &mut Window,
16252        cx: &mut Context<Self>,
16253    ) {
16254        self.change_selections(None, window, cx, |s| {
16255            s.move_with(|_, sel| {
16256                if sel.start != sel.end {
16257                    sel.reversed = !sel.reversed
16258                }
16259            });
16260        });
16261        self.request_autoscroll(Autoscroll::newest(), cx);
16262        cx.notify();
16263    }
16264
16265    pub fn toggle_fold(
16266        &mut self,
16267        _: &actions::ToggleFold,
16268        window: &mut Window,
16269        cx: &mut Context<Self>,
16270    ) {
16271        if self.is_singleton(cx) {
16272            let selection = self.selections.newest::<Point>(cx);
16273
16274            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16275            let range = if selection.is_empty() {
16276                let point = selection.head().to_display_point(&display_map);
16277                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16278                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16279                    .to_point(&display_map);
16280                start..end
16281            } else {
16282                selection.range()
16283            };
16284            if display_map.folds_in_range(range).next().is_some() {
16285                self.unfold_lines(&Default::default(), window, cx)
16286            } else {
16287                self.fold(&Default::default(), window, cx)
16288            }
16289        } else {
16290            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16291            let buffer_ids: HashSet<_> = self
16292                .selections
16293                .disjoint_anchor_ranges()
16294                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16295                .collect();
16296
16297            let should_unfold = buffer_ids
16298                .iter()
16299                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16300
16301            for buffer_id in buffer_ids {
16302                if should_unfold {
16303                    self.unfold_buffer(buffer_id, cx);
16304                } else {
16305                    self.fold_buffer(buffer_id, cx);
16306                }
16307            }
16308        }
16309    }
16310
16311    pub fn toggle_fold_recursive(
16312        &mut self,
16313        _: &actions::ToggleFoldRecursive,
16314        window: &mut Window,
16315        cx: &mut Context<Self>,
16316    ) {
16317        let selection = self.selections.newest::<Point>(cx);
16318
16319        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16320        let range = if selection.is_empty() {
16321            let point = selection.head().to_display_point(&display_map);
16322            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16323            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16324                .to_point(&display_map);
16325            start..end
16326        } else {
16327            selection.range()
16328        };
16329        if display_map.folds_in_range(range).next().is_some() {
16330            self.unfold_recursive(&Default::default(), window, cx)
16331        } else {
16332            self.fold_recursive(&Default::default(), window, cx)
16333        }
16334    }
16335
16336    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16337        if self.is_singleton(cx) {
16338            let mut to_fold = Vec::new();
16339            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16340            let selections = self.selections.all_adjusted(cx);
16341
16342            for selection in selections {
16343                let range = selection.range().sorted();
16344                let buffer_start_row = range.start.row;
16345
16346                if range.start.row != range.end.row {
16347                    let mut found = false;
16348                    let mut row = range.start.row;
16349                    while row <= range.end.row {
16350                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16351                        {
16352                            found = true;
16353                            row = crease.range().end.row + 1;
16354                            to_fold.push(crease);
16355                        } else {
16356                            row += 1
16357                        }
16358                    }
16359                    if found {
16360                        continue;
16361                    }
16362                }
16363
16364                for row in (0..=range.start.row).rev() {
16365                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16366                        if crease.range().end.row >= buffer_start_row {
16367                            to_fold.push(crease);
16368                            if row <= range.start.row {
16369                                break;
16370                            }
16371                        }
16372                    }
16373                }
16374            }
16375
16376            self.fold_creases(to_fold, true, window, cx);
16377        } else {
16378            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16379            let buffer_ids = self
16380                .selections
16381                .disjoint_anchor_ranges()
16382                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16383                .collect::<HashSet<_>>();
16384            for buffer_id in buffer_ids {
16385                self.fold_buffer(buffer_id, cx);
16386            }
16387        }
16388    }
16389
16390    fn fold_at_level(
16391        &mut self,
16392        fold_at: &FoldAtLevel,
16393        window: &mut Window,
16394        cx: &mut Context<Self>,
16395    ) {
16396        if !self.buffer.read(cx).is_singleton() {
16397            return;
16398        }
16399
16400        let fold_at_level = fold_at.0;
16401        let snapshot = self.buffer.read(cx).snapshot(cx);
16402        let mut to_fold = Vec::new();
16403        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16404
16405        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16406            while start_row < end_row {
16407                match self
16408                    .snapshot(window, cx)
16409                    .crease_for_buffer_row(MultiBufferRow(start_row))
16410                {
16411                    Some(crease) => {
16412                        let nested_start_row = crease.range().start.row + 1;
16413                        let nested_end_row = crease.range().end.row;
16414
16415                        if current_level < fold_at_level {
16416                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16417                        } else if current_level == fold_at_level {
16418                            to_fold.push(crease);
16419                        }
16420
16421                        start_row = nested_end_row + 1;
16422                    }
16423                    None => start_row += 1,
16424                }
16425            }
16426        }
16427
16428        self.fold_creases(to_fold, true, window, cx);
16429    }
16430
16431    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16432        if self.buffer.read(cx).is_singleton() {
16433            let mut fold_ranges = Vec::new();
16434            let snapshot = self.buffer.read(cx).snapshot(cx);
16435
16436            for row in 0..snapshot.max_row().0 {
16437                if let Some(foldable_range) = self
16438                    .snapshot(window, cx)
16439                    .crease_for_buffer_row(MultiBufferRow(row))
16440                {
16441                    fold_ranges.push(foldable_range);
16442                }
16443            }
16444
16445            self.fold_creases(fold_ranges, true, window, cx);
16446        } else {
16447            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16448                editor
16449                    .update_in(cx, |editor, _, cx| {
16450                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16451                            editor.fold_buffer(buffer_id, cx);
16452                        }
16453                    })
16454                    .ok();
16455            });
16456        }
16457    }
16458
16459    pub fn fold_function_bodies(
16460        &mut self,
16461        _: &actions::FoldFunctionBodies,
16462        window: &mut Window,
16463        cx: &mut Context<Self>,
16464    ) {
16465        let snapshot = self.buffer.read(cx).snapshot(cx);
16466
16467        let ranges = snapshot
16468            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16469            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16470            .collect::<Vec<_>>();
16471
16472        let creases = ranges
16473            .into_iter()
16474            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16475            .collect();
16476
16477        self.fold_creases(creases, true, window, cx);
16478    }
16479
16480    pub fn fold_recursive(
16481        &mut self,
16482        _: &actions::FoldRecursive,
16483        window: &mut Window,
16484        cx: &mut Context<Self>,
16485    ) {
16486        let mut to_fold = Vec::new();
16487        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16488        let selections = self.selections.all_adjusted(cx);
16489
16490        for selection in selections {
16491            let range = selection.range().sorted();
16492            let buffer_start_row = range.start.row;
16493
16494            if range.start.row != range.end.row {
16495                let mut found = false;
16496                for row in range.start.row..=range.end.row {
16497                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16498                        found = true;
16499                        to_fold.push(crease);
16500                    }
16501                }
16502                if found {
16503                    continue;
16504                }
16505            }
16506
16507            for row in (0..=range.start.row).rev() {
16508                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16509                    if crease.range().end.row >= buffer_start_row {
16510                        to_fold.push(crease);
16511                    } else {
16512                        break;
16513                    }
16514                }
16515            }
16516        }
16517
16518        self.fold_creases(to_fold, true, window, cx);
16519    }
16520
16521    pub fn fold_at(
16522        &mut self,
16523        buffer_row: MultiBufferRow,
16524        window: &mut Window,
16525        cx: &mut Context<Self>,
16526    ) {
16527        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16528
16529        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16530            let autoscroll = self
16531                .selections
16532                .all::<Point>(cx)
16533                .iter()
16534                .any(|selection| crease.range().overlaps(&selection.range()));
16535
16536            self.fold_creases(vec![crease], autoscroll, window, cx);
16537        }
16538    }
16539
16540    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16541        if self.is_singleton(cx) {
16542            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16543            let buffer = &display_map.buffer_snapshot;
16544            let selections = self.selections.all::<Point>(cx);
16545            let ranges = selections
16546                .iter()
16547                .map(|s| {
16548                    let range = s.display_range(&display_map).sorted();
16549                    let mut start = range.start.to_point(&display_map);
16550                    let mut end = range.end.to_point(&display_map);
16551                    start.column = 0;
16552                    end.column = buffer.line_len(MultiBufferRow(end.row));
16553                    start..end
16554                })
16555                .collect::<Vec<_>>();
16556
16557            self.unfold_ranges(&ranges, true, true, cx);
16558        } else {
16559            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16560            let buffer_ids = self
16561                .selections
16562                .disjoint_anchor_ranges()
16563                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16564                .collect::<HashSet<_>>();
16565            for buffer_id in buffer_ids {
16566                self.unfold_buffer(buffer_id, cx);
16567            }
16568        }
16569    }
16570
16571    pub fn unfold_recursive(
16572        &mut self,
16573        _: &UnfoldRecursive,
16574        _window: &mut Window,
16575        cx: &mut Context<Self>,
16576    ) {
16577        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16578        let selections = self.selections.all::<Point>(cx);
16579        let ranges = selections
16580            .iter()
16581            .map(|s| {
16582                let mut range = s.display_range(&display_map).sorted();
16583                *range.start.column_mut() = 0;
16584                *range.end.column_mut() = display_map.line_len(range.end.row());
16585                let start = range.start.to_point(&display_map);
16586                let end = range.end.to_point(&display_map);
16587                start..end
16588            })
16589            .collect::<Vec<_>>();
16590
16591        self.unfold_ranges(&ranges, true, true, cx);
16592    }
16593
16594    pub fn unfold_at(
16595        &mut self,
16596        buffer_row: MultiBufferRow,
16597        _window: &mut Window,
16598        cx: &mut Context<Self>,
16599    ) {
16600        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16601
16602        let intersection_range = Point::new(buffer_row.0, 0)
16603            ..Point::new(
16604                buffer_row.0,
16605                display_map.buffer_snapshot.line_len(buffer_row),
16606            );
16607
16608        let autoscroll = self
16609            .selections
16610            .all::<Point>(cx)
16611            .iter()
16612            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16613
16614        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16615    }
16616
16617    pub fn unfold_all(
16618        &mut self,
16619        _: &actions::UnfoldAll,
16620        _window: &mut Window,
16621        cx: &mut Context<Self>,
16622    ) {
16623        if self.buffer.read(cx).is_singleton() {
16624            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16625            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16626        } else {
16627            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16628                editor
16629                    .update(cx, |editor, cx| {
16630                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16631                            editor.unfold_buffer(buffer_id, cx);
16632                        }
16633                    })
16634                    .ok();
16635            });
16636        }
16637    }
16638
16639    pub fn fold_selected_ranges(
16640        &mut self,
16641        _: &FoldSelectedRanges,
16642        window: &mut Window,
16643        cx: &mut Context<Self>,
16644    ) {
16645        let selections = self.selections.all_adjusted(cx);
16646        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16647        let ranges = selections
16648            .into_iter()
16649            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16650            .collect::<Vec<_>>();
16651        self.fold_creases(ranges, true, window, cx);
16652    }
16653
16654    pub fn fold_ranges<T: ToOffset + Clone>(
16655        &mut self,
16656        ranges: Vec<Range<T>>,
16657        auto_scroll: bool,
16658        window: &mut Window,
16659        cx: &mut Context<Self>,
16660    ) {
16661        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16662        let ranges = ranges
16663            .into_iter()
16664            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16665            .collect::<Vec<_>>();
16666        self.fold_creases(ranges, auto_scroll, window, cx);
16667    }
16668
16669    pub fn fold_creases<T: ToOffset + Clone>(
16670        &mut self,
16671        creases: Vec<Crease<T>>,
16672        auto_scroll: bool,
16673        _window: &mut Window,
16674        cx: &mut Context<Self>,
16675    ) {
16676        if creases.is_empty() {
16677            return;
16678        }
16679
16680        let mut buffers_affected = HashSet::default();
16681        let multi_buffer = self.buffer().read(cx);
16682        for crease in &creases {
16683            if let Some((_, buffer, _)) =
16684                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16685            {
16686                buffers_affected.insert(buffer.read(cx).remote_id());
16687            };
16688        }
16689
16690        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16691
16692        if auto_scroll {
16693            self.request_autoscroll(Autoscroll::fit(), cx);
16694        }
16695
16696        cx.notify();
16697
16698        self.scrollbar_marker_state.dirty = true;
16699        self.folds_did_change(cx);
16700    }
16701
16702    /// Removes any folds whose ranges intersect any of the given ranges.
16703    pub fn unfold_ranges<T: ToOffset + Clone>(
16704        &mut self,
16705        ranges: &[Range<T>],
16706        inclusive: bool,
16707        auto_scroll: bool,
16708        cx: &mut Context<Self>,
16709    ) {
16710        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16711            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16712        });
16713        self.folds_did_change(cx);
16714    }
16715
16716    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16717        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16718            return;
16719        }
16720        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16721        self.display_map.update(cx, |display_map, cx| {
16722            display_map.fold_buffers([buffer_id], cx)
16723        });
16724        cx.emit(EditorEvent::BufferFoldToggled {
16725            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16726            folded: true,
16727        });
16728        cx.notify();
16729    }
16730
16731    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16732        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16733            return;
16734        }
16735        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16736        self.display_map.update(cx, |display_map, cx| {
16737            display_map.unfold_buffers([buffer_id], cx);
16738        });
16739        cx.emit(EditorEvent::BufferFoldToggled {
16740            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16741            folded: false,
16742        });
16743        cx.notify();
16744    }
16745
16746    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16747        self.display_map.read(cx).is_buffer_folded(buffer)
16748    }
16749
16750    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16751        self.display_map.read(cx).folded_buffers()
16752    }
16753
16754    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16755        self.display_map.update(cx, |display_map, cx| {
16756            display_map.disable_header_for_buffer(buffer_id, cx);
16757        });
16758        cx.notify();
16759    }
16760
16761    /// Removes any folds with the given ranges.
16762    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16763        &mut self,
16764        ranges: &[Range<T>],
16765        type_id: TypeId,
16766        auto_scroll: bool,
16767        cx: &mut Context<Self>,
16768    ) {
16769        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16770            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16771        });
16772        self.folds_did_change(cx);
16773    }
16774
16775    fn remove_folds_with<T: ToOffset + Clone>(
16776        &mut self,
16777        ranges: &[Range<T>],
16778        auto_scroll: bool,
16779        cx: &mut Context<Self>,
16780        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16781    ) {
16782        if ranges.is_empty() {
16783            return;
16784        }
16785
16786        let mut buffers_affected = HashSet::default();
16787        let multi_buffer = self.buffer().read(cx);
16788        for range in ranges {
16789            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16790                buffers_affected.insert(buffer.read(cx).remote_id());
16791            };
16792        }
16793
16794        self.display_map.update(cx, update);
16795
16796        if auto_scroll {
16797            self.request_autoscroll(Autoscroll::fit(), cx);
16798        }
16799
16800        cx.notify();
16801        self.scrollbar_marker_state.dirty = true;
16802        self.active_indent_guides_state.dirty = true;
16803    }
16804
16805    pub fn update_fold_widths(
16806        &mut self,
16807        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16808        cx: &mut Context<Self>,
16809    ) -> bool {
16810        self.display_map
16811            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16812    }
16813
16814    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16815        self.display_map.read(cx).fold_placeholder.clone()
16816    }
16817
16818    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16819        self.buffer.update(cx, |buffer, cx| {
16820            buffer.set_all_diff_hunks_expanded(cx);
16821        });
16822    }
16823
16824    pub fn expand_all_diff_hunks(
16825        &mut self,
16826        _: &ExpandAllDiffHunks,
16827        _window: &mut Window,
16828        cx: &mut Context<Self>,
16829    ) {
16830        self.buffer.update(cx, |buffer, cx| {
16831            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16832        });
16833    }
16834
16835    pub fn toggle_selected_diff_hunks(
16836        &mut self,
16837        _: &ToggleSelectedDiffHunks,
16838        _window: &mut Window,
16839        cx: &mut Context<Self>,
16840    ) {
16841        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16842        self.toggle_diff_hunks_in_ranges(ranges, cx);
16843    }
16844
16845    pub fn diff_hunks_in_ranges<'a>(
16846        &'a self,
16847        ranges: &'a [Range<Anchor>],
16848        buffer: &'a MultiBufferSnapshot,
16849    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16850        ranges.iter().flat_map(move |range| {
16851            let end_excerpt_id = range.end.excerpt_id;
16852            let range = range.to_point(buffer);
16853            let mut peek_end = range.end;
16854            if range.end.row < buffer.max_row().0 {
16855                peek_end = Point::new(range.end.row + 1, 0);
16856            }
16857            buffer
16858                .diff_hunks_in_range(range.start..peek_end)
16859                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16860        })
16861    }
16862
16863    pub fn has_stageable_diff_hunks_in_ranges(
16864        &self,
16865        ranges: &[Range<Anchor>],
16866        snapshot: &MultiBufferSnapshot,
16867    ) -> bool {
16868        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16869        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16870    }
16871
16872    pub fn toggle_staged_selected_diff_hunks(
16873        &mut self,
16874        _: &::git::ToggleStaged,
16875        _: &mut Window,
16876        cx: &mut Context<Self>,
16877    ) {
16878        let snapshot = self.buffer.read(cx).snapshot(cx);
16879        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16880        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16881        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16882    }
16883
16884    pub fn set_render_diff_hunk_controls(
16885        &mut self,
16886        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16887        cx: &mut Context<Self>,
16888    ) {
16889        self.render_diff_hunk_controls = render_diff_hunk_controls;
16890        cx.notify();
16891    }
16892
16893    pub fn stage_and_next(
16894        &mut self,
16895        _: &::git::StageAndNext,
16896        window: &mut Window,
16897        cx: &mut Context<Self>,
16898    ) {
16899        self.do_stage_or_unstage_and_next(true, window, cx);
16900    }
16901
16902    pub fn unstage_and_next(
16903        &mut self,
16904        _: &::git::UnstageAndNext,
16905        window: &mut Window,
16906        cx: &mut Context<Self>,
16907    ) {
16908        self.do_stage_or_unstage_and_next(false, window, cx);
16909    }
16910
16911    pub fn stage_or_unstage_diff_hunks(
16912        &mut self,
16913        stage: bool,
16914        ranges: Vec<Range<Anchor>>,
16915        cx: &mut Context<Self>,
16916    ) {
16917        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16918        cx.spawn(async move |this, cx| {
16919            task.await?;
16920            this.update(cx, |this, cx| {
16921                let snapshot = this.buffer.read(cx).snapshot(cx);
16922                let chunk_by = this
16923                    .diff_hunks_in_ranges(&ranges, &snapshot)
16924                    .chunk_by(|hunk| hunk.buffer_id);
16925                for (buffer_id, hunks) in &chunk_by {
16926                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16927                }
16928            })
16929        })
16930        .detach_and_log_err(cx);
16931    }
16932
16933    fn save_buffers_for_ranges_if_needed(
16934        &mut self,
16935        ranges: &[Range<Anchor>],
16936        cx: &mut Context<Editor>,
16937    ) -> Task<Result<()>> {
16938        let multibuffer = self.buffer.read(cx);
16939        let snapshot = multibuffer.read(cx);
16940        let buffer_ids: HashSet<_> = ranges
16941            .iter()
16942            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16943            .collect();
16944        drop(snapshot);
16945
16946        let mut buffers = HashSet::default();
16947        for buffer_id in buffer_ids {
16948            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16949                let buffer = buffer_entity.read(cx);
16950                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16951                {
16952                    buffers.insert(buffer_entity);
16953                }
16954            }
16955        }
16956
16957        if let Some(project) = &self.project {
16958            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16959        } else {
16960            Task::ready(Ok(()))
16961        }
16962    }
16963
16964    fn do_stage_or_unstage_and_next(
16965        &mut self,
16966        stage: bool,
16967        window: &mut Window,
16968        cx: &mut Context<Self>,
16969    ) {
16970        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16971
16972        if ranges.iter().any(|range| range.start != range.end) {
16973            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16974            return;
16975        }
16976
16977        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16978        let snapshot = self.snapshot(window, cx);
16979        let position = self.selections.newest::<Point>(cx).head();
16980        let mut row = snapshot
16981            .buffer_snapshot
16982            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16983            .find(|hunk| hunk.row_range.start.0 > position.row)
16984            .map(|hunk| hunk.row_range.start);
16985
16986        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16987        // Outside of the project diff editor, wrap around to the beginning.
16988        if !all_diff_hunks_expanded {
16989            row = row.or_else(|| {
16990                snapshot
16991                    .buffer_snapshot
16992                    .diff_hunks_in_range(Point::zero()..position)
16993                    .find(|hunk| hunk.row_range.end.0 < position.row)
16994                    .map(|hunk| hunk.row_range.start)
16995            });
16996        }
16997
16998        if let Some(row) = row {
16999            let destination = Point::new(row.0, 0);
17000            let autoscroll = Autoscroll::center();
17001
17002            self.unfold_ranges(&[destination..destination], false, false, cx);
17003            self.change_selections(Some(autoscroll), window, cx, |s| {
17004                s.select_ranges([destination..destination]);
17005            });
17006        }
17007    }
17008
17009    fn do_stage_or_unstage(
17010        &self,
17011        stage: bool,
17012        buffer_id: BufferId,
17013        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17014        cx: &mut App,
17015    ) -> Option<()> {
17016        let project = self.project.as_ref()?;
17017        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17018        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17019        let buffer_snapshot = buffer.read(cx).snapshot();
17020        let file_exists = buffer_snapshot
17021            .file()
17022            .is_some_and(|file| file.disk_state().exists());
17023        diff.update(cx, |diff, cx| {
17024            diff.stage_or_unstage_hunks(
17025                stage,
17026                &hunks
17027                    .map(|hunk| buffer_diff::DiffHunk {
17028                        buffer_range: hunk.buffer_range,
17029                        diff_base_byte_range: hunk.diff_base_byte_range,
17030                        secondary_status: hunk.secondary_status,
17031                        range: Point::zero()..Point::zero(), // unused
17032                    })
17033                    .collect::<Vec<_>>(),
17034                &buffer_snapshot,
17035                file_exists,
17036                cx,
17037            )
17038        });
17039        None
17040    }
17041
17042    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17043        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17044        self.buffer
17045            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17046    }
17047
17048    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17049        self.buffer.update(cx, |buffer, cx| {
17050            let ranges = vec![Anchor::min()..Anchor::max()];
17051            if !buffer.all_diff_hunks_expanded()
17052                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17053            {
17054                buffer.collapse_diff_hunks(ranges, cx);
17055                true
17056            } else {
17057                false
17058            }
17059        })
17060    }
17061
17062    fn toggle_diff_hunks_in_ranges(
17063        &mut self,
17064        ranges: Vec<Range<Anchor>>,
17065        cx: &mut Context<Editor>,
17066    ) {
17067        self.buffer.update(cx, |buffer, cx| {
17068            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17069            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17070        })
17071    }
17072
17073    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17074        self.buffer.update(cx, |buffer, cx| {
17075            let snapshot = buffer.snapshot(cx);
17076            let excerpt_id = range.end.excerpt_id;
17077            let point_range = range.to_point(&snapshot);
17078            let expand = !buffer.single_hunk_is_expanded(range, cx);
17079            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17080        })
17081    }
17082
17083    pub(crate) fn apply_all_diff_hunks(
17084        &mut self,
17085        _: &ApplyAllDiffHunks,
17086        window: &mut Window,
17087        cx: &mut Context<Self>,
17088    ) {
17089        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17090
17091        let buffers = self.buffer.read(cx).all_buffers();
17092        for branch_buffer in buffers {
17093            branch_buffer.update(cx, |branch_buffer, cx| {
17094                branch_buffer.merge_into_base(Vec::new(), cx);
17095            });
17096        }
17097
17098        if let Some(project) = self.project.clone() {
17099            self.save(true, project, window, cx).detach_and_log_err(cx);
17100        }
17101    }
17102
17103    pub(crate) fn apply_selected_diff_hunks(
17104        &mut self,
17105        _: &ApplyDiffHunk,
17106        window: &mut Window,
17107        cx: &mut Context<Self>,
17108    ) {
17109        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17110        let snapshot = self.snapshot(window, cx);
17111        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17112        let mut ranges_by_buffer = HashMap::default();
17113        self.transact(window, cx, |editor, _window, cx| {
17114            for hunk in hunks {
17115                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17116                    ranges_by_buffer
17117                        .entry(buffer.clone())
17118                        .or_insert_with(Vec::new)
17119                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17120                }
17121            }
17122
17123            for (buffer, ranges) in ranges_by_buffer {
17124                buffer.update(cx, |buffer, cx| {
17125                    buffer.merge_into_base(ranges, cx);
17126                });
17127            }
17128        });
17129
17130        if let Some(project) = self.project.clone() {
17131            self.save(true, project, window, cx).detach_and_log_err(cx);
17132        }
17133    }
17134
17135    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17136        if hovered != self.gutter_hovered {
17137            self.gutter_hovered = hovered;
17138            cx.notify();
17139        }
17140    }
17141
17142    pub fn insert_blocks(
17143        &mut self,
17144        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17145        autoscroll: Option<Autoscroll>,
17146        cx: &mut Context<Self>,
17147    ) -> Vec<CustomBlockId> {
17148        let blocks = self
17149            .display_map
17150            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17151        if let Some(autoscroll) = autoscroll {
17152            self.request_autoscroll(autoscroll, cx);
17153        }
17154        cx.notify();
17155        blocks
17156    }
17157
17158    pub fn resize_blocks(
17159        &mut self,
17160        heights: HashMap<CustomBlockId, u32>,
17161        autoscroll: Option<Autoscroll>,
17162        cx: &mut Context<Self>,
17163    ) {
17164        self.display_map
17165            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17166        if let Some(autoscroll) = autoscroll {
17167            self.request_autoscroll(autoscroll, cx);
17168        }
17169        cx.notify();
17170    }
17171
17172    pub fn replace_blocks(
17173        &mut self,
17174        renderers: HashMap<CustomBlockId, RenderBlock>,
17175        autoscroll: Option<Autoscroll>,
17176        cx: &mut Context<Self>,
17177    ) {
17178        self.display_map
17179            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17180        if let Some(autoscroll) = autoscroll {
17181            self.request_autoscroll(autoscroll, cx);
17182        }
17183        cx.notify();
17184    }
17185
17186    pub fn remove_blocks(
17187        &mut self,
17188        block_ids: HashSet<CustomBlockId>,
17189        autoscroll: Option<Autoscroll>,
17190        cx: &mut Context<Self>,
17191    ) {
17192        self.display_map.update(cx, |display_map, cx| {
17193            display_map.remove_blocks(block_ids, cx)
17194        });
17195        if let Some(autoscroll) = autoscroll {
17196            self.request_autoscroll(autoscroll, cx);
17197        }
17198        cx.notify();
17199    }
17200
17201    pub fn row_for_block(
17202        &self,
17203        block_id: CustomBlockId,
17204        cx: &mut Context<Self>,
17205    ) -> Option<DisplayRow> {
17206        self.display_map
17207            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17208    }
17209
17210    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17211        self.focused_block = Some(focused_block);
17212    }
17213
17214    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17215        self.focused_block.take()
17216    }
17217
17218    pub fn insert_creases(
17219        &mut self,
17220        creases: impl IntoIterator<Item = Crease<Anchor>>,
17221        cx: &mut Context<Self>,
17222    ) -> Vec<CreaseId> {
17223        self.display_map
17224            .update(cx, |map, cx| map.insert_creases(creases, cx))
17225    }
17226
17227    pub fn remove_creases(
17228        &mut self,
17229        ids: impl IntoIterator<Item = CreaseId>,
17230        cx: &mut Context<Self>,
17231    ) -> Vec<(CreaseId, Range<Anchor>)> {
17232        self.display_map
17233            .update(cx, |map, cx| map.remove_creases(ids, cx))
17234    }
17235
17236    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17237        self.display_map
17238            .update(cx, |map, cx| map.snapshot(cx))
17239            .longest_row()
17240    }
17241
17242    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17243        self.display_map
17244            .update(cx, |map, cx| map.snapshot(cx))
17245            .max_point()
17246    }
17247
17248    pub fn text(&self, cx: &App) -> String {
17249        self.buffer.read(cx).read(cx).text()
17250    }
17251
17252    pub fn is_empty(&self, cx: &App) -> bool {
17253        self.buffer.read(cx).read(cx).is_empty()
17254    }
17255
17256    pub fn text_option(&self, cx: &App) -> Option<String> {
17257        let text = self.text(cx);
17258        let text = text.trim();
17259
17260        if text.is_empty() {
17261            return None;
17262        }
17263
17264        Some(text.to_string())
17265    }
17266
17267    pub fn set_text(
17268        &mut self,
17269        text: impl Into<Arc<str>>,
17270        window: &mut Window,
17271        cx: &mut Context<Self>,
17272    ) {
17273        self.transact(window, cx, |this, _, cx| {
17274            this.buffer
17275                .read(cx)
17276                .as_singleton()
17277                .expect("you can only call set_text on editors for singleton buffers")
17278                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17279        });
17280    }
17281
17282    pub fn display_text(&self, cx: &mut App) -> String {
17283        self.display_map
17284            .update(cx, |map, cx| map.snapshot(cx))
17285            .text()
17286    }
17287
17288    fn create_minimap(
17289        &self,
17290        minimap_settings: MinimapSettings,
17291        window: &mut Window,
17292        cx: &mut Context<Self>,
17293    ) -> Option<Entity<Self>> {
17294        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17295            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17296    }
17297
17298    fn initialize_new_minimap(
17299        &self,
17300        minimap_settings: MinimapSettings,
17301        window: &mut Window,
17302        cx: &mut Context<Self>,
17303    ) -> Entity<Self> {
17304        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17305
17306        let mut minimap = Editor::new_internal(
17307            EditorMode::Minimap {
17308                parent: cx.weak_entity(),
17309            },
17310            self.buffer.clone(),
17311            self.project.clone(),
17312            Some(self.display_map.clone()),
17313            window,
17314            cx,
17315        );
17316        minimap.scroll_manager.clone_state(&self.scroll_manager);
17317        minimap.set_text_style_refinement(TextStyleRefinement {
17318            font_size: Some(MINIMAP_FONT_SIZE),
17319            font_weight: Some(MINIMAP_FONT_WEIGHT),
17320            ..Default::default()
17321        });
17322        minimap.update_minimap_configuration(minimap_settings, cx);
17323        cx.new(|_| minimap)
17324    }
17325
17326    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17327        let current_line_highlight = minimap_settings
17328            .current_line_highlight
17329            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17330        self.set_current_line_highlight(Some(current_line_highlight));
17331    }
17332
17333    pub fn minimap(&self) -> Option<&Entity<Self>> {
17334        self.minimap
17335            .as_ref()
17336            .filter(|_| self.minimap_visibility.visible())
17337    }
17338
17339    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17340        let mut wrap_guides = smallvec![];
17341
17342        if self.show_wrap_guides == Some(false) {
17343            return wrap_guides;
17344        }
17345
17346        let settings = self.buffer.read(cx).language_settings(cx);
17347        if settings.show_wrap_guides {
17348            match self.soft_wrap_mode(cx) {
17349                SoftWrap::Column(soft_wrap) => {
17350                    wrap_guides.push((soft_wrap as usize, true));
17351                }
17352                SoftWrap::Bounded(soft_wrap) => {
17353                    wrap_guides.push((soft_wrap as usize, true));
17354                }
17355                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17356            }
17357            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17358        }
17359
17360        wrap_guides
17361    }
17362
17363    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17364        let settings = self.buffer.read(cx).language_settings(cx);
17365        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17366        match mode {
17367            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17368                SoftWrap::None
17369            }
17370            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17371            language_settings::SoftWrap::PreferredLineLength => {
17372                SoftWrap::Column(settings.preferred_line_length)
17373            }
17374            language_settings::SoftWrap::Bounded => {
17375                SoftWrap::Bounded(settings.preferred_line_length)
17376            }
17377        }
17378    }
17379
17380    pub fn set_soft_wrap_mode(
17381        &mut self,
17382        mode: language_settings::SoftWrap,
17383
17384        cx: &mut Context<Self>,
17385    ) {
17386        self.soft_wrap_mode_override = Some(mode);
17387        cx.notify();
17388    }
17389
17390    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17391        self.hard_wrap = hard_wrap;
17392        cx.notify();
17393    }
17394
17395    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17396        self.text_style_refinement = Some(style);
17397    }
17398
17399    /// called by the Element so we know what style we were most recently rendered with.
17400    pub(crate) fn set_style(
17401        &mut self,
17402        style: EditorStyle,
17403        window: &mut Window,
17404        cx: &mut Context<Self>,
17405    ) {
17406        // We intentionally do not inform the display map about the minimap style
17407        // so that wrapping is not recalculated and stays consistent for the editor
17408        // and its linked minimap.
17409        if !self.mode.is_minimap() {
17410            let rem_size = window.rem_size();
17411            self.display_map.update(cx, |map, cx| {
17412                map.set_font(
17413                    style.text.font(),
17414                    style.text.font_size.to_pixels(rem_size),
17415                    cx,
17416                )
17417            });
17418        }
17419        self.style = Some(style);
17420    }
17421
17422    pub fn style(&self) -> Option<&EditorStyle> {
17423        self.style.as_ref()
17424    }
17425
17426    // Called by the element. This method is not designed to be called outside of the editor
17427    // element's layout code because it does not notify when rewrapping is computed synchronously.
17428    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17429        self.display_map
17430            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17431    }
17432
17433    pub fn set_soft_wrap(&mut self) {
17434        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17435    }
17436
17437    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17438        if self.soft_wrap_mode_override.is_some() {
17439            self.soft_wrap_mode_override.take();
17440        } else {
17441            let soft_wrap = match self.soft_wrap_mode(cx) {
17442                SoftWrap::GitDiff => return,
17443                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17444                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17445                    language_settings::SoftWrap::None
17446                }
17447            };
17448            self.soft_wrap_mode_override = Some(soft_wrap);
17449        }
17450        cx.notify();
17451    }
17452
17453    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17454        let Some(workspace) = self.workspace() else {
17455            return;
17456        };
17457        let fs = workspace.read(cx).app_state().fs.clone();
17458        let current_show = TabBarSettings::get_global(cx).show;
17459        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17460            setting.show = Some(!current_show);
17461        });
17462    }
17463
17464    pub fn toggle_indent_guides(
17465        &mut self,
17466        _: &ToggleIndentGuides,
17467        _: &mut Window,
17468        cx: &mut Context<Self>,
17469    ) {
17470        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17471            self.buffer
17472                .read(cx)
17473                .language_settings(cx)
17474                .indent_guides
17475                .enabled
17476        });
17477        self.show_indent_guides = Some(!currently_enabled);
17478        cx.notify();
17479    }
17480
17481    fn should_show_indent_guides(&self) -> Option<bool> {
17482        self.show_indent_guides
17483    }
17484
17485    pub fn toggle_line_numbers(
17486        &mut self,
17487        _: &ToggleLineNumbers,
17488        _: &mut Window,
17489        cx: &mut Context<Self>,
17490    ) {
17491        let mut editor_settings = EditorSettings::get_global(cx).clone();
17492        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17493        EditorSettings::override_global(editor_settings, cx);
17494    }
17495
17496    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17497        if let Some(show_line_numbers) = self.show_line_numbers {
17498            return show_line_numbers;
17499        }
17500        EditorSettings::get_global(cx).gutter.line_numbers
17501    }
17502
17503    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17504        self.use_relative_line_numbers
17505            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17506    }
17507
17508    pub fn toggle_relative_line_numbers(
17509        &mut self,
17510        _: &ToggleRelativeLineNumbers,
17511        _: &mut Window,
17512        cx: &mut Context<Self>,
17513    ) {
17514        let is_relative = self.should_use_relative_line_numbers(cx);
17515        self.set_relative_line_number(Some(!is_relative), cx)
17516    }
17517
17518    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17519        self.use_relative_line_numbers = is_relative;
17520        cx.notify();
17521    }
17522
17523    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17524        self.show_gutter = show_gutter;
17525        cx.notify();
17526    }
17527
17528    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17529        self.show_scrollbars = ScrollbarAxes {
17530            horizontal: show,
17531            vertical: show,
17532        };
17533        cx.notify();
17534    }
17535
17536    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17537        self.show_scrollbars.vertical = show;
17538        cx.notify();
17539    }
17540
17541    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17542        self.show_scrollbars.horizontal = show;
17543        cx.notify();
17544    }
17545
17546    pub fn set_minimap_visibility(
17547        &mut self,
17548        minimap_visibility: MinimapVisibility,
17549        window: &mut Window,
17550        cx: &mut Context<Self>,
17551    ) {
17552        if self.minimap_visibility != minimap_visibility {
17553            if minimap_visibility.visible() && self.minimap.is_none() {
17554                let minimap_settings = EditorSettings::get_global(cx).minimap;
17555                self.minimap =
17556                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17557            }
17558            self.minimap_visibility = minimap_visibility;
17559            cx.notify();
17560        }
17561    }
17562
17563    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17564        self.set_show_scrollbars(false, cx);
17565        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17566    }
17567
17568    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17569        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17570    }
17571
17572    /// Normally the text in full mode and auto height editors is padded on the
17573    /// left side by roughly half a character width for improved hit testing.
17574    ///
17575    /// Use this method to disable this for cases where this is not wanted (e.g.
17576    /// if you want to align the editor text with some other text above or below)
17577    /// or if you want to add this padding to single-line editors.
17578    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17579        self.offset_content = offset_content;
17580        cx.notify();
17581    }
17582
17583    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17584        self.show_line_numbers = Some(show_line_numbers);
17585        cx.notify();
17586    }
17587
17588    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17589        self.disable_expand_excerpt_buttons = true;
17590        cx.notify();
17591    }
17592
17593    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17594        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17595        cx.notify();
17596    }
17597
17598    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17599        self.show_code_actions = Some(show_code_actions);
17600        cx.notify();
17601    }
17602
17603    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17604        self.show_runnables = Some(show_runnables);
17605        cx.notify();
17606    }
17607
17608    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17609        self.show_breakpoints = Some(show_breakpoints);
17610        cx.notify();
17611    }
17612
17613    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17614        if self.display_map.read(cx).masked != masked {
17615            self.display_map.update(cx, |map, _| map.masked = masked);
17616        }
17617        cx.notify()
17618    }
17619
17620    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17621        self.show_wrap_guides = Some(show_wrap_guides);
17622        cx.notify();
17623    }
17624
17625    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17626        self.show_indent_guides = Some(show_indent_guides);
17627        cx.notify();
17628    }
17629
17630    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17631        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17632            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17633                if let Some(dir) = file.abs_path(cx).parent() {
17634                    return Some(dir.to_owned());
17635                }
17636            }
17637
17638            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17639                return Some(project_path.path.to_path_buf());
17640            }
17641        }
17642
17643        None
17644    }
17645
17646    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17647        self.active_excerpt(cx)?
17648            .1
17649            .read(cx)
17650            .file()
17651            .and_then(|f| f.as_local())
17652    }
17653
17654    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17655        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17656            let buffer = buffer.read(cx);
17657            if let Some(project_path) = buffer.project_path(cx) {
17658                let project = self.project.as_ref()?.read(cx);
17659                project.absolute_path(&project_path, cx)
17660            } else {
17661                buffer
17662                    .file()
17663                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17664            }
17665        })
17666    }
17667
17668    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17669        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17670            let project_path = buffer.read(cx).project_path(cx)?;
17671            let project = self.project.as_ref()?.read(cx);
17672            let entry = project.entry_for_path(&project_path, cx)?;
17673            let path = entry.path.to_path_buf();
17674            Some(path)
17675        })
17676    }
17677
17678    pub fn reveal_in_finder(
17679        &mut self,
17680        _: &RevealInFileManager,
17681        _window: &mut Window,
17682        cx: &mut Context<Self>,
17683    ) {
17684        if let Some(target) = self.target_file(cx) {
17685            cx.reveal_path(&target.abs_path(cx));
17686        }
17687    }
17688
17689    pub fn copy_path(
17690        &mut self,
17691        _: &zed_actions::workspace::CopyPath,
17692        _window: &mut Window,
17693        cx: &mut Context<Self>,
17694    ) {
17695        if let Some(path) = self.target_file_abs_path(cx) {
17696            if let Some(path) = path.to_str() {
17697                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17698            }
17699        }
17700    }
17701
17702    pub fn copy_relative_path(
17703        &mut self,
17704        _: &zed_actions::workspace::CopyRelativePath,
17705        _window: &mut Window,
17706        cx: &mut Context<Self>,
17707    ) {
17708        if let Some(path) = self.target_file_path(cx) {
17709            if let Some(path) = path.to_str() {
17710                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17711            }
17712        }
17713    }
17714
17715    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17716        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17717            buffer.read(cx).project_path(cx)
17718        } else {
17719            None
17720        }
17721    }
17722
17723    // Returns true if the editor handled a go-to-line request
17724    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17725        maybe!({
17726            let breakpoint_store = self.breakpoint_store.as_ref()?;
17727
17728            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17729            else {
17730                self.clear_row_highlights::<ActiveDebugLine>();
17731                return None;
17732            };
17733
17734            let position = active_stack_frame.position;
17735            let buffer_id = position.buffer_id?;
17736            let snapshot = self
17737                .project
17738                .as_ref()?
17739                .read(cx)
17740                .buffer_for_id(buffer_id, cx)?
17741                .read(cx)
17742                .snapshot();
17743
17744            let mut handled = false;
17745            for (id, ExcerptRange { context, .. }) in
17746                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17747            {
17748                if context.start.cmp(&position, &snapshot).is_ge()
17749                    || context.end.cmp(&position, &snapshot).is_lt()
17750                {
17751                    continue;
17752                }
17753                let snapshot = self.buffer.read(cx).snapshot(cx);
17754                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17755
17756                handled = true;
17757                self.clear_row_highlights::<ActiveDebugLine>();
17758
17759                self.go_to_line::<ActiveDebugLine>(
17760                    multibuffer_anchor,
17761                    Some(cx.theme().colors().editor_debugger_active_line_background),
17762                    window,
17763                    cx,
17764                );
17765
17766                cx.notify();
17767            }
17768
17769            handled.then_some(())
17770        })
17771        .is_some()
17772    }
17773
17774    pub fn copy_file_name_without_extension(
17775        &mut self,
17776        _: &CopyFileNameWithoutExtension,
17777        _: &mut Window,
17778        cx: &mut Context<Self>,
17779    ) {
17780        if let Some(file) = self.target_file(cx) {
17781            if let Some(file_stem) = file.path().file_stem() {
17782                if let Some(name) = file_stem.to_str() {
17783                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17784                }
17785            }
17786        }
17787    }
17788
17789    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17790        if let Some(file) = self.target_file(cx) {
17791            if let Some(file_name) = file.path().file_name() {
17792                if let Some(name) = file_name.to_str() {
17793                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17794                }
17795            }
17796        }
17797    }
17798
17799    pub fn toggle_git_blame(
17800        &mut self,
17801        _: &::git::Blame,
17802        window: &mut Window,
17803        cx: &mut Context<Self>,
17804    ) {
17805        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17806
17807        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17808            self.start_git_blame(true, window, cx);
17809        }
17810
17811        cx.notify();
17812    }
17813
17814    pub fn toggle_git_blame_inline(
17815        &mut self,
17816        _: &ToggleGitBlameInline,
17817        window: &mut Window,
17818        cx: &mut Context<Self>,
17819    ) {
17820        self.toggle_git_blame_inline_internal(true, window, cx);
17821        cx.notify();
17822    }
17823
17824    pub fn open_git_blame_commit(
17825        &mut self,
17826        _: &OpenGitBlameCommit,
17827        window: &mut Window,
17828        cx: &mut Context<Self>,
17829    ) {
17830        self.open_git_blame_commit_internal(window, cx);
17831    }
17832
17833    fn open_git_blame_commit_internal(
17834        &mut self,
17835        window: &mut Window,
17836        cx: &mut Context<Self>,
17837    ) -> Option<()> {
17838        let blame = self.blame.as_ref()?;
17839        let snapshot = self.snapshot(window, cx);
17840        let cursor = self.selections.newest::<Point>(cx).head();
17841        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17842        let blame_entry = blame
17843            .update(cx, |blame, cx| {
17844                blame
17845                    .blame_for_rows(
17846                        &[RowInfo {
17847                            buffer_id: Some(buffer.remote_id()),
17848                            buffer_row: Some(point.row),
17849                            ..Default::default()
17850                        }],
17851                        cx,
17852                    )
17853                    .next()
17854            })
17855            .flatten()?;
17856        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17857        let repo = blame.read(cx).repository(cx)?;
17858        let workspace = self.workspace()?.downgrade();
17859        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17860        None
17861    }
17862
17863    pub fn git_blame_inline_enabled(&self) -> bool {
17864        self.git_blame_inline_enabled
17865    }
17866
17867    pub fn toggle_selection_menu(
17868        &mut self,
17869        _: &ToggleSelectionMenu,
17870        _: &mut Window,
17871        cx: &mut Context<Self>,
17872    ) {
17873        self.show_selection_menu = self
17874            .show_selection_menu
17875            .map(|show_selections_menu| !show_selections_menu)
17876            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17877
17878        cx.notify();
17879    }
17880
17881    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17882        self.show_selection_menu
17883            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17884    }
17885
17886    fn start_git_blame(
17887        &mut self,
17888        user_triggered: bool,
17889        window: &mut Window,
17890        cx: &mut Context<Self>,
17891    ) {
17892        if let Some(project) = self.project.as_ref() {
17893            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17894                return;
17895            };
17896
17897            if buffer.read(cx).file().is_none() {
17898                return;
17899            }
17900
17901            let focused = self.focus_handle(cx).contains_focused(window, cx);
17902
17903            let project = project.clone();
17904            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17905            self.blame_subscription =
17906                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17907            self.blame = Some(blame);
17908        }
17909    }
17910
17911    fn toggle_git_blame_inline_internal(
17912        &mut self,
17913        user_triggered: bool,
17914        window: &mut Window,
17915        cx: &mut Context<Self>,
17916    ) {
17917        if self.git_blame_inline_enabled {
17918            self.git_blame_inline_enabled = false;
17919            self.show_git_blame_inline = false;
17920            self.show_git_blame_inline_delay_task.take();
17921        } else {
17922            self.git_blame_inline_enabled = true;
17923            self.start_git_blame_inline(user_triggered, window, cx);
17924        }
17925
17926        cx.notify();
17927    }
17928
17929    fn start_git_blame_inline(
17930        &mut self,
17931        user_triggered: bool,
17932        window: &mut Window,
17933        cx: &mut Context<Self>,
17934    ) {
17935        self.start_git_blame(user_triggered, window, cx);
17936
17937        if ProjectSettings::get_global(cx)
17938            .git
17939            .inline_blame_delay()
17940            .is_some()
17941        {
17942            self.start_inline_blame_timer(window, cx);
17943        } else {
17944            self.show_git_blame_inline = true
17945        }
17946    }
17947
17948    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17949        self.blame.as_ref()
17950    }
17951
17952    pub fn show_git_blame_gutter(&self) -> bool {
17953        self.show_git_blame_gutter
17954    }
17955
17956    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17957        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17958    }
17959
17960    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17961        self.show_git_blame_inline
17962            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17963            && !self.newest_selection_head_on_empty_line(cx)
17964            && self.has_blame_entries(cx)
17965    }
17966
17967    fn has_blame_entries(&self, cx: &App) -> bool {
17968        self.blame()
17969            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17970    }
17971
17972    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17973        let cursor_anchor = self.selections.newest_anchor().head();
17974
17975        let snapshot = self.buffer.read(cx).snapshot(cx);
17976        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17977
17978        snapshot.line_len(buffer_row) == 0
17979    }
17980
17981    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17982        let buffer_and_selection = maybe!({
17983            let selection = self.selections.newest::<Point>(cx);
17984            let selection_range = selection.range();
17985
17986            let multi_buffer = self.buffer().read(cx);
17987            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17988            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17989
17990            let (buffer, range, _) = if selection.reversed {
17991                buffer_ranges.first()
17992            } else {
17993                buffer_ranges.last()
17994            }?;
17995
17996            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17997                ..text::ToPoint::to_point(&range.end, &buffer).row;
17998            Some((
17999                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18000                selection,
18001            ))
18002        });
18003
18004        let Some((buffer, selection)) = buffer_and_selection else {
18005            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18006        };
18007
18008        let Some(project) = self.project.as_ref() else {
18009            return Task::ready(Err(anyhow!("editor does not have project")));
18010        };
18011
18012        project.update(cx, |project, cx| {
18013            project.get_permalink_to_line(&buffer, selection, cx)
18014        })
18015    }
18016
18017    pub fn copy_permalink_to_line(
18018        &mut self,
18019        _: &CopyPermalinkToLine,
18020        window: &mut Window,
18021        cx: &mut Context<Self>,
18022    ) {
18023        let permalink_task = self.get_permalink_to_line(cx);
18024        let workspace = self.workspace();
18025
18026        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18027            Ok(permalink) => {
18028                cx.update(|_, cx| {
18029                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18030                })
18031                .ok();
18032            }
18033            Err(err) => {
18034                let message = format!("Failed to copy permalink: {err}");
18035
18036                anyhow::Result::<()>::Err(err).log_err();
18037
18038                if let Some(workspace) = workspace {
18039                    workspace
18040                        .update_in(cx, |workspace, _, cx| {
18041                            struct CopyPermalinkToLine;
18042
18043                            workspace.show_toast(
18044                                Toast::new(
18045                                    NotificationId::unique::<CopyPermalinkToLine>(),
18046                                    message,
18047                                ),
18048                                cx,
18049                            )
18050                        })
18051                        .ok();
18052                }
18053            }
18054        })
18055        .detach();
18056    }
18057
18058    pub fn copy_file_location(
18059        &mut self,
18060        _: &CopyFileLocation,
18061        _: &mut Window,
18062        cx: &mut Context<Self>,
18063    ) {
18064        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18065        if let Some(file) = self.target_file(cx) {
18066            if let Some(path) = file.path().to_str() {
18067                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18068            }
18069        }
18070    }
18071
18072    pub fn open_permalink_to_line(
18073        &mut self,
18074        _: &OpenPermalinkToLine,
18075        window: &mut Window,
18076        cx: &mut Context<Self>,
18077    ) {
18078        let permalink_task = self.get_permalink_to_line(cx);
18079        let workspace = self.workspace();
18080
18081        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18082            Ok(permalink) => {
18083                cx.update(|_, cx| {
18084                    cx.open_url(permalink.as_ref());
18085                })
18086                .ok();
18087            }
18088            Err(err) => {
18089                let message = format!("Failed to open permalink: {err}");
18090
18091                anyhow::Result::<()>::Err(err).log_err();
18092
18093                if let Some(workspace) = workspace {
18094                    workspace
18095                        .update(cx, |workspace, cx| {
18096                            struct OpenPermalinkToLine;
18097
18098                            workspace.show_toast(
18099                                Toast::new(
18100                                    NotificationId::unique::<OpenPermalinkToLine>(),
18101                                    message,
18102                                ),
18103                                cx,
18104                            )
18105                        })
18106                        .ok();
18107                }
18108            }
18109        })
18110        .detach();
18111    }
18112
18113    pub fn insert_uuid_v4(
18114        &mut self,
18115        _: &InsertUuidV4,
18116        window: &mut Window,
18117        cx: &mut Context<Self>,
18118    ) {
18119        self.insert_uuid(UuidVersion::V4, window, cx);
18120    }
18121
18122    pub fn insert_uuid_v7(
18123        &mut self,
18124        _: &InsertUuidV7,
18125        window: &mut Window,
18126        cx: &mut Context<Self>,
18127    ) {
18128        self.insert_uuid(UuidVersion::V7, window, cx);
18129    }
18130
18131    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18132        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
18133        self.transact(window, cx, |this, window, cx| {
18134            let edits = this
18135                .selections
18136                .all::<Point>(cx)
18137                .into_iter()
18138                .map(|selection| {
18139                    let uuid = match version {
18140                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18141                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18142                    };
18143
18144                    (selection.range(), uuid.to_string())
18145                });
18146            this.edit(edits, cx);
18147            this.refresh_inline_completion(true, false, window, cx);
18148        });
18149    }
18150
18151    pub fn open_selections_in_multibuffer(
18152        &mut self,
18153        _: &OpenSelectionsInMultibuffer,
18154        window: &mut Window,
18155        cx: &mut Context<Self>,
18156    ) {
18157        let multibuffer = self.buffer.read(cx);
18158
18159        let Some(buffer) = multibuffer.as_singleton() else {
18160            return;
18161        };
18162
18163        let Some(workspace) = self.workspace() else {
18164            return;
18165        };
18166
18167        let locations = self
18168            .selections
18169            .disjoint_anchors()
18170            .iter()
18171            .map(|range| Location {
18172                buffer: buffer.clone(),
18173                range: range.start.text_anchor..range.end.text_anchor,
18174            })
18175            .collect::<Vec<_>>();
18176
18177        let title = multibuffer.title(cx).to_string();
18178
18179        cx.spawn_in(window, async move |_, cx| {
18180            workspace.update_in(cx, |workspace, window, cx| {
18181                Self::open_locations_in_multibuffer(
18182                    workspace,
18183                    locations,
18184                    format!("Selections for '{title}'"),
18185                    false,
18186                    MultibufferSelectionMode::All,
18187                    window,
18188                    cx,
18189                );
18190            })
18191        })
18192        .detach();
18193    }
18194
18195    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18196    /// last highlight added will be used.
18197    ///
18198    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18199    pub fn highlight_rows<T: 'static>(
18200        &mut self,
18201        range: Range<Anchor>,
18202        color: Hsla,
18203        options: RowHighlightOptions,
18204        cx: &mut Context<Self>,
18205    ) {
18206        let snapshot = self.buffer().read(cx).snapshot(cx);
18207        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18208        let ix = row_highlights.binary_search_by(|highlight| {
18209            Ordering::Equal
18210                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18211                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18212        });
18213
18214        if let Err(mut ix) = ix {
18215            let index = post_inc(&mut self.highlight_order);
18216
18217            // If this range intersects with the preceding highlight, then merge it with
18218            // the preceding highlight. Otherwise insert a new highlight.
18219            let mut merged = false;
18220            if ix > 0 {
18221                let prev_highlight = &mut row_highlights[ix - 1];
18222                if prev_highlight
18223                    .range
18224                    .end
18225                    .cmp(&range.start, &snapshot)
18226                    .is_ge()
18227                {
18228                    ix -= 1;
18229                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18230                        prev_highlight.range.end = range.end;
18231                    }
18232                    merged = true;
18233                    prev_highlight.index = index;
18234                    prev_highlight.color = color;
18235                    prev_highlight.options = options;
18236                }
18237            }
18238
18239            if !merged {
18240                row_highlights.insert(
18241                    ix,
18242                    RowHighlight {
18243                        range: range.clone(),
18244                        index,
18245                        color,
18246                        options,
18247                        type_id: TypeId::of::<T>(),
18248                    },
18249                );
18250            }
18251
18252            // If any of the following highlights intersect with this one, merge them.
18253            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18254                let highlight = &row_highlights[ix];
18255                if next_highlight
18256                    .range
18257                    .start
18258                    .cmp(&highlight.range.end, &snapshot)
18259                    .is_le()
18260                {
18261                    if next_highlight
18262                        .range
18263                        .end
18264                        .cmp(&highlight.range.end, &snapshot)
18265                        .is_gt()
18266                    {
18267                        row_highlights[ix].range.end = next_highlight.range.end;
18268                    }
18269                    row_highlights.remove(ix + 1);
18270                } else {
18271                    break;
18272                }
18273            }
18274        }
18275    }
18276
18277    /// Remove any highlighted row ranges of the given type that intersect the
18278    /// given ranges.
18279    pub fn remove_highlighted_rows<T: 'static>(
18280        &mut self,
18281        ranges_to_remove: Vec<Range<Anchor>>,
18282        cx: &mut Context<Self>,
18283    ) {
18284        let snapshot = self.buffer().read(cx).snapshot(cx);
18285        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18286        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18287        row_highlights.retain(|highlight| {
18288            while let Some(range_to_remove) = ranges_to_remove.peek() {
18289                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18290                    Ordering::Less | Ordering::Equal => {
18291                        ranges_to_remove.next();
18292                    }
18293                    Ordering::Greater => {
18294                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18295                            Ordering::Less | Ordering::Equal => {
18296                                return false;
18297                            }
18298                            Ordering::Greater => break,
18299                        }
18300                    }
18301                }
18302            }
18303
18304            true
18305        })
18306    }
18307
18308    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18309    pub fn clear_row_highlights<T: 'static>(&mut self) {
18310        self.highlighted_rows.remove(&TypeId::of::<T>());
18311    }
18312
18313    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18314    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18315        self.highlighted_rows
18316            .get(&TypeId::of::<T>())
18317            .map_or(&[] as &[_], |vec| vec.as_slice())
18318            .iter()
18319            .map(|highlight| (highlight.range.clone(), highlight.color))
18320    }
18321
18322    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18323    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18324    /// Allows to ignore certain kinds of highlights.
18325    pub fn highlighted_display_rows(
18326        &self,
18327        window: &mut Window,
18328        cx: &mut App,
18329    ) -> BTreeMap<DisplayRow, LineHighlight> {
18330        let snapshot = self.snapshot(window, cx);
18331        let mut used_highlight_orders = HashMap::default();
18332        self.highlighted_rows
18333            .iter()
18334            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18335            .fold(
18336                BTreeMap::<DisplayRow, LineHighlight>::new(),
18337                |mut unique_rows, highlight| {
18338                    let start = highlight.range.start.to_display_point(&snapshot);
18339                    let end = highlight.range.end.to_display_point(&snapshot);
18340                    let start_row = start.row().0;
18341                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18342                        && end.column() == 0
18343                    {
18344                        end.row().0.saturating_sub(1)
18345                    } else {
18346                        end.row().0
18347                    };
18348                    for row in start_row..=end_row {
18349                        let used_index =
18350                            used_highlight_orders.entry(row).or_insert(highlight.index);
18351                        if highlight.index >= *used_index {
18352                            *used_index = highlight.index;
18353                            unique_rows.insert(
18354                                DisplayRow(row),
18355                                LineHighlight {
18356                                    include_gutter: highlight.options.include_gutter,
18357                                    border: None,
18358                                    background: highlight.color.into(),
18359                                    type_id: Some(highlight.type_id),
18360                                },
18361                            );
18362                        }
18363                    }
18364                    unique_rows
18365                },
18366            )
18367    }
18368
18369    pub fn highlighted_display_row_for_autoscroll(
18370        &self,
18371        snapshot: &DisplaySnapshot,
18372    ) -> Option<DisplayRow> {
18373        self.highlighted_rows
18374            .values()
18375            .flat_map(|highlighted_rows| highlighted_rows.iter())
18376            .filter_map(|highlight| {
18377                if highlight.options.autoscroll {
18378                    Some(highlight.range.start.to_display_point(snapshot).row())
18379                } else {
18380                    None
18381                }
18382            })
18383            .min()
18384    }
18385
18386    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18387        self.highlight_background::<SearchWithinRange>(
18388            ranges,
18389            |colors| colors.editor_document_highlight_read_background,
18390            cx,
18391        )
18392    }
18393
18394    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18395        self.breadcrumb_header = Some(new_header);
18396    }
18397
18398    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18399        self.clear_background_highlights::<SearchWithinRange>(cx);
18400    }
18401
18402    pub fn highlight_background<T: 'static>(
18403        &mut self,
18404        ranges: &[Range<Anchor>],
18405        color_fetcher: fn(&ThemeColors) -> Hsla,
18406        cx: &mut Context<Self>,
18407    ) {
18408        self.background_highlights
18409            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18410        self.scrollbar_marker_state.dirty = true;
18411        cx.notify();
18412    }
18413
18414    pub fn clear_background_highlights<T: 'static>(
18415        &mut self,
18416        cx: &mut Context<Self>,
18417    ) -> Option<BackgroundHighlight> {
18418        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18419        if !text_highlights.1.is_empty() {
18420            self.scrollbar_marker_state.dirty = true;
18421            cx.notify();
18422        }
18423        Some(text_highlights)
18424    }
18425
18426    pub fn highlight_gutter<T: 'static>(
18427        &mut self,
18428        ranges: impl Into<Vec<Range<Anchor>>>,
18429        color_fetcher: fn(&App) -> Hsla,
18430        cx: &mut Context<Self>,
18431    ) {
18432        self.gutter_highlights
18433            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18434        cx.notify();
18435    }
18436
18437    pub fn clear_gutter_highlights<T: 'static>(
18438        &mut self,
18439        cx: &mut Context<Self>,
18440    ) -> Option<GutterHighlight> {
18441        cx.notify();
18442        self.gutter_highlights.remove(&TypeId::of::<T>())
18443    }
18444
18445    pub fn insert_gutter_highlight<T: 'static>(
18446        &mut self,
18447        range: Range<Anchor>,
18448        color_fetcher: fn(&App) -> Hsla,
18449        cx: &mut Context<Self>,
18450    ) {
18451        let snapshot = self.buffer().read(cx).snapshot(cx);
18452        let mut highlights = self
18453            .gutter_highlights
18454            .remove(&TypeId::of::<T>())
18455            .map(|(_, highlights)| highlights)
18456            .unwrap_or_default();
18457        let ix = highlights.binary_search_by(|highlight| {
18458            Ordering::Equal
18459                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18460                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18461        });
18462        if let Err(ix) = ix {
18463            highlights.insert(ix, range);
18464        }
18465        self.gutter_highlights
18466            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18467    }
18468
18469    pub fn remove_gutter_highlights<T: 'static>(
18470        &mut self,
18471        ranges_to_remove: Vec<Range<Anchor>>,
18472        cx: &mut Context<Self>,
18473    ) {
18474        let snapshot = self.buffer().read(cx).snapshot(cx);
18475        let Some((color_fetcher, mut gutter_highlights)) =
18476            self.gutter_highlights.remove(&TypeId::of::<T>())
18477        else {
18478            return;
18479        };
18480        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18481        gutter_highlights.retain(|highlight| {
18482            while let Some(range_to_remove) = ranges_to_remove.peek() {
18483                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18484                    Ordering::Less | Ordering::Equal => {
18485                        ranges_to_remove.next();
18486                    }
18487                    Ordering::Greater => {
18488                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18489                            Ordering::Less | Ordering::Equal => {
18490                                return false;
18491                            }
18492                            Ordering::Greater => break,
18493                        }
18494                    }
18495                }
18496            }
18497
18498            true
18499        });
18500        self.gutter_highlights
18501            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18502    }
18503
18504    #[cfg(feature = "test-support")]
18505    pub fn all_text_background_highlights(
18506        &self,
18507        window: &mut Window,
18508        cx: &mut Context<Self>,
18509    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18510        let snapshot = self.snapshot(window, cx);
18511        let buffer = &snapshot.buffer_snapshot;
18512        let start = buffer.anchor_before(0);
18513        let end = buffer.anchor_after(buffer.len());
18514        let theme = cx.theme().colors();
18515        self.background_highlights_in_range(start..end, &snapshot, theme)
18516    }
18517
18518    #[cfg(feature = "test-support")]
18519    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18520        let snapshot = self.buffer().read(cx).snapshot(cx);
18521
18522        let highlights = self
18523            .background_highlights
18524            .get(&TypeId::of::<items::BufferSearchHighlights>());
18525
18526        if let Some((_color, ranges)) = highlights {
18527            ranges
18528                .iter()
18529                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18530                .collect_vec()
18531        } else {
18532            vec![]
18533        }
18534    }
18535
18536    fn document_highlights_for_position<'a>(
18537        &'a self,
18538        position: Anchor,
18539        buffer: &'a MultiBufferSnapshot,
18540    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18541        let read_highlights = self
18542            .background_highlights
18543            .get(&TypeId::of::<DocumentHighlightRead>())
18544            .map(|h| &h.1);
18545        let write_highlights = self
18546            .background_highlights
18547            .get(&TypeId::of::<DocumentHighlightWrite>())
18548            .map(|h| &h.1);
18549        let left_position = position.bias_left(buffer);
18550        let right_position = position.bias_right(buffer);
18551        read_highlights
18552            .into_iter()
18553            .chain(write_highlights)
18554            .flat_map(move |ranges| {
18555                let start_ix = match ranges.binary_search_by(|probe| {
18556                    let cmp = probe.end.cmp(&left_position, buffer);
18557                    if cmp.is_ge() {
18558                        Ordering::Greater
18559                    } else {
18560                        Ordering::Less
18561                    }
18562                }) {
18563                    Ok(i) | Err(i) => i,
18564                };
18565
18566                ranges[start_ix..]
18567                    .iter()
18568                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18569            })
18570    }
18571
18572    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18573        self.background_highlights
18574            .get(&TypeId::of::<T>())
18575            .map_or(false, |(_, highlights)| !highlights.is_empty())
18576    }
18577
18578    pub fn background_highlights_in_range(
18579        &self,
18580        search_range: Range<Anchor>,
18581        display_snapshot: &DisplaySnapshot,
18582        theme: &ThemeColors,
18583    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18584        let mut results = Vec::new();
18585        for (color_fetcher, ranges) in self.background_highlights.values() {
18586            let color = color_fetcher(theme);
18587            let start_ix = match ranges.binary_search_by(|probe| {
18588                let cmp = probe
18589                    .end
18590                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18591                if cmp.is_gt() {
18592                    Ordering::Greater
18593                } else {
18594                    Ordering::Less
18595                }
18596            }) {
18597                Ok(i) | Err(i) => i,
18598            };
18599            for range in &ranges[start_ix..] {
18600                if range
18601                    .start
18602                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18603                    .is_ge()
18604                {
18605                    break;
18606                }
18607
18608                let start = range.start.to_display_point(display_snapshot);
18609                let end = range.end.to_display_point(display_snapshot);
18610                results.push((start..end, color))
18611            }
18612        }
18613        results
18614    }
18615
18616    pub fn background_highlight_row_ranges<T: 'static>(
18617        &self,
18618        search_range: Range<Anchor>,
18619        display_snapshot: &DisplaySnapshot,
18620        count: usize,
18621    ) -> Vec<RangeInclusive<DisplayPoint>> {
18622        let mut results = Vec::new();
18623        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18624            return vec![];
18625        };
18626
18627        let start_ix = match ranges.binary_search_by(|probe| {
18628            let cmp = probe
18629                .end
18630                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18631            if cmp.is_gt() {
18632                Ordering::Greater
18633            } else {
18634                Ordering::Less
18635            }
18636        }) {
18637            Ok(i) | Err(i) => i,
18638        };
18639        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18640            if let (Some(start_display), Some(end_display)) = (start, end) {
18641                results.push(
18642                    start_display.to_display_point(display_snapshot)
18643                        ..=end_display.to_display_point(display_snapshot),
18644                );
18645            }
18646        };
18647        let mut start_row: Option<Point> = None;
18648        let mut end_row: Option<Point> = None;
18649        if ranges.len() > count {
18650            return Vec::new();
18651        }
18652        for range in &ranges[start_ix..] {
18653            if range
18654                .start
18655                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18656                .is_ge()
18657            {
18658                break;
18659            }
18660            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18661            if let Some(current_row) = &end_row {
18662                if end.row == current_row.row {
18663                    continue;
18664                }
18665            }
18666            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18667            if start_row.is_none() {
18668                assert_eq!(end_row, None);
18669                start_row = Some(start);
18670                end_row = Some(end);
18671                continue;
18672            }
18673            if let Some(current_end) = end_row.as_mut() {
18674                if start.row > current_end.row + 1 {
18675                    push_region(start_row, end_row);
18676                    start_row = Some(start);
18677                    end_row = Some(end);
18678                } else {
18679                    // Merge two hunks.
18680                    *current_end = end;
18681                }
18682            } else {
18683                unreachable!();
18684            }
18685        }
18686        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18687        push_region(start_row, end_row);
18688        results
18689    }
18690
18691    pub fn gutter_highlights_in_range(
18692        &self,
18693        search_range: Range<Anchor>,
18694        display_snapshot: &DisplaySnapshot,
18695        cx: &App,
18696    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18697        let mut results = Vec::new();
18698        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18699            let color = color_fetcher(cx);
18700            let start_ix = match ranges.binary_search_by(|probe| {
18701                let cmp = probe
18702                    .end
18703                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18704                if cmp.is_gt() {
18705                    Ordering::Greater
18706                } else {
18707                    Ordering::Less
18708                }
18709            }) {
18710                Ok(i) | Err(i) => i,
18711            };
18712            for range in &ranges[start_ix..] {
18713                if range
18714                    .start
18715                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18716                    .is_ge()
18717                {
18718                    break;
18719                }
18720
18721                let start = range.start.to_display_point(display_snapshot);
18722                let end = range.end.to_display_point(display_snapshot);
18723                results.push((start..end, color))
18724            }
18725        }
18726        results
18727    }
18728
18729    /// Get the text ranges corresponding to the redaction query
18730    pub fn redacted_ranges(
18731        &self,
18732        search_range: Range<Anchor>,
18733        display_snapshot: &DisplaySnapshot,
18734        cx: &App,
18735    ) -> Vec<Range<DisplayPoint>> {
18736        display_snapshot
18737            .buffer_snapshot
18738            .redacted_ranges(search_range, |file| {
18739                if let Some(file) = file {
18740                    file.is_private()
18741                        && EditorSettings::get(
18742                            Some(SettingsLocation {
18743                                worktree_id: file.worktree_id(cx),
18744                                path: file.path().as_ref(),
18745                            }),
18746                            cx,
18747                        )
18748                        .redact_private_values
18749                } else {
18750                    false
18751                }
18752            })
18753            .map(|range| {
18754                range.start.to_display_point(display_snapshot)
18755                    ..range.end.to_display_point(display_snapshot)
18756            })
18757            .collect()
18758    }
18759
18760    pub fn highlight_text<T: 'static>(
18761        &mut self,
18762        ranges: Vec<Range<Anchor>>,
18763        style: HighlightStyle,
18764        cx: &mut Context<Self>,
18765    ) {
18766        self.display_map.update(cx, |map, _| {
18767            map.highlight_text(TypeId::of::<T>(), ranges, style)
18768        });
18769        cx.notify();
18770    }
18771
18772    pub(crate) fn highlight_inlays<T: 'static>(
18773        &mut self,
18774        highlights: Vec<InlayHighlight>,
18775        style: HighlightStyle,
18776        cx: &mut Context<Self>,
18777    ) {
18778        self.display_map.update(cx, |map, _| {
18779            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18780        });
18781        cx.notify();
18782    }
18783
18784    pub fn text_highlights<'a, T: 'static>(
18785        &'a self,
18786        cx: &'a App,
18787    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18788        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18789    }
18790
18791    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18792        let cleared = self
18793            .display_map
18794            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18795        if cleared {
18796            cx.notify();
18797        }
18798    }
18799
18800    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18801        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18802            && self.focus_handle.is_focused(window)
18803    }
18804
18805    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18806        self.show_cursor_when_unfocused = is_enabled;
18807        cx.notify();
18808    }
18809
18810    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18811        cx.notify();
18812    }
18813
18814    fn on_debug_session_event(
18815        &mut self,
18816        _session: Entity<Session>,
18817        event: &SessionEvent,
18818        cx: &mut Context<Self>,
18819    ) {
18820        match event {
18821            SessionEvent::InvalidateInlineValue => {
18822                self.refresh_inline_values(cx);
18823            }
18824            _ => {}
18825        }
18826    }
18827
18828    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18829        let Some(project) = self.project.clone() else {
18830            return;
18831        };
18832
18833        if !self.inline_value_cache.enabled {
18834            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18835            self.splice_inlays(&inlays, Vec::new(), cx);
18836            return;
18837        }
18838
18839        let current_execution_position = self
18840            .highlighted_rows
18841            .get(&TypeId::of::<ActiveDebugLine>())
18842            .and_then(|lines| lines.last().map(|line| line.range.start));
18843
18844        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18845            let inline_values = editor
18846                .update(cx, |editor, cx| {
18847                    let Some(current_execution_position) = current_execution_position else {
18848                        return Some(Task::ready(Ok(Vec::new())));
18849                    };
18850
18851                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18852                        let snapshot = buffer.snapshot(cx);
18853
18854                        let excerpt = snapshot.excerpt_containing(
18855                            current_execution_position..current_execution_position,
18856                        )?;
18857
18858                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18859                    })?;
18860
18861                    let range =
18862                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18863
18864                    project.inline_values(buffer, range, cx)
18865                })
18866                .ok()
18867                .flatten()?
18868                .await
18869                .context("refreshing debugger inlays")
18870                .log_err()?;
18871
18872            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18873
18874            for (buffer_id, inline_value) in inline_values
18875                .into_iter()
18876                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18877            {
18878                buffer_inline_values
18879                    .entry(buffer_id)
18880                    .or_default()
18881                    .push(inline_value);
18882            }
18883
18884            editor
18885                .update(cx, |editor, cx| {
18886                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18887                    let mut new_inlays = Vec::default();
18888
18889                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18890                        let buffer_id = buffer_snapshot.remote_id();
18891                        buffer_inline_values
18892                            .get(&buffer_id)
18893                            .into_iter()
18894                            .flatten()
18895                            .for_each(|hint| {
18896                                let inlay = Inlay::debugger_hint(
18897                                    post_inc(&mut editor.next_inlay_id),
18898                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18899                                    hint.text(),
18900                                );
18901
18902                                new_inlays.push(inlay);
18903                            });
18904                    }
18905
18906                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18907                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18908
18909                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18910                })
18911                .ok()?;
18912            Some(())
18913        });
18914    }
18915
18916    fn on_buffer_event(
18917        &mut self,
18918        multibuffer: &Entity<MultiBuffer>,
18919        event: &multi_buffer::Event,
18920        window: &mut Window,
18921        cx: &mut Context<Self>,
18922    ) {
18923        match event {
18924            multi_buffer::Event::Edited {
18925                singleton_buffer_edited,
18926                edited_buffer,
18927            } => {
18928                self.scrollbar_marker_state.dirty = true;
18929                self.active_indent_guides_state.dirty = true;
18930                self.refresh_active_diagnostics(cx);
18931                self.refresh_code_actions(window, cx);
18932                self.refresh_selected_text_highlights(true, window, cx);
18933                refresh_matching_bracket_highlights(self, window, cx);
18934                if self.has_active_inline_completion() {
18935                    self.update_visible_inline_completion(window, cx);
18936                }
18937                if let Some(project) = self.project.as_ref() {
18938                    if let Some(edited_buffer) = edited_buffer {
18939                        project.update(cx, |project, cx| {
18940                            self.registered_buffers
18941                                .entry(edited_buffer.read(cx).remote_id())
18942                                .or_insert_with(|| {
18943                                    project
18944                                        .register_buffer_with_language_servers(&edited_buffer, cx)
18945                                });
18946                        });
18947                        if edited_buffer.read(cx).file().is_some() {
18948                            self.pull_diagnostics(
18949                                Some(edited_buffer.read(cx).remote_id()),
18950                                window,
18951                                cx,
18952                            );
18953                        }
18954                    }
18955                }
18956                cx.emit(EditorEvent::BufferEdited);
18957                cx.emit(SearchEvent::MatchesInvalidated);
18958                if *singleton_buffer_edited {
18959                    if let Some(buffer) = edited_buffer {
18960                        if buffer.read(cx).file().is_none() {
18961                            cx.emit(EditorEvent::TitleChanged);
18962                        }
18963                    }
18964                    if let Some(project) = &self.project {
18965                        #[allow(clippy::mutable_key_type)]
18966                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18967                            multibuffer
18968                                .all_buffers()
18969                                .into_iter()
18970                                .filter_map(|buffer| {
18971                                    buffer.update(cx, |buffer, cx| {
18972                                        let language = buffer.language()?;
18973                                        let should_discard = project.update(cx, |project, cx| {
18974                                            project.is_local()
18975                                                && !project.has_language_servers_for(buffer, cx)
18976                                        });
18977                                        should_discard.not().then_some(language.clone())
18978                                    })
18979                                })
18980                                .collect::<HashSet<_>>()
18981                        });
18982                        if !languages_affected.is_empty() {
18983                            self.refresh_inlay_hints(
18984                                InlayHintRefreshReason::BufferEdited(languages_affected),
18985                                cx,
18986                            );
18987                        }
18988                    }
18989                }
18990
18991                let Some(project) = &self.project else { return };
18992                let (telemetry, is_via_ssh) = {
18993                    let project = project.read(cx);
18994                    let telemetry = project.client().telemetry().clone();
18995                    let is_via_ssh = project.is_via_ssh();
18996                    (telemetry, is_via_ssh)
18997                };
18998                refresh_linked_ranges(self, window, cx);
18999                telemetry.log_edit_event("editor", is_via_ssh);
19000            }
19001            multi_buffer::Event::ExcerptsAdded {
19002                buffer,
19003                predecessor,
19004                excerpts,
19005            } => {
19006                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19007                let buffer_id = buffer.read(cx).remote_id();
19008                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19009                    if let Some(project) = &self.project {
19010                        update_uncommitted_diff_for_buffer(
19011                            cx.entity(),
19012                            project,
19013                            [buffer.clone()],
19014                            self.buffer.clone(),
19015                            cx,
19016                        )
19017                        .detach();
19018                    }
19019                }
19020                cx.emit(EditorEvent::ExcerptsAdded {
19021                    buffer: buffer.clone(),
19022                    predecessor: *predecessor,
19023                    excerpts: excerpts.clone(),
19024                });
19025                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19026            }
19027            multi_buffer::Event::ExcerptsRemoved {
19028                ids,
19029                removed_buffer_ids,
19030            } => {
19031                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19032                let buffer = self.buffer.read(cx);
19033                self.registered_buffers
19034                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19035                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19036                cx.emit(EditorEvent::ExcerptsRemoved {
19037                    ids: ids.clone(),
19038                    removed_buffer_ids: removed_buffer_ids.clone(),
19039                })
19040            }
19041            multi_buffer::Event::ExcerptsEdited {
19042                excerpt_ids,
19043                buffer_ids,
19044            } => {
19045                self.display_map.update(cx, |map, cx| {
19046                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19047                });
19048                cx.emit(EditorEvent::ExcerptsEdited {
19049                    ids: excerpt_ids.clone(),
19050                })
19051            }
19052            multi_buffer::Event::ExcerptsExpanded { ids } => {
19053                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19054                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19055            }
19056            multi_buffer::Event::Reparsed(buffer_id) => {
19057                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19058                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19059
19060                cx.emit(EditorEvent::Reparsed(*buffer_id));
19061            }
19062            multi_buffer::Event::DiffHunksToggled => {
19063                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19064            }
19065            multi_buffer::Event::LanguageChanged(buffer_id) => {
19066                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19067                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19068                cx.emit(EditorEvent::Reparsed(*buffer_id));
19069                cx.notify();
19070            }
19071            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19072            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19073            multi_buffer::Event::FileHandleChanged
19074            | multi_buffer::Event::Reloaded
19075            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19076            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19077            multi_buffer::Event::DiagnosticsUpdated => {
19078                self.update_diagnostics_state(window, cx);
19079            }
19080            _ => {}
19081        };
19082    }
19083
19084    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19085        self.refresh_active_diagnostics(cx);
19086        self.refresh_inline_diagnostics(true, window, cx);
19087        self.scrollbar_marker_state.dirty = true;
19088        cx.notify();
19089    }
19090
19091    pub fn start_temporary_diff_override(&mut self) {
19092        self.load_diff_task.take();
19093        self.temporary_diff_override = true;
19094    }
19095
19096    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19097        self.temporary_diff_override = false;
19098        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19099        self.buffer.update(cx, |buffer, cx| {
19100            buffer.set_all_diff_hunks_collapsed(cx);
19101        });
19102
19103        if let Some(project) = self.project.clone() {
19104            self.load_diff_task = Some(
19105                update_uncommitted_diff_for_buffer(
19106                    cx.entity(),
19107                    &project,
19108                    self.buffer.read(cx).all_buffers(),
19109                    self.buffer.clone(),
19110                    cx,
19111                )
19112                .shared(),
19113            );
19114        }
19115    }
19116
19117    fn on_display_map_changed(
19118        &mut self,
19119        _: Entity<DisplayMap>,
19120        _: &mut Window,
19121        cx: &mut Context<Self>,
19122    ) {
19123        cx.notify();
19124    }
19125
19126    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19127        let new_severity = if self.diagnostics_enabled() {
19128            EditorSettings::get_global(cx)
19129                .diagnostics_max_severity
19130                .unwrap_or(DiagnosticSeverity::Hint)
19131        } else {
19132            DiagnosticSeverity::Off
19133        };
19134        self.set_max_diagnostics_severity(new_severity, cx);
19135        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19136        self.update_edit_prediction_settings(cx);
19137        self.refresh_inline_completion(true, false, window, cx);
19138        self.refresh_inlay_hints(
19139            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19140                self.selections.newest_anchor().head(),
19141                &self.buffer.read(cx).snapshot(cx),
19142                cx,
19143            )),
19144            cx,
19145        );
19146
19147        let old_cursor_shape = self.cursor_shape;
19148
19149        {
19150            let editor_settings = EditorSettings::get_global(cx);
19151            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19152            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19153            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19154            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19155            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19156        }
19157
19158        if old_cursor_shape != self.cursor_shape {
19159            cx.emit(EditorEvent::CursorShapeChanged);
19160        }
19161
19162        let project_settings = ProjectSettings::get_global(cx);
19163        self.serialize_dirty_buffers =
19164            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19165
19166        if self.mode.is_full() {
19167            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19168            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19169            if self.show_inline_diagnostics != show_inline_diagnostics {
19170                self.show_inline_diagnostics = show_inline_diagnostics;
19171                self.refresh_inline_diagnostics(false, window, cx);
19172            }
19173
19174            if self.git_blame_inline_enabled != inline_blame_enabled {
19175                self.toggle_git_blame_inline_internal(false, window, cx);
19176            }
19177
19178            let minimap_settings = EditorSettings::get_global(cx).minimap;
19179            if self.minimap_visibility != MinimapVisibility::Disabled {
19180                if self.minimap_visibility.settings_visibility()
19181                    != minimap_settings.minimap_enabled()
19182                {
19183                    self.set_minimap_visibility(
19184                        MinimapVisibility::for_mode(self.mode(), cx),
19185                        window,
19186                        cx,
19187                    );
19188                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19189                    minimap_entity.update(cx, |minimap_editor, cx| {
19190                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19191                    })
19192                }
19193            }
19194        }
19195
19196        cx.notify();
19197    }
19198
19199    pub fn set_searchable(&mut self, searchable: bool) {
19200        self.searchable = searchable;
19201    }
19202
19203    pub fn searchable(&self) -> bool {
19204        self.searchable
19205    }
19206
19207    fn open_proposed_changes_editor(
19208        &mut self,
19209        _: &OpenProposedChangesEditor,
19210        window: &mut Window,
19211        cx: &mut Context<Self>,
19212    ) {
19213        let Some(workspace) = self.workspace() else {
19214            cx.propagate();
19215            return;
19216        };
19217
19218        let selections = self.selections.all::<usize>(cx);
19219        let multi_buffer = self.buffer.read(cx);
19220        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19221        let mut new_selections_by_buffer = HashMap::default();
19222        for selection in selections {
19223            for (buffer, range, _) in
19224                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19225            {
19226                let mut range = range.to_point(buffer);
19227                range.start.column = 0;
19228                range.end.column = buffer.line_len(range.end.row);
19229                new_selections_by_buffer
19230                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19231                    .or_insert(Vec::new())
19232                    .push(range)
19233            }
19234        }
19235
19236        let proposed_changes_buffers = new_selections_by_buffer
19237            .into_iter()
19238            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19239            .collect::<Vec<_>>();
19240        let proposed_changes_editor = cx.new(|cx| {
19241            ProposedChangesEditor::new(
19242                "Proposed changes",
19243                proposed_changes_buffers,
19244                self.project.clone(),
19245                window,
19246                cx,
19247            )
19248        });
19249
19250        window.defer(cx, move |window, cx| {
19251            workspace.update(cx, |workspace, cx| {
19252                workspace.active_pane().update(cx, |pane, cx| {
19253                    pane.add_item(
19254                        Box::new(proposed_changes_editor),
19255                        true,
19256                        true,
19257                        None,
19258                        window,
19259                        cx,
19260                    );
19261                });
19262            });
19263        });
19264    }
19265
19266    pub fn open_excerpts_in_split(
19267        &mut self,
19268        _: &OpenExcerptsSplit,
19269        window: &mut Window,
19270        cx: &mut Context<Self>,
19271    ) {
19272        self.open_excerpts_common(None, true, window, cx)
19273    }
19274
19275    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19276        self.open_excerpts_common(None, false, window, cx)
19277    }
19278
19279    fn open_excerpts_common(
19280        &mut self,
19281        jump_data: Option<JumpData>,
19282        split: bool,
19283        window: &mut Window,
19284        cx: &mut Context<Self>,
19285    ) {
19286        let Some(workspace) = self.workspace() else {
19287            cx.propagate();
19288            return;
19289        };
19290
19291        if self.buffer.read(cx).is_singleton() {
19292            cx.propagate();
19293            return;
19294        }
19295
19296        let mut new_selections_by_buffer = HashMap::default();
19297        match &jump_data {
19298            Some(JumpData::MultiBufferPoint {
19299                excerpt_id,
19300                position,
19301                anchor,
19302                line_offset_from_top,
19303            }) => {
19304                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19305                if let Some(buffer) = multi_buffer_snapshot
19306                    .buffer_id_for_excerpt(*excerpt_id)
19307                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19308                {
19309                    let buffer_snapshot = buffer.read(cx).snapshot();
19310                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19311                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19312                    } else {
19313                        buffer_snapshot.clip_point(*position, Bias::Left)
19314                    };
19315                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19316                    new_selections_by_buffer.insert(
19317                        buffer,
19318                        (
19319                            vec![jump_to_offset..jump_to_offset],
19320                            Some(*line_offset_from_top),
19321                        ),
19322                    );
19323                }
19324            }
19325            Some(JumpData::MultiBufferRow {
19326                row,
19327                line_offset_from_top,
19328            }) => {
19329                let point = MultiBufferPoint::new(row.0, 0);
19330                if let Some((buffer, buffer_point, _)) =
19331                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19332                {
19333                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19334                    new_selections_by_buffer
19335                        .entry(buffer)
19336                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19337                        .0
19338                        .push(buffer_offset..buffer_offset)
19339                }
19340            }
19341            None => {
19342                let selections = self.selections.all::<usize>(cx);
19343                let multi_buffer = self.buffer.read(cx);
19344                for selection in selections {
19345                    for (snapshot, range, _, anchor) in multi_buffer
19346                        .snapshot(cx)
19347                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19348                    {
19349                        if let Some(anchor) = anchor {
19350                            // selection is in a deleted hunk
19351                            let Some(buffer_id) = anchor.buffer_id else {
19352                                continue;
19353                            };
19354                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19355                                continue;
19356                            };
19357                            let offset = text::ToOffset::to_offset(
19358                                &anchor.text_anchor,
19359                                &buffer_handle.read(cx).snapshot(),
19360                            );
19361                            let range = offset..offset;
19362                            new_selections_by_buffer
19363                                .entry(buffer_handle)
19364                                .or_insert((Vec::new(), None))
19365                                .0
19366                                .push(range)
19367                        } else {
19368                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19369                            else {
19370                                continue;
19371                            };
19372                            new_selections_by_buffer
19373                                .entry(buffer_handle)
19374                                .or_insert((Vec::new(), None))
19375                                .0
19376                                .push(range)
19377                        }
19378                    }
19379                }
19380            }
19381        }
19382
19383        new_selections_by_buffer
19384            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19385
19386        if new_selections_by_buffer.is_empty() {
19387            return;
19388        }
19389
19390        // We defer the pane interaction because we ourselves are a workspace item
19391        // and activating a new item causes the pane to call a method on us reentrantly,
19392        // which panics if we're on the stack.
19393        window.defer(cx, move |window, cx| {
19394            workspace.update(cx, |workspace, cx| {
19395                let pane = if split {
19396                    workspace.adjacent_pane(window, cx)
19397                } else {
19398                    workspace.active_pane().clone()
19399                };
19400
19401                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19402                    let editor = buffer
19403                        .read(cx)
19404                        .file()
19405                        .is_none()
19406                        .then(|| {
19407                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19408                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19409                            // Instead, we try to activate the existing editor in the pane first.
19410                            let (editor, pane_item_index) =
19411                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19412                                    let editor = item.downcast::<Editor>()?;
19413                                    let singleton_buffer =
19414                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19415                                    if singleton_buffer == buffer {
19416                                        Some((editor, i))
19417                                    } else {
19418                                        None
19419                                    }
19420                                })?;
19421                            pane.update(cx, |pane, cx| {
19422                                pane.activate_item(pane_item_index, true, true, window, cx)
19423                            });
19424                            Some(editor)
19425                        })
19426                        .flatten()
19427                        .unwrap_or_else(|| {
19428                            workspace.open_project_item::<Self>(
19429                                pane.clone(),
19430                                buffer,
19431                                true,
19432                                true,
19433                                window,
19434                                cx,
19435                            )
19436                        });
19437
19438                    editor.update(cx, |editor, cx| {
19439                        let autoscroll = match scroll_offset {
19440                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19441                            None => Autoscroll::newest(),
19442                        };
19443                        let nav_history = editor.nav_history.take();
19444                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19445                            s.select_ranges(ranges);
19446                        });
19447                        editor.nav_history = nav_history;
19448                    });
19449                }
19450            })
19451        });
19452    }
19453
19454    // For now, don't allow opening excerpts in buffers that aren't backed by
19455    // regular project files.
19456    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19457        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19458    }
19459
19460    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19461        let snapshot = self.buffer.read(cx).read(cx);
19462        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19463        Some(
19464            ranges
19465                .iter()
19466                .map(move |range| {
19467                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19468                })
19469                .collect(),
19470        )
19471    }
19472
19473    fn selection_replacement_ranges(
19474        &self,
19475        range: Range<OffsetUtf16>,
19476        cx: &mut App,
19477    ) -> Vec<Range<OffsetUtf16>> {
19478        let selections = self.selections.all::<OffsetUtf16>(cx);
19479        let newest_selection = selections
19480            .iter()
19481            .max_by_key(|selection| selection.id)
19482            .unwrap();
19483        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19484        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19485        let snapshot = self.buffer.read(cx).read(cx);
19486        selections
19487            .into_iter()
19488            .map(|mut selection| {
19489                selection.start.0 =
19490                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19491                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19492                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19493                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19494            })
19495            .collect()
19496    }
19497
19498    fn report_editor_event(
19499        &self,
19500        event_type: &'static str,
19501        file_extension: Option<String>,
19502        cx: &App,
19503    ) {
19504        if cfg!(any(test, feature = "test-support")) {
19505            return;
19506        }
19507
19508        let Some(project) = &self.project else { return };
19509
19510        // If None, we are in a file without an extension
19511        let file = self
19512            .buffer
19513            .read(cx)
19514            .as_singleton()
19515            .and_then(|b| b.read(cx).file());
19516        let file_extension = file_extension.or(file
19517            .as_ref()
19518            .and_then(|file| Path::new(file.file_name(cx)).extension())
19519            .and_then(|e| e.to_str())
19520            .map(|a| a.to_string()));
19521
19522        let vim_mode = vim_enabled(cx);
19523
19524        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19525        let copilot_enabled = edit_predictions_provider
19526            == language::language_settings::EditPredictionProvider::Copilot;
19527        let copilot_enabled_for_language = self
19528            .buffer
19529            .read(cx)
19530            .language_settings(cx)
19531            .show_edit_predictions;
19532
19533        let project = project.read(cx);
19534        telemetry::event!(
19535            event_type,
19536            file_extension,
19537            vim_mode,
19538            copilot_enabled,
19539            copilot_enabled_for_language,
19540            edit_predictions_provider,
19541            is_via_ssh = project.is_via_ssh(),
19542        );
19543    }
19544
19545    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19546    /// with each line being an array of {text, highlight} objects.
19547    fn copy_highlight_json(
19548        &mut self,
19549        _: &CopyHighlightJson,
19550        window: &mut Window,
19551        cx: &mut Context<Self>,
19552    ) {
19553        #[derive(Serialize)]
19554        struct Chunk<'a> {
19555            text: String,
19556            highlight: Option<&'a str>,
19557        }
19558
19559        let snapshot = self.buffer.read(cx).snapshot(cx);
19560        let range = self
19561            .selected_text_range(false, window, cx)
19562            .and_then(|selection| {
19563                if selection.range.is_empty() {
19564                    None
19565                } else {
19566                    Some(selection.range)
19567                }
19568            })
19569            .unwrap_or_else(|| 0..snapshot.len());
19570
19571        let chunks = snapshot.chunks(range, true);
19572        let mut lines = Vec::new();
19573        let mut line: VecDeque<Chunk> = VecDeque::new();
19574
19575        let Some(style) = self.style.as_ref() else {
19576            return;
19577        };
19578
19579        for chunk in chunks {
19580            let highlight = chunk
19581                .syntax_highlight_id
19582                .and_then(|id| id.name(&style.syntax));
19583            let mut chunk_lines = chunk.text.split('\n').peekable();
19584            while let Some(text) = chunk_lines.next() {
19585                let mut merged_with_last_token = false;
19586                if let Some(last_token) = line.back_mut() {
19587                    if last_token.highlight == highlight {
19588                        last_token.text.push_str(text);
19589                        merged_with_last_token = true;
19590                    }
19591                }
19592
19593                if !merged_with_last_token {
19594                    line.push_back(Chunk {
19595                        text: text.into(),
19596                        highlight,
19597                    });
19598                }
19599
19600                if chunk_lines.peek().is_some() {
19601                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19602                        line.pop_front();
19603                    }
19604                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19605                        line.pop_back();
19606                    }
19607
19608                    lines.push(mem::take(&mut line));
19609                }
19610            }
19611        }
19612
19613        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19614            return;
19615        };
19616        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19617    }
19618
19619    pub fn open_context_menu(
19620        &mut self,
19621        _: &OpenContextMenu,
19622        window: &mut Window,
19623        cx: &mut Context<Self>,
19624    ) {
19625        self.request_autoscroll(Autoscroll::newest(), cx);
19626        let position = self.selections.newest_display(cx).start;
19627        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19628    }
19629
19630    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19631        &self.inlay_hint_cache
19632    }
19633
19634    pub fn replay_insert_event(
19635        &mut self,
19636        text: &str,
19637        relative_utf16_range: Option<Range<isize>>,
19638        window: &mut Window,
19639        cx: &mut Context<Self>,
19640    ) {
19641        if !self.input_enabled {
19642            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19643            return;
19644        }
19645        if let Some(relative_utf16_range) = relative_utf16_range {
19646            let selections = self.selections.all::<OffsetUtf16>(cx);
19647            self.change_selections(None, window, cx, |s| {
19648                let new_ranges = selections.into_iter().map(|range| {
19649                    let start = OffsetUtf16(
19650                        range
19651                            .head()
19652                            .0
19653                            .saturating_add_signed(relative_utf16_range.start),
19654                    );
19655                    let end = OffsetUtf16(
19656                        range
19657                            .head()
19658                            .0
19659                            .saturating_add_signed(relative_utf16_range.end),
19660                    );
19661                    start..end
19662                });
19663                s.select_ranges(new_ranges);
19664            });
19665        }
19666
19667        self.handle_input(text, window, cx);
19668    }
19669
19670    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19671        let Some(provider) = self.semantics_provider.as_ref() else {
19672            return false;
19673        };
19674
19675        let mut supports = false;
19676        self.buffer().update(cx, |this, cx| {
19677            this.for_each_buffer(|buffer| {
19678                supports |= provider.supports_inlay_hints(buffer, cx);
19679            });
19680        });
19681
19682        supports
19683    }
19684
19685    pub fn is_focused(&self, window: &Window) -> bool {
19686        self.focus_handle.is_focused(window)
19687    }
19688
19689    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19690        cx.emit(EditorEvent::Focused);
19691
19692        if let Some(descendant) = self
19693            .last_focused_descendant
19694            .take()
19695            .and_then(|descendant| descendant.upgrade())
19696        {
19697            window.focus(&descendant);
19698        } else {
19699            if let Some(blame) = self.blame.as_ref() {
19700                blame.update(cx, GitBlame::focus)
19701            }
19702
19703            self.blink_manager.update(cx, BlinkManager::enable);
19704            self.show_cursor_names(window, cx);
19705            self.buffer.update(cx, |buffer, cx| {
19706                buffer.finalize_last_transaction(cx);
19707                if self.leader_id.is_none() {
19708                    buffer.set_active_selections(
19709                        &self.selections.disjoint_anchors(),
19710                        self.selections.line_mode,
19711                        self.cursor_shape,
19712                        cx,
19713                    );
19714                }
19715            });
19716        }
19717    }
19718
19719    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19720        cx.emit(EditorEvent::FocusedIn)
19721    }
19722
19723    fn handle_focus_out(
19724        &mut self,
19725        event: FocusOutEvent,
19726        _window: &mut Window,
19727        cx: &mut Context<Self>,
19728    ) {
19729        if event.blurred != self.focus_handle {
19730            self.last_focused_descendant = Some(event.blurred);
19731        }
19732        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19733    }
19734
19735    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19736        self.blink_manager.update(cx, BlinkManager::disable);
19737        self.buffer
19738            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19739
19740        if let Some(blame) = self.blame.as_ref() {
19741            blame.update(cx, GitBlame::blur)
19742        }
19743        if !self.hover_state.focused(window, cx) {
19744            hide_hover(self, cx);
19745        }
19746        if !self
19747            .context_menu
19748            .borrow()
19749            .as_ref()
19750            .is_some_and(|context_menu| context_menu.focused(window, cx))
19751        {
19752            self.hide_context_menu(window, cx);
19753        }
19754        self.discard_inline_completion(false, cx);
19755        cx.emit(EditorEvent::Blurred);
19756        cx.notify();
19757    }
19758
19759    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19760        let mut pending: String = window
19761            .pending_input_keystrokes()
19762            .into_iter()
19763            .flatten()
19764            .filter_map(|keystroke| {
19765                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19766                    keystroke.key_char.clone()
19767                } else {
19768                    None
19769                }
19770            })
19771            .collect();
19772
19773        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19774            pending = "".to_string();
19775        }
19776
19777        let existing_pending = self
19778            .text_highlights::<PendingInput>(cx)
19779            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
19780        if existing_pending.is_none() && pending.is_empty() {
19781            return;
19782        }
19783        let transaction =
19784            self.transact(window, cx, |this, window, cx| {
19785                let selections = this.selections.all::<usize>(cx);
19786                let edits = selections
19787                    .iter()
19788                    .map(|selection| (selection.end..selection.end, pending.clone()));
19789                this.edit(edits, cx);
19790                this.change_selections(None, window, cx, |s| {
19791                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19792                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19793                    }));
19794                });
19795                if let Some(existing_ranges) = existing_pending {
19796                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19797                    this.edit(edits, cx);
19798                }
19799            });
19800
19801        let snapshot = self.snapshot(window, cx);
19802        let ranges = self
19803            .selections
19804            .all::<usize>(cx)
19805            .into_iter()
19806            .map(|selection| {
19807                snapshot.buffer_snapshot.anchor_after(selection.end)
19808                    ..snapshot
19809                        .buffer_snapshot
19810                        .anchor_before(selection.end + pending.len())
19811            })
19812            .collect();
19813
19814        if pending.is_empty() {
19815            self.clear_highlights::<PendingInput>(cx);
19816        } else {
19817            self.highlight_text::<PendingInput>(
19818                ranges,
19819                HighlightStyle {
19820                    underline: Some(UnderlineStyle {
19821                        thickness: px(1.),
19822                        color: None,
19823                        wavy: false,
19824                    }),
19825                    ..Default::default()
19826                },
19827                cx,
19828            );
19829        }
19830
19831        self.ime_transaction = self.ime_transaction.or(transaction);
19832        if let Some(transaction) = self.ime_transaction {
19833            self.buffer.update(cx, |buffer, cx| {
19834                buffer.group_until_transaction(transaction, cx);
19835            });
19836        }
19837
19838        if self.text_highlights::<PendingInput>(cx).is_none() {
19839            self.ime_transaction.take();
19840        }
19841    }
19842
19843    pub fn register_action_renderer(
19844        &mut self,
19845        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
19846    ) -> Subscription {
19847        let id = self.next_editor_action_id.post_inc();
19848        self.editor_actions
19849            .borrow_mut()
19850            .insert(id, Box::new(listener));
19851
19852        let editor_actions = self.editor_actions.clone();
19853        Subscription::new(move || {
19854            editor_actions.borrow_mut().remove(&id);
19855        })
19856    }
19857
19858    pub fn register_action<A: Action>(
19859        &mut self,
19860        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19861    ) -> Subscription {
19862        let id = self.next_editor_action_id.post_inc();
19863        let listener = Arc::new(listener);
19864        self.editor_actions.borrow_mut().insert(
19865            id,
19866            Box::new(move |_, window, _| {
19867                let listener = listener.clone();
19868                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19869                    let action = action.downcast_ref().unwrap();
19870                    if phase == DispatchPhase::Bubble {
19871                        listener(action, window, cx)
19872                    }
19873                })
19874            }),
19875        );
19876
19877        let editor_actions = self.editor_actions.clone();
19878        Subscription::new(move || {
19879            editor_actions.borrow_mut().remove(&id);
19880        })
19881    }
19882
19883    pub fn file_header_size(&self) -> u32 {
19884        FILE_HEADER_HEIGHT
19885    }
19886
19887    pub fn restore(
19888        &mut self,
19889        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19890        window: &mut Window,
19891        cx: &mut Context<Self>,
19892    ) {
19893        let workspace = self.workspace();
19894        let project = self.project.as_ref();
19895        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19896            let mut tasks = Vec::new();
19897            for (buffer_id, changes) in revert_changes {
19898                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19899                    buffer.update(cx, |buffer, cx| {
19900                        buffer.edit(
19901                            changes
19902                                .into_iter()
19903                                .map(|(range, text)| (range, text.to_string())),
19904                            None,
19905                            cx,
19906                        );
19907                    });
19908
19909                    if let Some(project) =
19910                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19911                    {
19912                        project.update(cx, |project, cx| {
19913                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19914                        })
19915                    }
19916                }
19917            }
19918            tasks
19919        });
19920        cx.spawn_in(window, async move |_, cx| {
19921            for (buffer, task) in save_tasks {
19922                let result = task.await;
19923                if result.is_err() {
19924                    let Some(path) = buffer
19925                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19926                        .ok()
19927                    else {
19928                        continue;
19929                    };
19930                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19931                        let Some(task) = cx
19932                            .update_window_entity(&workspace, |workspace, window, cx| {
19933                                workspace
19934                                    .open_path_preview(path, None, false, false, false, window, cx)
19935                            })
19936                            .ok()
19937                        else {
19938                            continue;
19939                        };
19940                        task.await.log_err();
19941                    }
19942                }
19943            }
19944        })
19945        .detach();
19946        self.change_selections(None, window, cx, |selections| selections.refresh());
19947    }
19948
19949    pub fn to_pixel_point(
19950        &self,
19951        source: multi_buffer::Anchor,
19952        editor_snapshot: &EditorSnapshot,
19953        window: &mut Window,
19954    ) -> Option<gpui::Point<Pixels>> {
19955        let source_point = source.to_display_point(editor_snapshot);
19956        self.display_to_pixel_point(source_point, editor_snapshot, window)
19957    }
19958
19959    pub fn display_to_pixel_point(
19960        &self,
19961        source: DisplayPoint,
19962        editor_snapshot: &EditorSnapshot,
19963        window: &mut Window,
19964    ) -> Option<gpui::Point<Pixels>> {
19965        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19966        let text_layout_details = self.text_layout_details(window);
19967        let scroll_top = text_layout_details
19968            .scroll_anchor
19969            .scroll_position(editor_snapshot)
19970            .y;
19971
19972        if source.row().as_f32() < scroll_top.floor() {
19973            return None;
19974        }
19975        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19976        let source_y = line_height * (source.row().as_f32() - scroll_top);
19977        Some(gpui::Point::new(source_x, source_y))
19978    }
19979
19980    pub fn has_visible_completions_menu(&self) -> bool {
19981        !self.edit_prediction_preview_is_active()
19982            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19983                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19984            })
19985    }
19986
19987    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19988        if self.mode.is_minimap() {
19989            return;
19990        }
19991        self.addons
19992            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19993    }
19994
19995    pub fn unregister_addon<T: Addon>(&mut self) {
19996        self.addons.remove(&std::any::TypeId::of::<T>());
19997    }
19998
19999    pub fn addon<T: Addon>(&self) -> Option<&T> {
20000        let type_id = std::any::TypeId::of::<T>();
20001        self.addons
20002            .get(&type_id)
20003            .and_then(|item| item.to_any().downcast_ref::<T>())
20004    }
20005
20006    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20007        let type_id = std::any::TypeId::of::<T>();
20008        self.addons
20009            .get_mut(&type_id)
20010            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20011    }
20012
20013    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20014        let text_layout_details = self.text_layout_details(window);
20015        let style = &text_layout_details.editor_style;
20016        let font_id = window.text_system().resolve_font(&style.text.font());
20017        let font_size = style.text.font_size.to_pixels(window.rem_size());
20018        let line_height = style.text.line_height_in_pixels(window.rem_size());
20019        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20020
20021        gpui::Size::new(em_width, line_height)
20022    }
20023
20024    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20025        self.load_diff_task.clone()
20026    }
20027
20028    fn read_metadata_from_db(
20029        &mut self,
20030        item_id: u64,
20031        workspace_id: WorkspaceId,
20032        window: &mut Window,
20033        cx: &mut Context<Editor>,
20034    ) {
20035        if self.is_singleton(cx)
20036            && !self.mode.is_minimap()
20037            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20038        {
20039            let buffer_snapshot = OnceCell::new();
20040
20041            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20042                if !folds.is_empty() {
20043                    let snapshot =
20044                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20045                    self.fold_ranges(
20046                        folds
20047                            .into_iter()
20048                            .map(|(start, end)| {
20049                                snapshot.clip_offset(start, Bias::Left)
20050                                    ..snapshot.clip_offset(end, Bias::Right)
20051                            })
20052                            .collect(),
20053                        false,
20054                        window,
20055                        cx,
20056                    );
20057                }
20058            }
20059
20060            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20061                if !selections.is_empty() {
20062                    let snapshot =
20063                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20064                    // skip adding the initial selection to selection history
20065                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20066                    self.change_selections(None, window, cx, |s| {
20067                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20068                            snapshot.clip_offset(start, Bias::Left)
20069                                ..snapshot.clip_offset(end, Bias::Right)
20070                        }));
20071                    });
20072                    self.selection_history.mode = SelectionHistoryMode::Normal;
20073                }
20074            };
20075        }
20076
20077        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20078    }
20079}
20080
20081fn vim_enabled(cx: &App) -> bool {
20082    cx.global::<SettingsStore>()
20083        .raw_user_settings()
20084        .get("vim_mode")
20085        == Some(&serde_json::Value::Bool(true))
20086}
20087
20088fn process_completion_for_edit(
20089    completion: &Completion,
20090    intent: CompletionIntent,
20091    buffer: &Entity<Buffer>,
20092    cursor_position: &text::Anchor,
20093    cx: &mut Context<Editor>,
20094) -> CompletionEdit {
20095    let buffer = buffer.read(cx);
20096    let buffer_snapshot = buffer.snapshot();
20097    let (snippet, new_text) = if completion.is_snippet() {
20098        // Workaround for typescript language server issues so that methods don't expand within
20099        // strings and functions with type expressions. The previous point is used because the query
20100        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20101        let mut snippet_source = completion.new_text.clone();
20102        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20103        previous_point.column = previous_point.column.saturating_sub(1);
20104        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20105            if scope.prefers_label_for_snippet_in_completion() {
20106                if let Some(label) = completion.label() {
20107                    if matches!(
20108                        completion.kind(),
20109                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20110                    ) {
20111                        snippet_source = label;
20112                    }
20113                }
20114            }
20115        }
20116        match Snippet::parse(&snippet_source).log_err() {
20117            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20118            None => (None, completion.new_text.clone()),
20119        }
20120    } else {
20121        (None, completion.new_text.clone())
20122    };
20123
20124    let mut range_to_replace = {
20125        let replace_range = &completion.replace_range;
20126        if let CompletionSource::Lsp {
20127            insert_range: Some(insert_range),
20128            ..
20129        } = &completion.source
20130        {
20131            debug_assert_eq!(
20132                insert_range.start, replace_range.start,
20133                "insert_range and replace_range should start at the same position"
20134            );
20135            debug_assert!(
20136                insert_range
20137                    .start
20138                    .cmp(&cursor_position, &buffer_snapshot)
20139                    .is_le(),
20140                "insert_range should start before or at cursor position"
20141            );
20142            debug_assert!(
20143                replace_range
20144                    .start
20145                    .cmp(&cursor_position, &buffer_snapshot)
20146                    .is_le(),
20147                "replace_range should start before or at cursor position"
20148            );
20149            debug_assert!(
20150                insert_range
20151                    .end
20152                    .cmp(&cursor_position, &buffer_snapshot)
20153                    .is_le(),
20154                "insert_range should end before or at cursor position"
20155            );
20156
20157            let should_replace = match intent {
20158                CompletionIntent::CompleteWithInsert => false,
20159                CompletionIntent::CompleteWithReplace => true,
20160                CompletionIntent::Complete | CompletionIntent::Compose => {
20161                    let insert_mode =
20162                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20163                            .completions
20164                            .lsp_insert_mode;
20165                    match insert_mode {
20166                        LspInsertMode::Insert => false,
20167                        LspInsertMode::Replace => true,
20168                        LspInsertMode::ReplaceSubsequence => {
20169                            let mut text_to_replace = buffer.chars_for_range(
20170                                buffer.anchor_before(replace_range.start)
20171                                    ..buffer.anchor_after(replace_range.end),
20172                            );
20173                            let mut current_needle = text_to_replace.next();
20174                            for haystack_ch in completion.label.text.chars() {
20175                                if let Some(needle_ch) = current_needle {
20176                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20177                                        current_needle = text_to_replace.next();
20178                                    }
20179                                }
20180                            }
20181                            current_needle.is_none()
20182                        }
20183                        LspInsertMode::ReplaceSuffix => {
20184                            if replace_range
20185                                .end
20186                                .cmp(&cursor_position, &buffer_snapshot)
20187                                .is_gt()
20188                            {
20189                                let range_after_cursor = *cursor_position..replace_range.end;
20190                                let text_after_cursor = buffer
20191                                    .text_for_range(
20192                                        buffer.anchor_before(range_after_cursor.start)
20193                                            ..buffer.anchor_after(range_after_cursor.end),
20194                                    )
20195                                    .collect::<String>()
20196                                    .to_ascii_lowercase();
20197                                completion
20198                                    .label
20199                                    .text
20200                                    .to_ascii_lowercase()
20201                                    .ends_with(&text_after_cursor)
20202                            } else {
20203                                true
20204                            }
20205                        }
20206                    }
20207                }
20208            };
20209
20210            if should_replace {
20211                replace_range.clone()
20212            } else {
20213                insert_range.clone()
20214            }
20215        } else {
20216            replace_range.clone()
20217        }
20218    };
20219
20220    if range_to_replace
20221        .end
20222        .cmp(&cursor_position, &buffer_snapshot)
20223        .is_lt()
20224    {
20225        range_to_replace.end = *cursor_position;
20226    }
20227
20228    CompletionEdit {
20229        new_text,
20230        replace_range: range_to_replace.to_offset(&buffer),
20231        snippet,
20232    }
20233}
20234
20235struct CompletionEdit {
20236    new_text: String,
20237    replace_range: Range<usize>,
20238    snippet: Option<Snippet>,
20239}
20240
20241fn insert_extra_newline_brackets(
20242    buffer: &MultiBufferSnapshot,
20243    range: Range<usize>,
20244    language: &language::LanguageScope,
20245) -> bool {
20246    let leading_whitespace_len = buffer
20247        .reversed_chars_at(range.start)
20248        .take_while(|c| c.is_whitespace() && *c != '\n')
20249        .map(|c| c.len_utf8())
20250        .sum::<usize>();
20251    let trailing_whitespace_len = buffer
20252        .chars_at(range.end)
20253        .take_while(|c| c.is_whitespace() && *c != '\n')
20254        .map(|c| c.len_utf8())
20255        .sum::<usize>();
20256    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20257
20258    language.brackets().any(|(pair, enabled)| {
20259        let pair_start = pair.start.trim_end();
20260        let pair_end = pair.end.trim_start();
20261
20262        enabled
20263            && pair.newline
20264            && buffer.contains_str_at(range.end, pair_end)
20265            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20266    })
20267}
20268
20269fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20270    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20271        [(buffer, range, _)] => (*buffer, range.clone()),
20272        _ => return false,
20273    };
20274    let pair = {
20275        let mut result: Option<BracketMatch> = None;
20276
20277        for pair in buffer
20278            .all_bracket_ranges(range.clone())
20279            .filter(move |pair| {
20280                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20281            })
20282        {
20283            let len = pair.close_range.end - pair.open_range.start;
20284
20285            if let Some(existing) = &result {
20286                let existing_len = existing.close_range.end - existing.open_range.start;
20287                if len > existing_len {
20288                    continue;
20289                }
20290            }
20291
20292            result = Some(pair);
20293        }
20294
20295        result
20296    };
20297    let Some(pair) = pair else {
20298        return false;
20299    };
20300    pair.newline_only
20301        && buffer
20302            .chars_for_range(pair.open_range.end..range.start)
20303            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20304            .all(|c| c.is_whitespace() && c != '\n')
20305}
20306
20307fn update_uncommitted_diff_for_buffer(
20308    editor: Entity<Editor>,
20309    project: &Entity<Project>,
20310    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20311    buffer: Entity<MultiBuffer>,
20312    cx: &mut App,
20313) -> Task<()> {
20314    let mut tasks = Vec::new();
20315    project.update(cx, |project, cx| {
20316        for buffer in buffers {
20317            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20318                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20319            }
20320        }
20321    });
20322    cx.spawn(async move |cx| {
20323        let diffs = future::join_all(tasks).await;
20324        if editor
20325            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20326            .unwrap_or(false)
20327        {
20328            return;
20329        }
20330
20331        buffer
20332            .update(cx, |buffer, cx| {
20333                for diff in diffs.into_iter().flatten() {
20334                    buffer.add_diff(diff, cx);
20335                }
20336            })
20337            .ok();
20338    })
20339}
20340
20341fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20342    let tab_size = tab_size.get() as usize;
20343    let mut width = offset;
20344
20345    for ch in text.chars() {
20346        width += if ch == '\t' {
20347            tab_size - (width % tab_size)
20348        } else {
20349            1
20350        };
20351    }
20352
20353    width - offset
20354}
20355
20356#[cfg(test)]
20357mod tests {
20358    use super::*;
20359
20360    #[test]
20361    fn test_string_size_with_expanded_tabs() {
20362        let nz = |val| NonZeroU32::new(val).unwrap();
20363        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20364        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20365        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20366        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20367        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20368        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20369        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20370        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20371    }
20372}
20373
20374/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20375struct WordBreakingTokenizer<'a> {
20376    input: &'a str,
20377}
20378
20379impl<'a> WordBreakingTokenizer<'a> {
20380    fn new(input: &'a str) -> Self {
20381        Self { input }
20382    }
20383}
20384
20385fn is_char_ideographic(ch: char) -> bool {
20386    use unicode_script::Script::*;
20387    use unicode_script::UnicodeScript;
20388    matches!(ch.script(), Han | Tangut | Yi)
20389}
20390
20391fn is_grapheme_ideographic(text: &str) -> bool {
20392    text.chars().any(is_char_ideographic)
20393}
20394
20395fn is_grapheme_whitespace(text: &str) -> bool {
20396    text.chars().any(|x| x.is_whitespace())
20397}
20398
20399fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20400    text.chars().next().map_or(false, |ch| {
20401        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20402    })
20403}
20404
20405#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20406enum WordBreakToken<'a> {
20407    Word { token: &'a str, grapheme_len: usize },
20408    InlineWhitespace { token: &'a str, grapheme_len: usize },
20409    Newline,
20410}
20411
20412impl<'a> Iterator for WordBreakingTokenizer<'a> {
20413    /// Yields a span, the count of graphemes in the token, and whether it was
20414    /// whitespace. Note that it also breaks at word boundaries.
20415    type Item = WordBreakToken<'a>;
20416
20417    fn next(&mut self) -> Option<Self::Item> {
20418        use unicode_segmentation::UnicodeSegmentation;
20419        if self.input.is_empty() {
20420            return None;
20421        }
20422
20423        let mut iter = self.input.graphemes(true).peekable();
20424        let mut offset = 0;
20425        let mut grapheme_len = 0;
20426        if let Some(first_grapheme) = iter.next() {
20427            let is_newline = first_grapheme == "\n";
20428            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20429            offset += first_grapheme.len();
20430            grapheme_len += 1;
20431            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20432                if let Some(grapheme) = iter.peek().copied() {
20433                    if should_stay_with_preceding_ideograph(grapheme) {
20434                        offset += grapheme.len();
20435                        grapheme_len += 1;
20436                    }
20437                }
20438            } else {
20439                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20440                let mut next_word_bound = words.peek().copied();
20441                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20442                    next_word_bound = words.next();
20443                }
20444                while let Some(grapheme) = iter.peek().copied() {
20445                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20446                        break;
20447                    };
20448                    if is_grapheme_whitespace(grapheme) != is_whitespace
20449                        || (grapheme == "\n") != is_newline
20450                    {
20451                        break;
20452                    };
20453                    offset += grapheme.len();
20454                    grapheme_len += 1;
20455                    iter.next();
20456                }
20457            }
20458            let token = &self.input[..offset];
20459            self.input = &self.input[offset..];
20460            if token == "\n" {
20461                Some(WordBreakToken::Newline)
20462            } else if is_whitespace {
20463                Some(WordBreakToken::InlineWhitespace {
20464                    token,
20465                    grapheme_len,
20466                })
20467            } else {
20468                Some(WordBreakToken::Word {
20469                    token,
20470                    grapheme_len,
20471                })
20472            }
20473        } else {
20474            None
20475        }
20476    }
20477}
20478
20479#[test]
20480fn test_word_breaking_tokenizer() {
20481    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20482        ("", &[]),
20483        ("  ", &[whitespace("  ", 2)]),
20484        ("Ʒ", &[word("Ʒ", 1)]),
20485        ("Ǽ", &[word("Ǽ", 1)]),
20486        ("", &[word("", 1)]),
20487        ("⋑⋑", &[word("⋑⋑", 2)]),
20488        (
20489            "原理,进而",
20490            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20491        ),
20492        (
20493            "hello world",
20494            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20495        ),
20496        (
20497            "hello, world",
20498            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20499        ),
20500        (
20501            "  hello world",
20502            &[
20503                whitespace("  ", 2),
20504                word("hello", 5),
20505                whitespace(" ", 1),
20506                word("world", 5),
20507            ],
20508        ),
20509        (
20510            "这是什么 \n 钢笔",
20511            &[
20512                word("", 1),
20513                word("", 1),
20514                word("", 1),
20515                word("", 1),
20516                whitespace(" ", 1),
20517                newline(),
20518                whitespace(" ", 1),
20519                word("", 1),
20520                word("", 1),
20521            ],
20522        ),
20523        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20524    ];
20525
20526    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20527        WordBreakToken::Word {
20528            token,
20529            grapheme_len,
20530        }
20531    }
20532
20533    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20534        WordBreakToken::InlineWhitespace {
20535            token,
20536            grapheme_len,
20537        }
20538    }
20539
20540    fn newline() -> WordBreakToken<'static> {
20541        WordBreakToken::Newline
20542    }
20543
20544    for (input, result) in tests {
20545        assert_eq!(
20546            WordBreakingTokenizer::new(input)
20547                .collect::<Vec<_>>()
20548                .as_slice(),
20549            *result,
20550        );
20551    }
20552}
20553
20554fn wrap_with_prefix(
20555    line_prefix: String,
20556    unwrapped_text: String,
20557    wrap_column: usize,
20558    tab_size: NonZeroU32,
20559    preserve_existing_whitespace: bool,
20560) -> String {
20561    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20562    let mut wrapped_text = String::new();
20563    let mut current_line = line_prefix.clone();
20564
20565    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20566    let mut current_line_len = line_prefix_len;
20567    let mut in_whitespace = false;
20568    for token in tokenizer {
20569        let have_preceding_whitespace = in_whitespace;
20570        match token {
20571            WordBreakToken::Word {
20572                token,
20573                grapheme_len,
20574            } => {
20575                in_whitespace = false;
20576                if current_line_len + grapheme_len > wrap_column
20577                    && current_line_len != line_prefix_len
20578                {
20579                    wrapped_text.push_str(current_line.trim_end());
20580                    wrapped_text.push('\n');
20581                    current_line.truncate(line_prefix.len());
20582                    current_line_len = line_prefix_len;
20583                }
20584                current_line.push_str(token);
20585                current_line_len += grapheme_len;
20586            }
20587            WordBreakToken::InlineWhitespace {
20588                mut token,
20589                mut grapheme_len,
20590            } => {
20591                in_whitespace = true;
20592                if have_preceding_whitespace && !preserve_existing_whitespace {
20593                    continue;
20594                }
20595                if !preserve_existing_whitespace {
20596                    token = " ";
20597                    grapheme_len = 1;
20598                }
20599                if current_line_len + grapheme_len > wrap_column {
20600                    wrapped_text.push_str(current_line.trim_end());
20601                    wrapped_text.push('\n');
20602                    current_line.truncate(line_prefix.len());
20603                    current_line_len = line_prefix_len;
20604                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20605                    current_line.push_str(token);
20606                    current_line_len += grapheme_len;
20607                }
20608            }
20609            WordBreakToken::Newline => {
20610                in_whitespace = true;
20611                if preserve_existing_whitespace {
20612                    wrapped_text.push_str(current_line.trim_end());
20613                    wrapped_text.push('\n');
20614                    current_line.truncate(line_prefix.len());
20615                    current_line_len = line_prefix_len;
20616                } else if have_preceding_whitespace {
20617                    continue;
20618                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20619                {
20620                    wrapped_text.push_str(current_line.trim_end());
20621                    wrapped_text.push('\n');
20622                    current_line.truncate(line_prefix.len());
20623                    current_line_len = line_prefix_len;
20624                } else if current_line_len != line_prefix_len {
20625                    current_line.push(' ');
20626                    current_line_len += 1;
20627                }
20628            }
20629        }
20630    }
20631
20632    if !current_line.is_empty() {
20633        wrapped_text.push_str(&current_line);
20634    }
20635    wrapped_text
20636}
20637
20638#[test]
20639fn test_wrap_with_prefix() {
20640    assert_eq!(
20641        wrap_with_prefix(
20642            "# ".to_string(),
20643            "abcdefg".to_string(),
20644            4,
20645            NonZeroU32::new(4).unwrap(),
20646            false,
20647        ),
20648        "# abcdefg"
20649    );
20650    assert_eq!(
20651        wrap_with_prefix(
20652            "".to_string(),
20653            "\thello world".to_string(),
20654            8,
20655            NonZeroU32::new(4).unwrap(),
20656            false,
20657        ),
20658        "hello\nworld"
20659    );
20660    assert_eq!(
20661        wrap_with_prefix(
20662            "// ".to_string(),
20663            "xx \nyy zz aa bb cc".to_string(),
20664            12,
20665            NonZeroU32::new(4).unwrap(),
20666            false,
20667        ),
20668        "// xx yy zz\n// aa bb cc"
20669    );
20670    assert_eq!(
20671        wrap_with_prefix(
20672            String::new(),
20673            "这是什么 \n 钢笔".to_string(),
20674            3,
20675            NonZeroU32::new(4).unwrap(),
20676            false,
20677        ),
20678        "这是什\n么 钢\n"
20679    );
20680}
20681
20682pub trait CollaborationHub {
20683    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20684    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20685    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20686}
20687
20688impl CollaborationHub for Entity<Project> {
20689    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20690        self.read(cx).collaborators()
20691    }
20692
20693    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20694        self.read(cx).user_store().read(cx).participant_indices()
20695    }
20696
20697    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20698        let this = self.read(cx);
20699        let user_ids = this.collaborators().values().map(|c| c.user_id);
20700        this.user_store().read(cx).participant_names(user_ids, cx)
20701    }
20702}
20703
20704pub trait SemanticsProvider {
20705    fn hover(
20706        &self,
20707        buffer: &Entity<Buffer>,
20708        position: text::Anchor,
20709        cx: &mut App,
20710    ) -> Option<Task<Vec<project::Hover>>>;
20711
20712    fn inline_values(
20713        &self,
20714        buffer_handle: Entity<Buffer>,
20715        range: Range<text::Anchor>,
20716        cx: &mut App,
20717    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20718
20719    fn inlay_hints(
20720        &self,
20721        buffer_handle: Entity<Buffer>,
20722        range: Range<text::Anchor>,
20723        cx: &mut App,
20724    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20725
20726    fn resolve_inlay_hint(
20727        &self,
20728        hint: InlayHint,
20729        buffer_handle: Entity<Buffer>,
20730        server_id: LanguageServerId,
20731        cx: &mut App,
20732    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20733
20734    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20735
20736    fn document_highlights(
20737        &self,
20738        buffer: &Entity<Buffer>,
20739        position: text::Anchor,
20740        cx: &mut App,
20741    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20742
20743    fn definitions(
20744        &self,
20745        buffer: &Entity<Buffer>,
20746        position: text::Anchor,
20747        kind: GotoDefinitionKind,
20748        cx: &mut App,
20749    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20750
20751    fn range_for_rename(
20752        &self,
20753        buffer: &Entity<Buffer>,
20754        position: text::Anchor,
20755        cx: &mut App,
20756    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20757
20758    fn perform_rename(
20759        &self,
20760        buffer: &Entity<Buffer>,
20761        position: text::Anchor,
20762        new_name: String,
20763        cx: &mut App,
20764    ) -> Option<Task<Result<ProjectTransaction>>>;
20765
20766    fn pull_diagnostics_for_buffer(
20767        &self,
20768        buffer: Entity<Buffer>,
20769        cx: &mut App,
20770    ) -> Task<anyhow::Result<()>>;
20771}
20772
20773pub trait CompletionProvider {
20774    fn completions(
20775        &self,
20776        excerpt_id: ExcerptId,
20777        buffer: &Entity<Buffer>,
20778        buffer_position: text::Anchor,
20779        trigger: CompletionContext,
20780        window: &mut Window,
20781        cx: &mut Context<Editor>,
20782    ) -> Task<Result<Vec<CompletionResponse>>>;
20783
20784    fn resolve_completions(
20785        &self,
20786        _buffer: Entity<Buffer>,
20787        _completion_indices: Vec<usize>,
20788        _completions: Rc<RefCell<Box<[Completion]>>>,
20789        _cx: &mut Context<Editor>,
20790    ) -> Task<Result<bool>> {
20791        Task::ready(Ok(false))
20792    }
20793
20794    fn apply_additional_edits_for_completion(
20795        &self,
20796        _buffer: Entity<Buffer>,
20797        _completions: Rc<RefCell<Box<[Completion]>>>,
20798        _completion_index: usize,
20799        _push_to_history: bool,
20800        _cx: &mut Context<Editor>,
20801    ) -> Task<Result<Option<language::Transaction>>> {
20802        Task::ready(Ok(None))
20803    }
20804
20805    fn is_completion_trigger(
20806        &self,
20807        buffer: &Entity<Buffer>,
20808        position: language::Anchor,
20809        text: &str,
20810        trigger_in_words: bool,
20811        menu_is_open: bool,
20812        cx: &mut Context<Editor>,
20813    ) -> bool;
20814
20815    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20816
20817    fn sort_completions(&self) -> bool {
20818        true
20819    }
20820
20821    fn filter_completions(&self) -> bool {
20822        true
20823    }
20824}
20825
20826pub trait CodeActionProvider {
20827    fn id(&self) -> Arc<str>;
20828
20829    fn code_actions(
20830        &self,
20831        buffer: &Entity<Buffer>,
20832        range: Range<text::Anchor>,
20833        window: &mut Window,
20834        cx: &mut App,
20835    ) -> Task<Result<Vec<CodeAction>>>;
20836
20837    fn apply_code_action(
20838        &self,
20839        buffer_handle: Entity<Buffer>,
20840        action: CodeAction,
20841        excerpt_id: ExcerptId,
20842        push_to_history: bool,
20843        window: &mut Window,
20844        cx: &mut App,
20845    ) -> Task<Result<ProjectTransaction>>;
20846}
20847
20848impl CodeActionProvider for Entity<Project> {
20849    fn id(&self) -> Arc<str> {
20850        "project".into()
20851    }
20852
20853    fn code_actions(
20854        &self,
20855        buffer: &Entity<Buffer>,
20856        range: Range<text::Anchor>,
20857        _window: &mut Window,
20858        cx: &mut App,
20859    ) -> Task<Result<Vec<CodeAction>>> {
20860        self.update(cx, |project, cx| {
20861            let code_lens = project.code_lens(buffer, range.clone(), cx);
20862            let code_actions = project.code_actions(buffer, range, None, cx);
20863            cx.background_spawn(async move {
20864                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20865                Ok(code_lens
20866                    .context("code lens fetch")?
20867                    .into_iter()
20868                    .chain(code_actions.context("code action fetch")?)
20869                    .collect())
20870            })
20871        })
20872    }
20873
20874    fn apply_code_action(
20875        &self,
20876        buffer_handle: Entity<Buffer>,
20877        action: CodeAction,
20878        _excerpt_id: ExcerptId,
20879        push_to_history: bool,
20880        _window: &mut Window,
20881        cx: &mut App,
20882    ) -> Task<Result<ProjectTransaction>> {
20883        self.update(cx, |project, cx| {
20884            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20885        })
20886    }
20887}
20888
20889fn snippet_completions(
20890    project: &Project,
20891    buffer: &Entity<Buffer>,
20892    buffer_position: text::Anchor,
20893    cx: &mut App,
20894) -> Task<Result<CompletionResponse>> {
20895    let languages = buffer.read(cx).languages_at(buffer_position);
20896    let snippet_store = project.snippets().read(cx);
20897
20898    let scopes: Vec<_> = languages
20899        .iter()
20900        .filter_map(|language| {
20901            let language_name = language.lsp_id();
20902            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20903
20904            if snippets.is_empty() {
20905                None
20906            } else {
20907                Some((language.default_scope(), snippets))
20908            }
20909        })
20910        .collect();
20911
20912    if scopes.is_empty() {
20913        return Task::ready(Ok(CompletionResponse {
20914            completions: vec![],
20915            is_incomplete: false,
20916        }));
20917    }
20918
20919    let snapshot = buffer.read(cx).text_snapshot();
20920    let chars: String = snapshot
20921        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20922        .collect();
20923    let executor = cx.background_executor().clone();
20924
20925    cx.background_spawn(async move {
20926        let mut is_incomplete = false;
20927        let mut completions: Vec<Completion> = Vec::new();
20928        for (scope, snippets) in scopes.into_iter() {
20929            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20930            let mut last_word = chars
20931                .chars()
20932                .take_while(|c| classifier.is_word(*c))
20933                .collect::<String>();
20934            last_word = last_word.chars().rev().collect();
20935
20936            if last_word.is_empty() {
20937                return Ok(CompletionResponse {
20938                    completions: vec![],
20939                    is_incomplete: true,
20940                });
20941            }
20942
20943            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20944            let to_lsp = |point: &text::Anchor| {
20945                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20946                point_to_lsp(end)
20947            };
20948            let lsp_end = to_lsp(&buffer_position);
20949
20950            let candidates = snippets
20951                .iter()
20952                .enumerate()
20953                .flat_map(|(ix, snippet)| {
20954                    snippet
20955                        .prefix
20956                        .iter()
20957                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20958                })
20959                .collect::<Vec<StringMatchCandidate>>();
20960
20961            const MAX_RESULTS: usize = 100;
20962            let mut matches = fuzzy::match_strings(
20963                &candidates,
20964                &last_word,
20965                last_word.chars().any(|c| c.is_uppercase()),
20966                MAX_RESULTS,
20967                &Default::default(),
20968                executor.clone(),
20969            )
20970            .await;
20971
20972            if matches.len() >= MAX_RESULTS {
20973                is_incomplete = true;
20974            }
20975
20976            // Remove all candidates where the query's start does not match the start of any word in the candidate
20977            if let Some(query_start) = last_word.chars().next() {
20978                matches.retain(|string_match| {
20979                    split_words(&string_match.string).any(|word| {
20980                        // Check that the first codepoint of the word as lowercase matches the first
20981                        // codepoint of the query as lowercase
20982                        word.chars()
20983                            .flat_map(|codepoint| codepoint.to_lowercase())
20984                            .zip(query_start.to_lowercase())
20985                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20986                    })
20987                });
20988            }
20989
20990            let matched_strings = matches
20991                .into_iter()
20992                .map(|m| m.string)
20993                .collect::<HashSet<_>>();
20994
20995            completions.extend(snippets.iter().filter_map(|snippet| {
20996                let matching_prefix = snippet
20997                    .prefix
20998                    .iter()
20999                    .find(|prefix| matched_strings.contains(*prefix))?;
21000                let start = as_offset - last_word.len();
21001                let start = snapshot.anchor_before(start);
21002                let range = start..buffer_position;
21003                let lsp_start = to_lsp(&start);
21004                let lsp_range = lsp::Range {
21005                    start: lsp_start,
21006                    end: lsp_end,
21007                };
21008                Some(Completion {
21009                    replace_range: range,
21010                    new_text: snippet.body.clone(),
21011                    source: CompletionSource::Lsp {
21012                        insert_range: None,
21013                        server_id: LanguageServerId(usize::MAX),
21014                        resolved: true,
21015                        lsp_completion: Box::new(lsp::CompletionItem {
21016                            label: snippet.prefix.first().unwrap().clone(),
21017                            kind: Some(CompletionItemKind::SNIPPET),
21018                            label_details: snippet.description.as_ref().map(|description| {
21019                                lsp::CompletionItemLabelDetails {
21020                                    detail: Some(description.clone()),
21021                                    description: None,
21022                                }
21023                            }),
21024                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21025                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21026                                lsp::InsertReplaceEdit {
21027                                    new_text: snippet.body.clone(),
21028                                    insert: lsp_range,
21029                                    replace: lsp_range,
21030                                },
21031                            )),
21032                            filter_text: Some(snippet.body.clone()),
21033                            sort_text: Some(char::MAX.to_string()),
21034                            ..lsp::CompletionItem::default()
21035                        }),
21036                        lsp_defaults: None,
21037                    },
21038                    label: CodeLabel {
21039                        text: matching_prefix.clone(),
21040                        runs: Vec::new(),
21041                        filter_range: 0..matching_prefix.len(),
21042                    },
21043                    icon_path: None,
21044                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21045                        single_line: snippet.name.clone().into(),
21046                        plain_text: snippet
21047                            .description
21048                            .clone()
21049                            .map(|description| description.into()),
21050                    }),
21051                    insert_text_mode: None,
21052                    confirm: None,
21053                })
21054            }))
21055        }
21056
21057        Ok(CompletionResponse {
21058            completions,
21059            is_incomplete,
21060        })
21061    })
21062}
21063
21064impl CompletionProvider for Entity<Project> {
21065    fn completions(
21066        &self,
21067        _excerpt_id: ExcerptId,
21068        buffer: &Entity<Buffer>,
21069        buffer_position: text::Anchor,
21070        options: CompletionContext,
21071        _window: &mut Window,
21072        cx: &mut Context<Editor>,
21073    ) -> Task<Result<Vec<CompletionResponse>>> {
21074        self.update(cx, |project, cx| {
21075            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21076            let project_completions = project.completions(buffer, buffer_position, options, cx);
21077            cx.background_spawn(async move {
21078                let mut responses = project_completions.await?;
21079                let snippets = snippets.await?;
21080                if !snippets.completions.is_empty() {
21081                    responses.push(snippets);
21082                }
21083                Ok(responses)
21084            })
21085        })
21086    }
21087
21088    fn resolve_completions(
21089        &self,
21090        buffer: Entity<Buffer>,
21091        completion_indices: Vec<usize>,
21092        completions: Rc<RefCell<Box<[Completion]>>>,
21093        cx: &mut Context<Editor>,
21094    ) -> Task<Result<bool>> {
21095        self.update(cx, |project, cx| {
21096            project.lsp_store().update(cx, |lsp_store, cx| {
21097                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21098            })
21099        })
21100    }
21101
21102    fn apply_additional_edits_for_completion(
21103        &self,
21104        buffer: Entity<Buffer>,
21105        completions: Rc<RefCell<Box<[Completion]>>>,
21106        completion_index: usize,
21107        push_to_history: bool,
21108        cx: &mut Context<Editor>,
21109    ) -> Task<Result<Option<language::Transaction>>> {
21110        self.update(cx, |project, cx| {
21111            project.lsp_store().update(cx, |lsp_store, cx| {
21112                lsp_store.apply_additional_edits_for_completion(
21113                    buffer,
21114                    completions,
21115                    completion_index,
21116                    push_to_history,
21117                    cx,
21118                )
21119            })
21120        })
21121    }
21122
21123    fn is_completion_trigger(
21124        &self,
21125        buffer: &Entity<Buffer>,
21126        position: language::Anchor,
21127        text: &str,
21128        trigger_in_words: bool,
21129        menu_is_open: bool,
21130        cx: &mut Context<Editor>,
21131    ) -> bool {
21132        let mut chars = text.chars();
21133        let char = if let Some(char) = chars.next() {
21134            char
21135        } else {
21136            return false;
21137        };
21138        if chars.next().is_some() {
21139            return false;
21140        }
21141
21142        let buffer = buffer.read(cx);
21143        let snapshot = buffer.snapshot();
21144        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21145            return false;
21146        }
21147        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21148        if trigger_in_words && classifier.is_word(char) {
21149            return true;
21150        }
21151
21152        buffer.completion_triggers().contains(text)
21153    }
21154}
21155
21156impl SemanticsProvider for Entity<Project> {
21157    fn hover(
21158        &self,
21159        buffer: &Entity<Buffer>,
21160        position: text::Anchor,
21161        cx: &mut App,
21162    ) -> Option<Task<Vec<project::Hover>>> {
21163        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21164    }
21165
21166    fn document_highlights(
21167        &self,
21168        buffer: &Entity<Buffer>,
21169        position: text::Anchor,
21170        cx: &mut App,
21171    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21172        Some(self.update(cx, |project, cx| {
21173            project.document_highlights(buffer, position, cx)
21174        }))
21175    }
21176
21177    fn definitions(
21178        &self,
21179        buffer: &Entity<Buffer>,
21180        position: text::Anchor,
21181        kind: GotoDefinitionKind,
21182        cx: &mut App,
21183    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21184        Some(self.update(cx, |project, cx| match kind {
21185            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21186            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21187            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21188            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21189        }))
21190    }
21191
21192    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21193        // TODO: make this work for remote projects
21194        self.update(cx, |project, cx| {
21195            if project
21196                .active_debug_session(cx)
21197                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21198            {
21199                return true;
21200            }
21201
21202            buffer.update(cx, |buffer, cx| {
21203                project.any_language_server_supports_inlay_hints(buffer, cx)
21204            })
21205        })
21206    }
21207
21208    fn inline_values(
21209        &self,
21210        buffer_handle: Entity<Buffer>,
21211
21212        range: Range<text::Anchor>,
21213        cx: &mut App,
21214    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21215        self.update(cx, |project, cx| {
21216            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21217
21218            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21219        })
21220    }
21221
21222    fn inlay_hints(
21223        &self,
21224        buffer_handle: Entity<Buffer>,
21225        range: Range<text::Anchor>,
21226        cx: &mut App,
21227    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21228        Some(self.update(cx, |project, cx| {
21229            project.inlay_hints(buffer_handle, range, cx)
21230        }))
21231    }
21232
21233    fn resolve_inlay_hint(
21234        &self,
21235        hint: InlayHint,
21236        buffer_handle: Entity<Buffer>,
21237        server_id: LanguageServerId,
21238        cx: &mut App,
21239    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21240        Some(self.update(cx, |project, cx| {
21241            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21242        }))
21243    }
21244
21245    fn range_for_rename(
21246        &self,
21247        buffer: &Entity<Buffer>,
21248        position: text::Anchor,
21249        cx: &mut App,
21250    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21251        Some(self.update(cx, |project, cx| {
21252            let buffer = buffer.clone();
21253            let task = project.prepare_rename(buffer.clone(), position, cx);
21254            cx.spawn(async move |_, cx| {
21255                Ok(match task.await? {
21256                    PrepareRenameResponse::Success(range) => Some(range),
21257                    PrepareRenameResponse::InvalidPosition => None,
21258                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21259                        // Fallback on using TreeSitter info to determine identifier range
21260                        buffer.read_with(cx, |buffer, _| {
21261                            let snapshot = buffer.snapshot();
21262                            let (range, kind) = snapshot.surrounding_word(position);
21263                            if kind != Some(CharKind::Word) {
21264                                return None;
21265                            }
21266                            Some(
21267                                snapshot.anchor_before(range.start)
21268                                    ..snapshot.anchor_after(range.end),
21269                            )
21270                        })?
21271                    }
21272                })
21273            })
21274        }))
21275    }
21276
21277    fn perform_rename(
21278        &self,
21279        buffer: &Entity<Buffer>,
21280        position: text::Anchor,
21281        new_name: String,
21282        cx: &mut App,
21283    ) -> Option<Task<Result<ProjectTransaction>>> {
21284        Some(self.update(cx, |project, cx| {
21285            project.perform_rename(buffer.clone(), position, new_name, cx)
21286        }))
21287    }
21288
21289    fn pull_diagnostics_for_buffer(
21290        &self,
21291        buffer: Entity<Buffer>,
21292        cx: &mut App,
21293    ) -> Task<anyhow::Result<()>> {
21294        let diagnostics = self.update(cx, |project, cx| {
21295            project
21296                .lsp_store()
21297                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21298        });
21299        let project = self.clone();
21300        cx.spawn(async move |cx| {
21301            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21302            project.update(cx, |project, cx| {
21303                project.lsp_store().update(cx, |lsp_store, cx| {
21304                    for diagnostics_set in diagnostics {
21305                        let LspPullDiagnostics::Response {
21306                            server_id,
21307                            uri,
21308                            diagnostics,
21309                        } = diagnostics_set
21310                        else {
21311                            continue;
21312                        };
21313
21314                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21315                        let disk_based_sources = adapter
21316                            .as_ref()
21317                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21318                            .unwrap_or(&[]);
21319                        match diagnostics {
21320                            PulledDiagnostics::Unchanged { result_id } => {
21321                                lsp_store
21322                                    .merge_diagnostics(
21323                                        server_id,
21324                                        lsp::PublishDiagnosticsParams {
21325                                            uri: uri.clone(),
21326                                            diagnostics: Vec::new(),
21327                                            version: None,
21328                                        },
21329                                        Some(result_id),
21330                                        DiagnosticSourceKind::Pulled,
21331                                        disk_based_sources,
21332                                        |_, _| true,
21333                                        cx,
21334                                    )
21335                                    .log_err();
21336                            }
21337                            PulledDiagnostics::Changed {
21338                                diagnostics,
21339                                result_id,
21340                            } => {
21341                                lsp_store
21342                                    .merge_diagnostics(
21343                                        server_id,
21344                                        lsp::PublishDiagnosticsParams {
21345                                            uri: uri.clone(),
21346                                            diagnostics,
21347                                            version: None,
21348                                        },
21349                                        result_id,
21350                                        DiagnosticSourceKind::Pulled,
21351                                        disk_based_sources,
21352                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21353                                            DiagnosticSourceKind::Pulled => false,
21354                                            DiagnosticSourceKind::Other
21355                                            | DiagnosticSourceKind::Pushed => true,
21356                                        },
21357                                        cx,
21358                                    )
21359                                    .log_err();
21360                            }
21361                        }
21362                    }
21363                })
21364            })
21365        })
21366    }
21367}
21368
21369fn inlay_hint_settings(
21370    location: Anchor,
21371    snapshot: &MultiBufferSnapshot,
21372    cx: &mut Context<Editor>,
21373) -> InlayHintSettings {
21374    let file = snapshot.file_at(location);
21375    let language = snapshot.language_at(location).map(|l| l.name());
21376    language_settings(language, file, cx).inlay_hints
21377}
21378
21379fn consume_contiguous_rows(
21380    contiguous_row_selections: &mut Vec<Selection<Point>>,
21381    selection: &Selection<Point>,
21382    display_map: &DisplaySnapshot,
21383    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21384) -> (MultiBufferRow, MultiBufferRow) {
21385    contiguous_row_selections.push(selection.clone());
21386    let start_row = MultiBufferRow(selection.start.row);
21387    let mut end_row = ending_row(selection, display_map);
21388
21389    while let Some(next_selection) = selections.peek() {
21390        if next_selection.start.row <= end_row.0 {
21391            end_row = ending_row(next_selection, display_map);
21392            contiguous_row_selections.push(selections.next().unwrap().clone());
21393        } else {
21394            break;
21395        }
21396    }
21397    (start_row, end_row)
21398}
21399
21400fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21401    if next_selection.end.column > 0 || next_selection.is_empty() {
21402        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21403    } else {
21404        MultiBufferRow(next_selection.end.row)
21405    }
21406}
21407
21408impl EditorSnapshot {
21409    pub fn remote_selections_in_range<'a>(
21410        &'a self,
21411        range: &'a Range<Anchor>,
21412        collaboration_hub: &dyn CollaborationHub,
21413        cx: &'a App,
21414    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21415        let participant_names = collaboration_hub.user_names(cx);
21416        let participant_indices = collaboration_hub.user_participant_indices(cx);
21417        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21418        let collaborators_by_replica_id = collaborators_by_peer_id
21419            .values()
21420            .map(|collaborator| (collaborator.replica_id, collaborator))
21421            .collect::<HashMap<_, _>>();
21422        self.buffer_snapshot
21423            .selections_in_range(range, false)
21424            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21425                if replica_id == AGENT_REPLICA_ID {
21426                    Some(RemoteSelection {
21427                        replica_id,
21428                        selection,
21429                        cursor_shape,
21430                        line_mode,
21431                        collaborator_id: CollaboratorId::Agent,
21432                        user_name: Some("Agent".into()),
21433                        color: cx.theme().players().agent(),
21434                    })
21435                } else {
21436                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21437                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21438                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21439                    Some(RemoteSelection {
21440                        replica_id,
21441                        selection,
21442                        cursor_shape,
21443                        line_mode,
21444                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21445                        user_name,
21446                        color: if let Some(index) = participant_index {
21447                            cx.theme().players().color_for_participant(index.0)
21448                        } else {
21449                            cx.theme().players().absent()
21450                        },
21451                    })
21452                }
21453            })
21454    }
21455
21456    pub fn hunks_for_ranges(
21457        &self,
21458        ranges: impl IntoIterator<Item = Range<Point>>,
21459    ) -> Vec<MultiBufferDiffHunk> {
21460        let mut hunks = Vec::new();
21461        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21462            HashMap::default();
21463        for query_range in ranges {
21464            let query_rows =
21465                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21466            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21467                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21468            ) {
21469                // Include deleted hunks that are adjacent to the query range, because
21470                // otherwise they would be missed.
21471                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21472                if hunk.status().is_deleted() {
21473                    intersects_range |= hunk.row_range.start == query_rows.end;
21474                    intersects_range |= hunk.row_range.end == query_rows.start;
21475                }
21476                if intersects_range {
21477                    if !processed_buffer_rows
21478                        .entry(hunk.buffer_id)
21479                        .or_default()
21480                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21481                    {
21482                        continue;
21483                    }
21484                    hunks.push(hunk);
21485                }
21486            }
21487        }
21488
21489        hunks
21490    }
21491
21492    fn display_diff_hunks_for_rows<'a>(
21493        &'a self,
21494        display_rows: Range<DisplayRow>,
21495        folded_buffers: &'a HashSet<BufferId>,
21496    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21497        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21498        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21499
21500        self.buffer_snapshot
21501            .diff_hunks_in_range(buffer_start..buffer_end)
21502            .filter_map(|hunk| {
21503                if folded_buffers.contains(&hunk.buffer_id) {
21504                    return None;
21505                }
21506
21507                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21508                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21509
21510                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21511                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21512
21513                let display_hunk = if hunk_display_start.column() != 0 {
21514                    DisplayDiffHunk::Folded {
21515                        display_row: hunk_display_start.row(),
21516                    }
21517                } else {
21518                    let mut end_row = hunk_display_end.row();
21519                    if hunk_display_end.column() > 0 {
21520                        end_row.0 += 1;
21521                    }
21522                    let is_created_file = hunk.is_created_file();
21523                    DisplayDiffHunk::Unfolded {
21524                        status: hunk.status(),
21525                        diff_base_byte_range: hunk.diff_base_byte_range,
21526                        display_row_range: hunk_display_start.row()..end_row,
21527                        multi_buffer_range: Anchor::range_in_buffer(
21528                            hunk.excerpt_id,
21529                            hunk.buffer_id,
21530                            hunk.buffer_range,
21531                        ),
21532                        is_created_file,
21533                    }
21534                };
21535
21536                Some(display_hunk)
21537            })
21538    }
21539
21540    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21541        self.display_snapshot.buffer_snapshot.language_at(position)
21542    }
21543
21544    pub fn is_focused(&self) -> bool {
21545        self.is_focused
21546    }
21547
21548    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21549        self.placeholder_text.as_ref()
21550    }
21551
21552    pub fn scroll_position(&self) -> gpui::Point<f32> {
21553        self.scroll_anchor.scroll_position(&self.display_snapshot)
21554    }
21555
21556    fn gutter_dimensions(
21557        &self,
21558        font_id: FontId,
21559        font_size: Pixels,
21560        max_line_number_width: Pixels,
21561        cx: &App,
21562    ) -> Option<GutterDimensions> {
21563        if !self.show_gutter {
21564            return None;
21565        }
21566
21567        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
21568        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
21569
21570        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21571            matches!(
21572                ProjectSettings::get_global(cx).git.git_gutter,
21573                Some(GitGutterSetting::TrackedFiles)
21574            )
21575        });
21576        let gutter_settings = EditorSettings::get_global(cx).gutter;
21577        let show_line_numbers = self
21578            .show_line_numbers
21579            .unwrap_or(gutter_settings.line_numbers);
21580        let line_gutter_width = if show_line_numbers {
21581            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
21582            let min_width_for_number_on_gutter =
21583                em_advance * gutter_settings.min_line_number_digits as f32;
21584            max_line_number_width.max(min_width_for_number_on_gutter)
21585        } else {
21586            0.0.into()
21587        };
21588
21589        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21590        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21591
21592        let git_blame_entries_width =
21593            self.git_blame_gutter_max_author_length
21594                .map(|max_author_length| {
21595                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21596                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21597
21598                    /// The number of characters to dedicate to gaps and margins.
21599                    const SPACING_WIDTH: usize = 4;
21600
21601                    let max_char_count = max_author_length.min(renderer.max_author_length())
21602                        + ::git::SHORT_SHA_LENGTH
21603                        + MAX_RELATIVE_TIMESTAMP.len()
21604                        + SPACING_WIDTH;
21605
21606                    em_advance * max_char_count
21607                });
21608
21609        let is_singleton = self.buffer_snapshot.is_singleton();
21610
21611        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21612        left_padding += if !is_singleton {
21613            em_width * 4.0
21614        } else if show_runnables || show_breakpoints {
21615            em_width * 3.0
21616        } else if show_git_gutter && show_line_numbers {
21617            em_width * 2.0
21618        } else if show_git_gutter || show_line_numbers {
21619            em_width
21620        } else {
21621            px(0.)
21622        };
21623
21624        let shows_folds = is_singleton && gutter_settings.folds;
21625
21626        let right_padding = if shows_folds && show_line_numbers {
21627            em_width * 4.0
21628        } else if shows_folds || (!is_singleton && show_line_numbers) {
21629            em_width * 3.0
21630        } else if show_line_numbers {
21631            em_width
21632        } else {
21633            px(0.)
21634        };
21635
21636        Some(GutterDimensions {
21637            left_padding,
21638            right_padding,
21639            width: line_gutter_width + left_padding + right_padding,
21640            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21641            git_blame_entries_width,
21642        })
21643    }
21644
21645    pub fn render_crease_toggle(
21646        &self,
21647        buffer_row: MultiBufferRow,
21648        row_contains_cursor: bool,
21649        editor: Entity<Editor>,
21650        window: &mut Window,
21651        cx: &mut App,
21652    ) -> Option<AnyElement> {
21653        let folded = self.is_line_folded(buffer_row);
21654        let mut is_foldable = false;
21655
21656        if let Some(crease) = self
21657            .crease_snapshot
21658            .query_row(buffer_row, &self.buffer_snapshot)
21659        {
21660            is_foldable = true;
21661            match crease {
21662                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21663                    if let Some(render_toggle) = render_toggle {
21664                        let toggle_callback =
21665                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21666                                if folded {
21667                                    editor.update(cx, |editor, cx| {
21668                                        editor.fold_at(buffer_row, window, cx)
21669                                    });
21670                                } else {
21671                                    editor.update(cx, |editor, cx| {
21672                                        editor.unfold_at(buffer_row, window, cx)
21673                                    });
21674                                }
21675                            });
21676                        return Some((render_toggle)(
21677                            buffer_row,
21678                            folded,
21679                            toggle_callback,
21680                            window,
21681                            cx,
21682                        ));
21683                    }
21684                }
21685            }
21686        }
21687
21688        is_foldable |= self.starts_indent(buffer_row);
21689
21690        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21691            Some(
21692                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21693                    .toggle_state(folded)
21694                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21695                        if folded {
21696                            this.unfold_at(buffer_row, window, cx);
21697                        } else {
21698                            this.fold_at(buffer_row, window, cx);
21699                        }
21700                    }))
21701                    .into_any_element(),
21702            )
21703        } else {
21704            None
21705        }
21706    }
21707
21708    pub fn render_crease_trailer(
21709        &self,
21710        buffer_row: MultiBufferRow,
21711        window: &mut Window,
21712        cx: &mut App,
21713    ) -> Option<AnyElement> {
21714        let folded = self.is_line_folded(buffer_row);
21715        if let Crease::Inline { render_trailer, .. } = self
21716            .crease_snapshot
21717            .query_row(buffer_row, &self.buffer_snapshot)?
21718        {
21719            let render_trailer = render_trailer.as_ref()?;
21720            Some(render_trailer(buffer_row, folded, window, cx))
21721        } else {
21722            None
21723        }
21724    }
21725}
21726
21727impl Deref for EditorSnapshot {
21728    type Target = DisplaySnapshot;
21729
21730    fn deref(&self) -> &Self::Target {
21731        &self.display_snapshot
21732    }
21733}
21734
21735#[derive(Clone, Debug, PartialEq, Eq)]
21736pub enum EditorEvent {
21737    InputIgnored {
21738        text: Arc<str>,
21739    },
21740    InputHandled {
21741        utf16_range_to_replace: Option<Range<isize>>,
21742        text: Arc<str>,
21743    },
21744    ExcerptsAdded {
21745        buffer: Entity<Buffer>,
21746        predecessor: ExcerptId,
21747        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21748    },
21749    ExcerptsRemoved {
21750        ids: Vec<ExcerptId>,
21751        removed_buffer_ids: Vec<BufferId>,
21752    },
21753    BufferFoldToggled {
21754        ids: Vec<ExcerptId>,
21755        folded: bool,
21756    },
21757    ExcerptsEdited {
21758        ids: Vec<ExcerptId>,
21759    },
21760    ExcerptsExpanded {
21761        ids: Vec<ExcerptId>,
21762    },
21763    BufferEdited,
21764    Edited {
21765        transaction_id: clock::Lamport,
21766    },
21767    Reparsed(BufferId),
21768    Focused,
21769    FocusedIn,
21770    Blurred,
21771    DirtyChanged,
21772    Saved,
21773    TitleChanged,
21774    DiffBaseChanged,
21775    SelectionsChanged {
21776        local: bool,
21777    },
21778    ScrollPositionChanged {
21779        local: bool,
21780        autoscroll: bool,
21781    },
21782    Closed,
21783    TransactionUndone {
21784        transaction_id: clock::Lamport,
21785    },
21786    TransactionBegun {
21787        transaction_id: clock::Lamport,
21788    },
21789    Reloaded,
21790    CursorShapeChanged,
21791    PushedToNavHistory {
21792        anchor: Anchor,
21793        is_deactivate: bool,
21794    },
21795}
21796
21797impl EventEmitter<EditorEvent> for Editor {}
21798
21799impl Focusable for Editor {
21800    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21801        self.focus_handle.clone()
21802    }
21803}
21804
21805impl Render for Editor {
21806    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21807        let settings = ThemeSettings::get_global(cx);
21808
21809        let mut text_style = match self.mode {
21810            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21811                color: cx.theme().colors().editor_foreground,
21812                font_family: settings.ui_font.family.clone(),
21813                font_features: settings.ui_font.features.clone(),
21814                font_fallbacks: settings.ui_font.fallbacks.clone(),
21815                font_size: rems(0.875).into(),
21816                font_weight: settings.ui_font.weight,
21817                line_height: relative(settings.buffer_line_height.value()),
21818                ..Default::default()
21819            },
21820            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21821                color: cx.theme().colors().editor_foreground,
21822                font_family: settings.buffer_font.family.clone(),
21823                font_features: settings.buffer_font.features.clone(),
21824                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21825                font_size: settings.buffer_font_size(cx).into(),
21826                font_weight: settings.buffer_font.weight,
21827                line_height: relative(settings.buffer_line_height.value()),
21828                ..Default::default()
21829            },
21830        };
21831        if let Some(text_style_refinement) = &self.text_style_refinement {
21832            text_style.refine(text_style_refinement)
21833        }
21834
21835        let background = match self.mode {
21836            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21837            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21838            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21839            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21840        };
21841
21842        EditorElement::new(
21843            &cx.entity(),
21844            EditorStyle {
21845                background,
21846                local_player: cx.theme().players().local(),
21847                text: text_style,
21848                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21849                syntax: cx.theme().syntax().clone(),
21850                status: cx.theme().status().clone(),
21851                inlay_hints_style: make_inlay_hints_style(cx),
21852                inline_completion_styles: make_suggestion_styles(cx),
21853                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21854                show_underlines: !self.mode.is_minimap(),
21855            },
21856        )
21857    }
21858}
21859
21860impl EntityInputHandler for Editor {
21861    fn text_for_range(
21862        &mut self,
21863        range_utf16: Range<usize>,
21864        adjusted_range: &mut Option<Range<usize>>,
21865        _: &mut Window,
21866        cx: &mut Context<Self>,
21867    ) -> Option<String> {
21868        let snapshot = self.buffer.read(cx).read(cx);
21869        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21870        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21871        if (start.0..end.0) != range_utf16 {
21872            adjusted_range.replace(start.0..end.0);
21873        }
21874        Some(snapshot.text_for_range(start..end).collect())
21875    }
21876
21877    fn selected_text_range(
21878        &mut self,
21879        ignore_disabled_input: bool,
21880        _: &mut Window,
21881        cx: &mut Context<Self>,
21882    ) -> Option<UTF16Selection> {
21883        // Prevent the IME menu from appearing when holding down an alphabetic key
21884        // while input is disabled.
21885        if !ignore_disabled_input && !self.input_enabled {
21886            return None;
21887        }
21888
21889        let selection = self.selections.newest::<OffsetUtf16>(cx);
21890        let range = selection.range();
21891
21892        Some(UTF16Selection {
21893            range: range.start.0..range.end.0,
21894            reversed: selection.reversed,
21895        })
21896    }
21897
21898    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21899        let snapshot = self.buffer.read(cx).read(cx);
21900        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21901        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21902    }
21903
21904    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21905        self.clear_highlights::<InputComposition>(cx);
21906        self.ime_transaction.take();
21907    }
21908
21909    fn replace_text_in_range(
21910        &mut self,
21911        range_utf16: Option<Range<usize>>,
21912        text: &str,
21913        window: &mut Window,
21914        cx: &mut Context<Self>,
21915    ) {
21916        if !self.input_enabled {
21917            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21918            return;
21919        }
21920
21921        self.transact(window, cx, |this, window, cx| {
21922            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21923                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21924                Some(this.selection_replacement_ranges(range_utf16, cx))
21925            } else {
21926                this.marked_text_ranges(cx)
21927            };
21928
21929            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21930                let newest_selection_id = this.selections.newest_anchor().id;
21931                this.selections
21932                    .all::<OffsetUtf16>(cx)
21933                    .iter()
21934                    .zip(ranges_to_replace.iter())
21935                    .find_map(|(selection, range)| {
21936                        if selection.id == newest_selection_id {
21937                            Some(
21938                                (range.start.0 as isize - selection.head().0 as isize)
21939                                    ..(range.end.0 as isize - selection.head().0 as isize),
21940                            )
21941                        } else {
21942                            None
21943                        }
21944                    })
21945            });
21946
21947            cx.emit(EditorEvent::InputHandled {
21948                utf16_range_to_replace: range_to_replace,
21949                text: text.into(),
21950            });
21951
21952            if let Some(new_selected_ranges) = new_selected_ranges {
21953                this.change_selections(None, window, cx, |selections| {
21954                    selections.select_ranges(new_selected_ranges)
21955                });
21956                this.backspace(&Default::default(), window, cx);
21957            }
21958
21959            this.handle_input(text, window, cx);
21960        });
21961
21962        if let Some(transaction) = self.ime_transaction {
21963            self.buffer.update(cx, |buffer, cx| {
21964                buffer.group_until_transaction(transaction, cx);
21965            });
21966        }
21967
21968        self.unmark_text(window, cx);
21969    }
21970
21971    fn replace_and_mark_text_in_range(
21972        &mut self,
21973        range_utf16: Option<Range<usize>>,
21974        text: &str,
21975        new_selected_range_utf16: Option<Range<usize>>,
21976        window: &mut Window,
21977        cx: &mut Context<Self>,
21978    ) {
21979        if !self.input_enabled {
21980            return;
21981        }
21982
21983        let transaction = self.transact(window, cx, |this, window, cx| {
21984            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21985                let snapshot = this.buffer.read(cx).read(cx);
21986                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21987                    for marked_range in &mut marked_ranges {
21988                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21989                        marked_range.start.0 += relative_range_utf16.start;
21990                        marked_range.start =
21991                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21992                        marked_range.end =
21993                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21994                    }
21995                }
21996                Some(marked_ranges)
21997            } else if let Some(range_utf16) = range_utf16 {
21998                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21999                Some(this.selection_replacement_ranges(range_utf16, cx))
22000            } else {
22001                None
22002            };
22003
22004            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22005                let newest_selection_id = this.selections.newest_anchor().id;
22006                this.selections
22007                    .all::<OffsetUtf16>(cx)
22008                    .iter()
22009                    .zip(ranges_to_replace.iter())
22010                    .find_map(|(selection, range)| {
22011                        if selection.id == newest_selection_id {
22012                            Some(
22013                                (range.start.0 as isize - selection.head().0 as isize)
22014                                    ..(range.end.0 as isize - selection.head().0 as isize),
22015                            )
22016                        } else {
22017                            None
22018                        }
22019                    })
22020            });
22021
22022            cx.emit(EditorEvent::InputHandled {
22023                utf16_range_to_replace: range_to_replace,
22024                text: text.into(),
22025            });
22026
22027            if let Some(ranges) = ranges_to_replace {
22028                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22029            }
22030
22031            let marked_ranges = {
22032                let snapshot = this.buffer.read(cx).read(cx);
22033                this.selections
22034                    .disjoint_anchors()
22035                    .iter()
22036                    .map(|selection| {
22037                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22038                    })
22039                    .collect::<Vec<_>>()
22040            };
22041
22042            if text.is_empty() {
22043                this.unmark_text(window, cx);
22044            } else {
22045                this.highlight_text::<InputComposition>(
22046                    marked_ranges.clone(),
22047                    HighlightStyle {
22048                        underline: Some(UnderlineStyle {
22049                            thickness: px(1.),
22050                            color: None,
22051                            wavy: false,
22052                        }),
22053                        ..Default::default()
22054                    },
22055                    cx,
22056                );
22057            }
22058
22059            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22060            let use_autoclose = this.use_autoclose;
22061            let use_auto_surround = this.use_auto_surround;
22062            this.set_use_autoclose(false);
22063            this.set_use_auto_surround(false);
22064            this.handle_input(text, window, cx);
22065            this.set_use_autoclose(use_autoclose);
22066            this.set_use_auto_surround(use_auto_surround);
22067
22068            if let Some(new_selected_range) = new_selected_range_utf16 {
22069                let snapshot = this.buffer.read(cx).read(cx);
22070                let new_selected_ranges = marked_ranges
22071                    .into_iter()
22072                    .map(|marked_range| {
22073                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22074                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22075                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22076                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22077                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22078                    })
22079                    .collect::<Vec<_>>();
22080
22081                drop(snapshot);
22082                this.change_selections(None, window, cx, |selections| {
22083                    selections.select_ranges(new_selected_ranges)
22084                });
22085            }
22086        });
22087
22088        self.ime_transaction = self.ime_transaction.or(transaction);
22089        if let Some(transaction) = self.ime_transaction {
22090            self.buffer.update(cx, |buffer, cx| {
22091                buffer.group_until_transaction(transaction, cx);
22092            });
22093        }
22094
22095        if self.text_highlights::<InputComposition>(cx).is_none() {
22096            self.ime_transaction.take();
22097        }
22098    }
22099
22100    fn bounds_for_range(
22101        &mut self,
22102        range_utf16: Range<usize>,
22103        element_bounds: gpui::Bounds<Pixels>,
22104        window: &mut Window,
22105        cx: &mut Context<Self>,
22106    ) -> Option<gpui::Bounds<Pixels>> {
22107        let text_layout_details = self.text_layout_details(window);
22108        let gpui::Size {
22109            width: em_width,
22110            height: line_height,
22111        } = self.character_size(window);
22112
22113        let snapshot = self.snapshot(window, cx);
22114        let scroll_position = snapshot.scroll_position();
22115        let scroll_left = scroll_position.x * em_width;
22116
22117        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22118        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22119            + self.gutter_dimensions.width
22120            + self.gutter_dimensions.margin;
22121        let y = line_height * (start.row().as_f32() - scroll_position.y);
22122
22123        Some(Bounds {
22124            origin: element_bounds.origin + point(x, y),
22125            size: size(em_width, line_height),
22126        })
22127    }
22128
22129    fn character_index_for_point(
22130        &mut self,
22131        point: gpui::Point<Pixels>,
22132        _window: &mut Window,
22133        _cx: &mut Context<Self>,
22134    ) -> Option<usize> {
22135        let position_map = self.last_position_map.as_ref()?;
22136        if !position_map.text_hitbox.contains(&point) {
22137            return None;
22138        }
22139        let display_point = position_map.point_for_position(point).previous_valid;
22140        let anchor = position_map
22141            .snapshot
22142            .display_point_to_anchor(display_point, Bias::Left);
22143        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22144        Some(utf16_offset.0)
22145    }
22146}
22147
22148trait SelectionExt {
22149    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22150    fn spanned_rows(
22151        &self,
22152        include_end_if_at_line_start: bool,
22153        map: &DisplaySnapshot,
22154    ) -> Range<MultiBufferRow>;
22155}
22156
22157impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22158    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22159        let start = self
22160            .start
22161            .to_point(&map.buffer_snapshot)
22162            .to_display_point(map);
22163        let end = self
22164            .end
22165            .to_point(&map.buffer_snapshot)
22166            .to_display_point(map);
22167        if self.reversed {
22168            end..start
22169        } else {
22170            start..end
22171        }
22172    }
22173
22174    fn spanned_rows(
22175        &self,
22176        include_end_if_at_line_start: bool,
22177        map: &DisplaySnapshot,
22178    ) -> Range<MultiBufferRow> {
22179        let start = self.start.to_point(&map.buffer_snapshot);
22180        let mut end = self.end.to_point(&map.buffer_snapshot);
22181        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22182            end.row -= 1;
22183        }
22184
22185        let buffer_start = map.prev_line_boundary(start).0;
22186        let buffer_end = map.next_line_boundary(end).0;
22187        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22188    }
22189}
22190
22191impl<T: InvalidationRegion> InvalidationStack<T> {
22192    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22193    where
22194        S: Clone + ToOffset,
22195    {
22196        while let Some(region) = self.last() {
22197            let all_selections_inside_invalidation_ranges =
22198                if selections.len() == region.ranges().len() {
22199                    selections
22200                        .iter()
22201                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22202                        .all(|(selection, invalidation_range)| {
22203                            let head = selection.head().to_offset(buffer);
22204                            invalidation_range.start <= head && invalidation_range.end >= head
22205                        })
22206                } else {
22207                    false
22208                };
22209
22210            if all_selections_inside_invalidation_ranges {
22211                break;
22212            } else {
22213                self.pop();
22214            }
22215        }
22216    }
22217}
22218
22219impl<T> Default for InvalidationStack<T> {
22220    fn default() -> Self {
22221        Self(Default::default())
22222    }
22223}
22224
22225impl<T> Deref for InvalidationStack<T> {
22226    type Target = Vec<T>;
22227
22228    fn deref(&self) -> &Self::Target {
22229        &self.0
22230    }
22231}
22232
22233impl<T> DerefMut for InvalidationStack<T> {
22234    fn deref_mut(&mut self) -> &mut Self::Target {
22235        &mut self.0
22236    }
22237}
22238
22239impl InvalidationRegion for SnippetState {
22240    fn ranges(&self) -> &[Range<Anchor>] {
22241        &self.ranges[self.active_index]
22242    }
22243}
22244
22245fn inline_completion_edit_text(
22246    current_snapshot: &BufferSnapshot,
22247    edits: &[(Range<Anchor>, String)],
22248    edit_preview: &EditPreview,
22249    include_deletions: bool,
22250    cx: &App,
22251) -> HighlightedText {
22252    let edits = edits
22253        .iter()
22254        .map(|(anchor, text)| {
22255            (
22256                anchor.start.text_anchor..anchor.end.text_anchor,
22257                text.clone(),
22258            )
22259        })
22260        .collect::<Vec<_>>();
22261
22262    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22263}
22264
22265pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22266    match severity {
22267        lsp::DiagnosticSeverity::ERROR => colors.error,
22268        lsp::DiagnosticSeverity::WARNING => colors.warning,
22269        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22270        lsp::DiagnosticSeverity::HINT => colors.info,
22271        _ => colors.ignored,
22272    }
22273}
22274
22275pub fn styled_runs_for_code_label<'a>(
22276    label: &'a CodeLabel,
22277    syntax_theme: &'a theme::SyntaxTheme,
22278) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22279    let fade_out = HighlightStyle {
22280        fade_out: Some(0.35),
22281        ..Default::default()
22282    };
22283
22284    let mut prev_end = label.filter_range.end;
22285    label
22286        .runs
22287        .iter()
22288        .enumerate()
22289        .flat_map(move |(ix, (range, highlight_id))| {
22290            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22291                style
22292            } else {
22293                return Default::default();
22294            };
22295            let mut muted_style = style;
22296            muted_style.highlight(fade_out);
22297
22298            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22299            if range.start >= label.filter_range.end {
22300                if range.start > prev_end {
22301                    runs.push((prev_end..range.start, fade_out));
22302                }
22303                runs.push((range.clone(), muted_style));
22304            } else if range.end <= label.filter_range.end {
22305                runs.push((range.clone(), style));
22306            } else {
22307                runs.push((range.start..label.filter_range.end, style));
22308                runs.push((label.filter_range.end..range.end, muted_style));
22309            }
22310            prev_end = cmp::max(prev_end, range.end);
22311
22312            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22313                runs.push((prev_end..label.text.len(), fade_out));
22314            }
22315
22316            runs
22317        })
22318}
22319
22320pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22321    let mut prev_index = 0;
22322    let mut prev_codepoint: Option<char> = None;
22323    text.char_indices()
22324        .chain([(text.len(), '\0')])
22325        .filter_map(move |(index, codepoint)| {
22326            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22327            let is_boundary = index == text.len()
22328                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22329                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22330            if is_boundary {
22331                let chunk = &text[prev_index..index];
22332                prev_index = index;
22333                Some(chunk)
22334            } else {
22335                None
22336            }
22337        })
22338}
22339
22340pub trait RangeToAnchorExt: Sized {
22341    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22342
22343    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22344        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22345        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22346    }
22347}
22348
22349impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22350    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22351        let start_offset = self.start.to_offset(snapshot);
22352        let end_offset = self.end.to_offset(snapshot);
22353        if start_offset == end_offset {
22354            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22355        } else {
22356            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22357        }
22358    }
22359}
22360
22361pub trait RowExt {
22362    fn as_f32(&self) -> f32;
22363
22364    fn next_row(&self) -> Self;
22365
22366    fn previous_row(&self) -> Self;
22367
22368    fn minus(&self, other: Self) -> u32;
22369}
22370
22371impl RowExt for DisplayRow {
22372    fn as_f32(&self) -> f32 {
22373        self.0 as f32
22374    }
22375
22376    fn next_row(&self) -> Self {
22377        Self(self.0 + 1)
22378    }
22379
22380    fn previous_row(&self) -> Self {
22381        Self(self.0.saturating_sub(1))
22382    }
22383
22384    fn minus(&self, other: Self) -> u32 {
22385        self.0 - other.0
22386    }
22387}
22388
22389impl RowExt for MultiBufferRow {
22390    fn as_f32(&self) -> f32 {
22391        self.0 as f32
22392    }
22393
22394    fn next_row(&self) -> Self {
22395        Self(self.0 + 1)
22396    }
22397
22398    fn previous_row(&self) -> Self {
22399        Self(self.0.saturating_sub(1))
22400    }
22401
22402    fn minus(&self, other: Self) -> u32 {
22403        self.0 - other.0
22404    }
22405}
22406
22407trait RowRangeExt {
22408    type Row;
22409
22410    fn len(&self) -> usize;
22411
22412    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22413}
22414
22415impl RowRangeExt for Range<MultiBufferRow> {
22416    type Row = MultiBufferRow;
22417
22418    fn len(&self) -> usize {
22419        (self.end.0 - self.start.0) as usize
22420    }
22421
22422    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22423        (self.start.0..self.end.0).map(MultiBufferRow)
22424    }
22425}
22426
22427impl RowRangeExt for Range<DisplayRow> {
22428    type Row = DisplayRow;
22429
22430    fn len(&self) -> usize {
22431        (self.end.0 - self.start.0) as usize
22432    }
22433
22434    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22435        (self.start.0..self.end.0).map(DisplayRow)
22436    }
22437}
22438
22439/// If select range has more than one line, we
22440/// just point the cursor to range.start.
22441fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22442    if range.start.row == range.end.row {
22443        range
22444    } else {
22445        range.start..range.start
22446    }
22447}
22448pub struct KillRing(ClipboardItem);
22449impl Global for KillRing {}
22450
22451const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22452
22453enum BreakpointPromptEditAction {
22454    Log,
22455    Condition,
22456    HitCondition,
22457}
22458
22459struct BreakpointPromptEditor {
22460    pub(crate) prompt: Entity<Editor>,
22461    editor: WeakEntity<Editor>,
22462    breakpoint_anchor: Anchor,
22463    breakpoint: Breakpoint,
22464    edit_action: BreakpointPromptEditAction,
22465    block_ids: HashSet<CustomBlockId>,
22466    editor_margins: Arc<Mutex<EditorMargins>>,
22467    _subscriptions: Vec<Subscription>,
22468}
22469
22470impl BreakpointPromptEditor {
22471    const MAX_LINES: u8 = 4;
22472
22473    fn new(
22474        editor: WeakEntity<Editor>,
22475        breakpoint_anchor: Anchor,
22476        breakpoint: Breakpoint,
22477        edit_action: BreakpointPromptEditAction,
22478        window: &mut Window,
22479        cx: &mut Context<Self>,
22480    ) -> Self {
22481        let base_text = match edit_action {
22482            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22483            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22484            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22485        }
22486        .map(|msg| msg.to_string())
22487        .unwrap_or_default();
22488
22489        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22490        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22491
22492        let prompt = cx.new(|cx| {
22493            let mut prompt = Editor::new(
22494                EditorMode::AutoHeight {
22495                    max_lines: Self::MAX_LINES as usize,
22496                },
22497                buffer,
22498                None,
22499                window,
22500                cx,
22501            );
22502            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22503            prompt.set_show_cursor_when_unfocused(false, cx);
22504            prompt.set_placeholder_text(
22505                match edit_action {
22506                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22507                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22508                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22509                },
22510                cx,
22511            );
22512
22513            prompt
22514        });
22515
22516        Self {
22517            prompt,
22518            editor,
22519            breakpoint_anchor,
22520            breakpoint,
22521            edit_action,
22522            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22523            block_ids: Default::default(),
22524            _subscriptions: vec![],
22525        }
22526    }
22527
22528    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22529        self.block_ids.extend(block_ids)
22530    }
22531
22532    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22533        if let Some(editor) = self.editor.upgrade() {
22534            let message = self
22535                .prompt
22536                .read(cx)
22537                .buffer
22538                .read(cx)
22539                .as_singleton()
22540                .expect("A multi buffer in breakpoint prompt isn't possible")
22541                .read(cx)
22542                .as_rope()
22543                .to_string();
22544
22545            editor.update(cx, |editor, cx| {
22546                editor.edit_breakpoint_at_anchor(
22547                    self.breakpoint_anchor,
22548                    self.breakpoint.clone(),
22549                    match self.edit_action {
22550                        BreakpointPromptEditAction::Log => {
22551                            BreakpointEditAction::EditLogMessage(message.into())
22552                        }
22553                        BreakpointPromptEditAction::Condition => {
22554                            BreakpointEditAction::EditCondition(message.into())
22555                        }
22556                        BreakpointPromptEditAction::HitCondition => {
22557                            BreakpointEditAction::EditHitCondition(message.into())
22558                        }
22559                    },
22560                    cx,
22561                );
22562
22563                editor.remove_blocks(self.block_ids.clone(), None, cx);
22564                cx.focus_self(window);
22565            });
22566        }
22567    }
22568
22569    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22570        self.editor
22571            .update(cx, |editor, cx| {
22572                editor.remove_blocks(self.block_ids.clone(), None, cx);
22573                window.focus(&editor.focus_handle);
22574            })
22575            .log_err();
22576    }
22577
22578    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22579        let settings = ThemeSettings::get_global(cx);
22580        let text_style = TextStyle {
22581            color: if self.prompt.read(cx).read_only(cx) {
22582                cx.theme().colors().text_disabled
22583            } else {
22584                cx.theme().colors().text
22585            },
22586            font_family: settings.buffer_font.family.clone(),
22587            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22588            font_size: settings.buffer_font_size(cx).into(),
22589            font_weight: settings.buffer_font.weight,
22590            line_height: relative(settings.buffer_line_height.value()),
22591            ..Default::default()
22592        };
22593        EditorElement::new(
22594            &self.prompt,
22595            EditorStyle {
22596                background: cx.theme().colors().editor_background,
22597                local_player: cx.theme().players().local(),
22598                text: text_style,
22599                ..Default::default()
22600            },
22601        )
22602    }
22603}
22604
22605impl Render for BreakpointPromptEditor {
22606    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22607        let editor_margins = *self.editor_margins.lock();
22608        let gutter_dimensions = editor_margins.gutter;
22609        h_flex()
22610            .key_context("Editor")
22611            .bg(cx.theme().colors().editor_background)
22612            .border_y_1()
22613            .border_color(cx.theme().status().info_border)
22614            .size_full()
22615            .py(window.line_height() / 2.5)
22616            .on_action(cx.listener(Self::confirm))
22617            .on_action(cx.listener(Self::cancel))
22618            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22619            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22620    }
22621}
22622
22623impl Focusable for BreakpointPromptEditor {
22624    fn focus_handle(&self, cx: &App) -> FocusHandle {
22625        self.prompt.focus_handle(cx)
22626    }
22627}
22628
22629fn all_edits_insertions_or_deletions(
22630    edits: &Vec<(Range<Anchor>, String)>,
22631    snapshot: &MultiBufferSnapshot,
22632) -> bool {
22633    let mut all_insertions = true;
22634    let mut all_deletions = true;
22635
22636    for (range, new_text) in edits.iter() {
22637        let range_is_empty = range.to_offset(&snapshot).is_empty();
22638        let text_is_empty = new_text.is_empty();
22639
22640        if range_is_empty != text_is_empty {
22641            if range_is_empty {
22642                all_deletions = false;
22643            } else {
22644                all_insertions = false;
22645            }
22646        } else {
22647            return false;
22648        }
22649
22650        if !all_insertions && !all_deletions {
22651            return false;
22652        }
22653    }
22654    all_insertions || all_deletions
22655}
22656
22657struct MissingEditPredictionKeybindingTooltip;
22658
22659impl Render for MissingEditPredictionKeybindingTooltip {
22660    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22661        ui::tooltip_container(window, cx, |container, _, cx| {
22662            container
22663                .flex_shrink_0()
22664                .max_w_80()
22665                .min_h(rems_from_px(124.))
22666                .justify_between()
22667                .child(
22668                    v_flex()
22669                        .flex_1()
22670                        .text_ui_sm(cx)
22671                        .child(Label::new("Conflict with Accept Keybinding"))
22672                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22673                )
22674                .child(
22675                    h_flex()
22676                        .pb_1()
22677                        .gap_1()
22678                        .items_end()
22679                        .w_full()
22680                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22681                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22682                        }))
22683                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22684                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22685                        })),
22686                )
22687        })
22688    }
22689}
22690
22691#[derive(Debug, Clone, Copy, PartialEq)]
22692pub struct LineHighlight {
22693    pub background: Background,
22694    pub border: Option<gpui::Hsla>,
22695    pub include_gutter: bool,
22696    pub type_id: Option<TypeId>,
22697}
22698
22699fn render_diff_hunk_controls(
22700    row: u32,
22701    status: &DiffHunkStatus,
22702    hunk_range: Range<Anchor>,
22703    is_created_file: bool,
22704    line_height: Pixels,
22705    editor: &Entity<Editor>,
22706    _window: &mut Window,
22707    cx: &mut App,
22708) -> AnyElement {
22709    h_flex()
22710        .h(line_height)
22711        .mr_1()
22712        .gap_1()
22713        .px_0p5()
22714        .pb_1()
22715        .border_x_1()
22716        .border_b_1()
22717        .border_color(cx.theme().colors().border_variant)
22718        .rounded_b_lg()
22719        .bg(cx.theme().colors().editor_background)
22720        .gap_1()
22721        .block_mouse_except_scroll()
22722        .shadow_md()
22723        .child(if status.has_secondary_hunk() {
22724            Button::new(("stage", row as u64), "Stage")
22725                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22726                .tooltip({
22727                    let focus_handle = editor.focus_handle(cx);
22728                    move |window, cx| {
22729                        Tooltip::for_action_in(
22730                            "Stage Hunk",
22731                            &::git::ToggleStaged,
22732                            &focus_handle,
22733                            window,
22734                            cx,
22735                        )
22736                    }
22737                })
22738                .on_click({
22739                    let editor = editor.clone();
22740                    move |_event, _window, cx| {
22741                        editor.update(cx, |editor, cx| {
22742                            editor.stage_or_unstage_diff_hunks(
22743                                true,
22744                                vec![hunk_range.start..hunk_range.start],
22745                                cx,
22746                            );
22747                        });
22748                    }
22749                })
22750        } else {
22751            Button::new(("unstage", row as u64), "Unstage")
22752                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22753                .tooltip({
22754                    let focus_handle = editor.focus_handle(cx);
22755                    move |window, cx| {
22756                        Tooltip::for_action_in(
22757                            "Unstage Hunk",
22758                            &::git::ToggleStaged,
22759                            &focus_handle,
22760                            window,
22761                            cx,
22762                        )
22763                    }
22764                })
22765                .on_click({
22766                    let editor = editor.clone();
22767                    move |_event, _window, cx| {
22768                        editor.update(cx, |editor, cx| {
22769                            editor.stage_or_unstage_diff_hunks(
22770                                false,
22771                                vec![hunk_range.start..hunk_range.start],
22772                                cx,
22773                            );
22774                        });
22775                    }
22776                })
22777        })
22778        .child(
22779            Button::new(("restore", row as u64), "Restore")
22780                .tooltip({
22781                    let focus_handle = editor.focus_handle(cx);
22782                    move |window, cx| {
22783                        Tooltip::for_action_in(
22784                            "Restore Hunk",
22785                            &::git::Restore,
22786                            &focus_handle,
22787                            window,
22788                            cx,
22789                        )
22790                    }
22791                })
22792                .on_click({
22793                    let editor = editor.clone();
22794                    move |_event, window, cx| {
22795                        editor.update(cx, |editor, cx| {
22796                            let snapshot = editor.snapshot(window, cx);
22797                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22798                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22799                        });
22800                    }
22801                })
22802                .disabled(is_created_file),
22803        )
22804        .when(
22805            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22806            |el| {
22807                el.child(
22808                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22809                        .shape(IconButtonShape::Square)
22810                        .icon_size(IconSize::Small)
22811                        // .disabled(!has_multiple_hunks)
22812                        .tooltip({
22813                            let focus_handle = editor.focus_handle(cx);
22814                            move |window, cx| {
22815                                Tooltip::for_action_in(
22816                                    "Next Hunk",
22817                                    &GoToHunk,
22818                                    &focus_handle,
22819                                    window,
22820                                    cx,
22821                                )
22822                            }
22823                        })
22824                        .on_click({
22825                            let editor = editor.clone();
22826                            move |_event, window, cx| {
22827                                editor.update(cx, |editor, cx| {
22828                                    let snapshot = editor.snapshot(window, cx);
22829                                    let position =
22830                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22831                                    editor.go_to_hunk_before_or_after_position(
22832                                        &snapshot,
22833                                        position,
22834                                        Direction::Next,
22835                                        window,
22836                                        cx,
22837                                    );
22838                                    editor.expand_selected_diff_hunks(cx);
22839                                });
22840                            }
22841                        }),
22842                )
22843                .child(
22844                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22845                        .shape(IconButtonShape::Square)
22846                        .icon_size(IconSize::Small)
22847                        // .disabled(!has_multiple_hunks)
22848                        .tooltip({
22849                            let focus_handle = editor.focus_handle(cx);
22850                            move |window, cx| {
22851                                Tooltip::for_action_in(
22852                                    "Previous Hunk",
22853                                    &GoToPreviousHunk,
22854                                    &focus_handle,
22855                                    window,
22856                                    cx,
22857                                )
22858                            }
22859                        })
22860                        .on_click({
22861                            let editor = editor.clone();
22862                            move |_event, window, cx| {
22863                                editor.update(cx, |editor, cx| {
22864                                    let snapshot = editor.snapshot(window, cx);
22865                                    let point =
22866                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22867                                    editor.go_to_hunk_before_or_after_position(
22868                                        &snapshot,
22869                                        point,
22870                                        Direction::Prev,
22871                                        window,
22872                                        cx,
22873                                    );
22874                                    editor.expand_selected_diff_hunks(cx);
22875                                });
22876                            }
22877                        }),
22878                )
22879            },
22880        )
22881        .into_any_element()
22882}