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, Theme, 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
  699#[derive(Clone)]
  700pub struct BackgroundHighlight {
  701    pub range: Range<Anchor>,
  702    pub color_fetcher: fn(&Theme) -> Hsla,
  703}
  704
  705type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  706
  707#[derive(Default)]
  708struct ScrollbarMarkerState {
  709    scrollbar_size: Size<Pixels>,
  710    dirty: bool,
  711    markers: Arc<[PaintQuad]>,
  712    pending_refresh: Option<Task<Result<()>>>,
  713}
  714
  715impl ScrollbarMarkerState {
  716    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  717        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  718    }
  719}
  720
  721#[derive(Clone, Copy, PartialEq, Eq)]
  722pub enum MinimapVisibility {
  723    Disabled,
  724    Enabled {
  725        /// The configuration currently present in the users settings.
  726        setting_configuration: bool,
  727        /// Whether to override the currently set visibility from the users setting.
  728        toggle_override: bool,
  729    },
  730}
  731
  732impl MinimapVisibility {
  733    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  734        if mode.is_full() {
  735            Self::Enabled {
  736                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  737                toggle_override: false,
  738            }
  739        } else {
  740            Self::Disabled
  741        }
  742    }
  743
  744    fn hidden(&self) -> Self {
  745        match *self {
  746            Self::Enabled {
  747                setting_configuration,
  748                ..
  749            } => Self::Enabled {
  750                setting_configuration,
  751                toggle_override: setting_configuration,
  752            },
  753            Self::Disabled => Self::Disabled,
  754        }
  755    }
  756
  757    fn disabled(&self) -> bool {
  758        match *self {
  759            Self::Disabled => true,
  760            _ => false,
  761        }
  762    }
  763
  764    fn settings_visibility(&self) -> bool {
  765        match *self {
  766            Self::Enabled {
  767                setting_configuration,
  768                ..
  769            } => setting_configuration,
  770            _ => false,
  771        }
  772    }
  773
  774    fn visible(&self) -> bool {
  775        match *self {
  776            Self::Enabled {
  777                setting_configuration,
  778                toggle_override,
  779            } => setting_configuration ^ toggle_override,
  780            _ => false,
  781        }
  782    }
  783
  784    fn toggle_visibility(&self) -> Self {
  785        match *self {
  786            Self::Enabled {
  787                toggle_override,
  788                setting_configuration,
  789            } => Self::Enabled {
  790                setting_configuration,
  791                toggle_override: !toggle_override,
  792            },
  793            Self::Disabled => Self::Disabled,
  794        }
  795    }
  796}
  797
  798#[derive(Clone, Debug)]
  799struct RunnableTasks {
  800    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  801    offset: multi_buffer::Anchor,
  802    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  803    column: u32,
  804    // Values of all named captures, including those starting with '_'
  805    extra_variables: HashMap<String, String>,
  806    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  807    context_range: Range<BufferOffset>,
  808}
  809
  810impl RunnableTasks {
  811    fn resolve<'a>(
  812        &'a self,
  813        cx: &'a task::TaskContext,
  814    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  815        self.templates.iter().filter_map(|(kind, template)| {
  816            template
  817                .resolve_task(&kind.to_id_base(), cx)
  818                .map(|task| (kind.clone(), task))
  819        })
  820    }
  821}
  822
  823#[derive(Clone)]
  824pub struct ResolvedTasks {
  825    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  826    position: Anchor,
  827}
  828
  829#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  830struct BufferOffset(usize);
  831
  832// Addons allow storing per-editor state in other crates (e.g. Vim)
  833pub trait Addon: 'static {
  834    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  835
  836    fn render_buffer_header_controls(
  837        &self,
  838        _: &ExcerptInfo,
  839        _: &Window,
  840        _: &App,
  841    ) -> Option<AnyElement> {
  842        None
  843    }
  844
  845    fn to_any(&self) -> &dyn std::any::Any;
  846
  847    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  848        None
  849    }
  850}
  851
  852/// A set of caret positions, registered when the editor was edited.
  853pub struct ChangeList {
  854    changes: Vec<Vec<Anchor>>,
  855    /// Currently "selected" change.
  856    position: Option<usize>,
  857}
  858
  859impl ChangeList {
  860    pub fn new() -> Self {
  861        Self {
  862            changes: Vec::new(),
  863            position: None,
  864        }
  865    }
  866
  867    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  868    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  869    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  870        if self.changes.is_empty() {
  871            return None;
  872        }
  873
  874        let prev = self.position.unwrap_or(self.changes.len());
  875        let next = if direction == Direction::Prev {
  876            prev.saturating_sub(count)
  877        } else {
  878            (prev + count).min(self.changes.len() - 1)
  879        };
  880        self.position = Some(next);
  881        self.changes.get(next).map(|anchors| anchors.as_slice())
  882    }
  883
  884    /// Adds a new change to the list, resetting the change list position.
  885    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  886        self.position.take();
  887        if pop_state {
  888            self.changes.pop();
  889        }
  890        self.changes.push(new_positions.clone());
  891    }
  892
  893    pub fn last(&self) -> Option<&[Anchor]> {
  894        self.changes.last().map(|anchors| anchors.as_slice())
  895    }
  896}
  897
  898#[derive(Clone)]
  899struct InlineBlamePopoverState {
  900    scroll_handle: ScrollHandle,
  901    commit_message: Option<ParsedCommitMessage>,
  902    markdown: Entity<Markdown>,
  903}
  904
  905struct InlineBlamePopover {
  906    position: gpui::Point<Pixels>,
  907    show_task: Option<Task<()>>,
  908    hide_task: Option<Task<()>>,
  909    popover_bounds: Option<Bounds<Pixels>>,
  910    popover_state: InlineBlamePopoverState,
  911}
  912
  913enum SelectionDragState {
  914    /// State when no drag related activity is detected.
  915    None,
  916    /// State when the mouse is down on a selection that is about to be dragged.
  917    ReadyToDrag {
  918        selection: Selection<Anchor>,
  919        click_position: gpui::Point<Pixels>,
  920    },
  921    /// State when the mouse is dragging the selection in the editor.
  922    Dragging {
  923        selection: Selection<Anchor>,
  924        drop_cursor: Selection<Anchor>,
  925        hide_drop_cursor: bool,
  926    },
  927}
  928
  929/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  930/// a breakpoint on them.
  931#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  932struct PhantomBreakpointIndicator {
  933    display_row: DisplayRow,
  934    /// There's a small debounce between hovering over the line and showing the indicator.
  935    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  936    is_active: bool,
  937    collides_with_existing_breakpoint: bool,
  938}
  939
  940/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  941///
  942/// See the [module level documentation](self) for more information.
  943pub struct Editor {
  944    focus_handle: FocusHandle,
  945    last_focused_descendant: Option<WeakFocusHandle>,
  946    /// The text buffer being edited
  947    buffer: Entity<MultiBuffer>,
  948    /// Map of how text in the buffer should be displayed.
  949    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  950    pub display_map: Entity<DisplayMap>,
  951    pub selections: SelectionsCollection,
  952    pub scroll_manager: ScrollManager,
  953    /// When inline assist editors are linked, they all render cursors because
  954    /// typing enters text into each of them, even the ones that aren't focused.
  955    pub(crate) show_cursor_when_unfocused: bool,
  956    columnar_selection_tail: Option<Anchor>,
  957    columnar_display_point: Option<DisplayPoint>,
  958    add_selections_state: Option<AddSelectionsState>,
  959    select_next_state: Option<SelectNextState>,
  960    select_prev_state: Option<SelectNextState>,
  961    selection_history: SelectionHistory,
  962    defer_selection_effects: bool,
  963    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  964    autoclose_regions: Vec<AutocloseRegion>,
  965    snippet_stack: InvalidationStack<SnippetState>,
  966    select_syntax_node_history: SelectSyntaxNodeHistory,
  967    ime_transaction: Option<TransactionId>,
  968    pub diagnostics_max_severity: DiagnosticSeverity,
  969    active_diagnostics: ActiveDiagnostic,
  970    show_inline_diagnostics: bool,
  971    inline_diagnostics_update: Task<()>,
  972    inline_diagnostics_enabled: bool,
  973    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  974    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  975    hard_wrap: Option<usize>,
  976
  977    // TODO: make this a access method
  978    pub project: Option<Entity<Project>>,
  979    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  980    completion_provider: Option<Rc<dyn CompletionProvider>>,
  981    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  982    blink_manager: Entity<BlinkManager>,
  983    show_cursor_names: bool,
  984    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  985    pub show_local_selections: bool,
  986    mode: EditorMode,
  987    show_breadcrumbs: bool,
  988    show_gutter: bool,
  989    show_scrollbars: ScrollbarAxes,
  990    minimap_visibility: MinimapVisibility,
  991    offset_content: bool,
  992    disable_expand_excerpt_buttons: bool,
  993    show_line_numbers: Option<bool>,
  994    use_relative_line_numbers: Option<bool>,
  995    show_git_diff_gutter: Option<bool>,
  996    show_code_actions: Option<bool>,
  997    show_runnables: Option<bool>,
  998    show_breakpoints: Option<bool>,
  999    show_wrap_guides: Option<bool>,
 1000    show_indent_guides: Option<bool>,
 1001    placeholder_text: Option<Arc<str>>,
 1002    highlight_order: usize,
 1003    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1004    background_highlights: TreeMap<TypeId, Vec<BackgroundHighlight>>,
 1005    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1006    scrollbar_marker_state: ScrollbarMarkerState,
 1007    active_indent_guides_state: ActiveIndentGuidesState,
 1008    nav_history: Option<ItemNavHistory>,
 1009    context_menu: RefCell<Option<CodeContextMenu>>,
 1010    context_menu_options: Option<ContextMenuOptions>,
 1011    mouse_context_menu: Option<MouseContextMenu>,
 1012    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1013    inline_blame_popover: Option<InlineBlamePopover>,
 1014    signature_help_state: SignatureHelpState,
 1015    auto_signature_help: Option<bool>,
 1016    find_all_references_task_sources: Vec<Anchor>,
 1017    next_completion_id: CompletionId,
 1018    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1019    code_actions_task: Option<Task<Result<()>>>,
 1020    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1021    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1022    document_highlights_task: Option<Task<()>>,
 1023    linked_editing_range_task: Option<Task<Option<()>>>,
 1024    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1025    pending_rename: Option<RenameState>,
 1026    searchable: bool,
 1027    cursor_shape: CursorShape,
 1028    current_line_highlight: Option<CurrentLineHighlight>,
 1029    collapse_matches: bool,
 1030    autoindent_mode: Option<AutoindentMode>,
 1031    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1032    input_enabled: bool,
 1033    use_modal_editing: bool,
 1034    read_only: bool,
 1035    leader_id: Option<CollaboratorId>,
 1036    remote_id: Option<ViewId>,
 1037    pub hover_state: HoverState,
 1038    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1039    gutter_hovered: bool,
 1040    hovered_link_state: Option<HoveredLinkState>,
 1041    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1042    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1043    active_inline_completion: Option<InlineCompletionState>,
 1044    /// Used to prevent flickering as the user types while the menu is open
 1045    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1046    edit_prediction_settings: EditPredictionSettings,
 1047    inline_completions_hidden_for_vim_mode: bool,
 1048    show_inline_completions_override: Option<bool>,
 1049    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1050    edit_prediction_preview: EditPredictionPreview,
 1051    edit_prediction_indent_conflict: bool,
 1052    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1053    inlay_hint_cache: InlayHintCache,
 1054    next_inlay_id: usize,
 1055    _subscriptions: Vec<Subscription>,
 1056    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1057    gutter_dimensions: GutterDimensions,
 1058    style: Option<EditorStyle>,
 1059    text_style_refinement: Option<TextStyleRefinement>,
 1060    next_editor_action_id: EditorActionId,
 1061    editor_actions: Rc<
 1062        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1063    >,
 1064    use_autoclose: bool,
 1065    use_auto_surround: bool,
 1066    auto_replace_emoji_shortcode: bool,
 1067    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1068    show_git_blame_gutter: bool,
 1069    show_git_blame_inline: bool,
 1070    show_git_blame_inline_delay_task: Option<Task<()>>,
 1071    git_blame_inline_enabled: bool,
 1072    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1073    serialize_dirty_buffers: bool,
 1074    show_selection_menu: Option<bool>,
 1075    blame: Option<Entity<GitBlame>>,
 1076    blame_subscription: Option<Subscription>,
 1077    custom_context_menu: Option<
 1078        Box<
 1079            dyn 'static
 1080                + Fn(
 1081                    &mut Self,
 1082                    DisplayPoint,
 1083                    &mut Window,
 1084                    &mut Context<Self>,
 1085                ) -> Option<Entity<ui::ContextMenu>>,
 1086        >,
 1087    >,
 1088    last_bounds: Option<Bounds<Pixels>>,
 1089    last_position_map: Option<Rc<PositionMap>>,
 1090    expect_bounds_change: Option<Bounds<Pixels>>,
 1091    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1092    tasks_update_task: Option<Task<()>>,
 1093    breakpoint_store: Option<Entity<BreakpointStore>>,
 1094    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1095    pull_diagnostics_task: Task<()>,
 1096    in_project_search: bool,
 1097    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1098    breadcrumb_header: Option<String>,
 1099    focused_block: Option<FocusedBlock>,
 1100    next_scroll_position: NextScrollCursorCenterTopBottom,
 1101    addons: HashMap<TypeId, Box<dyn Addon>>,
 1102    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1103    load_diff_task: Option<Shared<Task<()>>>,
 1104    /// Whether we are temporarily displaying a diff other than git's
 1105    temporary_diff_override: bool,
 1106    selection_mark_mode: bool,
 1107    toggle_fold_multiple_buffers: Task<()>,
 1108    _scroll_cursor_center_top_bottom_task: Task<()>,
 1109    serialize_selections: Task<()>,
 1110    serialize_folds: Task<()>,
 1111    mouse_cursor_hidden: bool,
 1112    minimap: Option<Entity<Self>>,
 1113    hide_mouse_mode: HideMouseMode,
 1114    pub change_list: ChangeList,
 1115    inline_value_cache: InlineValueCache,
 1116    selection_drag_state: SelectionDragState,
 1117    drag_and_drop_selection_enabled: bool,
 1118}
 1119
 1120#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1121enum NextScrollCursorCenterTopBottom {
 1122    #[default]
 1123    Center,
 1124    Top,
 1125    Bottom,
 1126}
 1127
 1128impl NextScrollCursorCenterTopBottom {
 1129    fn next(&self) -> Self {
 1130        match self {
 1131            Self::Center => Self::Top,
 1132            Self::Top => Self::Bottom,
 1133            Self::Bottom => Self::Center,
 1134        }
 1135    }
 1136}
 1137
 1138#[derive(Clone)]
 1139pub struct EditorSnapshot {
 1140    pub mode: EditorMode,
 1141    show_gutter: bool,
 1142    show_line_numbers: Option<bool>,
 1143    show_git_diff_gutter: Option<bool>,
 1144    show_code_actions: Option<bool>,
 1145    show_runnables: Option<bool>,
 1146    show_breakpoints: Option<bool>,
 1147    git_blame_gutter_max_author_length: Option<usize>,
 1148    pub display_snapshot: DisplaySnapshot,
 1149    pub placeholder_text: Option<Arc<str>>,
 1150    is_focused: bool,
 1151    scroll_anchor: ScrollAnchor,
 1152    ongoing_scroll: OngoingScroll,
 1153    current_line_highlight: CurrentLineHighlight,
 1154    gutter_hovered: bool,
 1155}
 1156
 1157#[derive(Default, Debug, Clone, Copy)]
 1158pub struct GutterDimensions {
 1159    pub left_padding: Pixels,
 1160    pub right_padding: Pixels,
 1161    pub width: Pixels,
 1162    pub margin: Pixels,
 1163    pub git_blame_entries_width: Option<Pixels>,
 1164}
 1165
 1166impl GutterDimensions {
 1167    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1168        Self {
 1169            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1170            ..Default::default()
 1171        }
 1172    }
 1173
 1174    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1175        -cx.text_system().descent(font_id, font_size)
 1176    }
 1177    /// The full width of the space taken up by the gutter.
 1178    pub fn full_width(&self) -> Pixels {
 1179        self.margin + self.width
 1180    }
 1181
 1182    /// The width of the space reserved for the fold indicators,
 1183    /// use alongside 'justify_end' and `gutter_width` to
 1184    /// right align content with the line numbers
 1185    pub fn fold_area_width(&self) -> Pixels {
 1186        self.margin + self.right_padding
 1187    }
 1188}
 1189
 1190#[derive(Debug)]
 1191pub struct RemoteSelection {
 1192    pub replica_id: ReplicaId,
 1193    pub selection: Selection<Anchor>,
 1194    pub cursor_shape: CursorShape,
 1195    pub collaborator_id: CollaboratorId,
 1196    pub line_mode: bool,
 1197    pub user_name: Option<SharedString>,
 1198    pub color: PlayerColor,
 1199}
 1200
 1201#[derive(Clone, Debug)]
 1202struct SelectionHistoryEntry {
 1203    selections: Arc<[Selection<Anchor>]>,
 1204    select_next_state: Option<SelectNextState>,
 1205    select_prev_state: Option<SelectNextState>,
 1206    add_selections_state: Option<AddSelectionsState>,
 1207}
 1208
 1209#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1210enum SelectionHistoryMode {
 1211    Normal,
 1212    Undoing,
 1213    Redoing,
 1214    Skipping,
 1215}
 1216
 1217#[derive(Clone, PartialEq, Eq, Hash)]
 1218struct HoveredCursor {
 1219    replica_id: u16,
 1220    selection_id: usize,
 1221}
 1222
 1223impl Default for SelectionHistoryMode {
 1224    fn default() -> Self {
 1225        Self::Normal
 1226    }
 1227}
 1228
 1229struct DeferredSelectionEffectsState {
 1230    changed: bool,
 1231    should_update_completions: bool,
 1232    autoscroll: Option<Autoscroll>,
 1233    old_cursor_position: Anchor,
 1234    history_entry: SelectionHistoryEntry,
 1235}
 1236
 1237#[derive(Default)]
 1238struct SelectionHistory {
 1239    #[allow(clippy::type_complexity)]
 1240    selections_by_transaction:
 1241        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1242    mode: SelectionHistoryMode,
 1243    undo_stack: VecDeque<SelectionHistoryEntry>,
 1244    redo_stack: VecDeque<SelectionHistoryEntry>,
 1245}
 1246
 1247impl SelectionHistory {
 1248    #[track_caller]
 1249    fn insert_transaction(
 1250        &mut self,
 1251        transaction_id: TransactionId,
 1252        selections: Arc<[Selection<Anchor>]>,
 1253    ) {
 1254        if selections.is_empty() {
 1255            log::error!(
 1256                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1257                std::panic::Location::caller()
 1258            );
 1259            return;
 1260        }
 1261        self.selections_by_transaction
 1262            .insert(transaction_id, (selections, None));
 1263    }
 1264
 1265    #[allow(clippy::type_complexity)]
 1266    fn transaction(
 1267        &self,
 1268        transaction_id: TransactionId,
 1269    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1270        self.selections_by_transaction.get(&transaction_id)
 1271    }
 1272
 1273    #[allow(clippy::type_complexity)]
 1274    fn transaction_mut(
 1275        &mut self,
 1276        transaction_id: TransactionId,
 1277    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1278        self.selections_by_transaction.get_mut(&transaction_id)
 1279    }
 1280
 1281    fn push(&mut self, entry: SelectionHistoryEntry) {
 1282        if !entry.selections.is_empty() {
 1283            match self.mode {
 1284                SelectionHistoryMode::Normal => {
 1285                    self.push_undo(entry);
 1286                    self.redo_stack.clear();
 1287                }
 1288                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1289                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1290                SelectionHistoryMode::Skipping => {}
 1291            }
 1292        }
 1293    }
 1294
 1295    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1296        if self
 1297            .undo_stack
 1298            .back()
 1299            .map_or(true, |e| e.selections != entry.selections)
 1300        {
 1301            self.undo_stack.push_back(entry);
 1302            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1303                self.undo_stack.pop_front();
 1304            }
 1305        }
 1306    }
 1307
 1308    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1309        if self
 1310            .redo_stack
 1311            .back()
 1312            .map_or(true, |e| e.selections != entry.selections)
 1313        {
 1314            self.redo_stack.push_back(entry);
 1315            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1316                self.redo_stack.pop_front();
 1317            }
 1318        }
 1319    }
 1320}
 1321
 1322#[derive(Clone, Copy)]
 1323pub struct RowHighlightOptions {
 1324    pub autoscroll: bool,
 1325    pub include_gutter: bool,
 1326}
 1327
 1328impl Default for RowHighlightOptions {
 1329    fn default() -> Self {
 1330        Self {
 1331            autoscroll: Default::default(),
 1332            include_gutter: true,
 1333        }
 1334    }
 1335}
 1336
 1337struct RowHighlight {
 1338    index: usize,
 1339    range: Range<Anchor>,
 1340    color: Hsla,
 1341    options: RowHighlightOptions,
 1342    type_id: TypeId,
 1343}
 1344
 1345#[derive(Clone, Debug)]
 1346struct AddSelectionsState {
 1347    groups: Vec<AddSelectionsGroup>,
 1348}
 1349
 1350#[derive(Clone, Debug)]
 1351struct AddSelectionsGroup {
 1352    above: bool,
 1353    stack: Vec<usize>,
 1354}
 1355
 1356#[derive(Clone)]
 1357struct SelectNextState {
 1358    query: AhoCorasick,
 1359    wordwise: bool,
 1360    done: bool,
 1361}
 1362
 1363impl std::fmt::Debug for SelectNextState {
 1364    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1365        f.debug_struct(std::any::type_name::<Self>())
 1366            .field("wordwise", &self.wordwise)
 1367            .field("done", &self.done)
 1368            .finish()
 1369    }
 1370}
 1371
 1372#[derive(Debug)]
 1373struct AutocloseRegion {
 1374    selection_id: usize,
 1375    range: Range<Anchor>,
 1376    pair: BracketPair,
 1377}
 1378
 1379#[derive(Debug)]
 1380struct SnippetState {
 1381    ranges: Vec<Vec<Range<Anchor>>>,
 1382    active_index: usize,
 1383    choices: Vec<Option<Vec<String>>>,
 1384}
 1385
 1386#[doc(hidden)]
 1387pub struct RenameState {
 1388    pub range: Range<Anchor>,
 1389    pub old_name: Arc<str>,
 1390    pub editor: Entity<Editor>,
 1391    block_id: CustomBlockId,
 1392}
 1393
 1394struct InvalidationStack<T>(Vec<T>);
 1395
 1396struct RegisteredInlineCompletionProvider {
 1397    provider: Arc<dyn InlineCompletionProviderHandle>,
 1398    _subscription: Subscription,
 1399}
 1400
 1401#[derive(Debug, PartialEq, Eq)]
 1402pub struct ActiveDiagnosticGroup {
 1403    pub active_range: Range<Anchor>,
 1404    pub active_message: String,
 1405    pub group_id: usize,
 1406    pub blocks: HashSet<CustomBlockId>,
 1407}
 1408
 1409#[derive(Debug, PartialEq, Eq)]
 1410
 1411pub(crate) enum ActiveDiagnostic {
 1412    None,
 1413    All,
 1414    Group(ActiveDiagnosticGroup),
 1415}
 1416
 1417#[derive(Serialize, Deserialize, Clone, Debug)]
 1418pub struct ClipboardSelection {
 1419    /// The number of bytes in this selection.
 1420    pub len: usize,
 1421    /// Whether this was a full-line selection.
 1422    pub is_entire_line: bool,
 1423    /// The indentation of the first line when this content was originally copied.
 1424    pub first_line_indent: u32,
 1425}
 1426
 1427// selections, scroll behavior, was newest selection reversed
 1428type SelectSyntaxNodeHistoryState = (
 1429    Box<[Selection<usize>]>,
 1430    SelectSyntaxNodeScrollBehavior,
 1431    bool,
 1432);
 1433
 1434#[derive(Default)]
 1435struct SelectSyntaxNodeHistory {
 1436    stack: Vec<SelectSyntaxNodeHistoryState>,
 1437    // disable temporarily to allow changing selections without losing the stack
 1438    pub disable_clearing: bool,
 1439}
 1440
 1441impl SelectSyntaxNodeHistory {
 1442    pub fn try_clear(&mut self) {
 1443        if !self.disable_clearing {
 1444            self.stack.clear();
 1445        }
 1446    }
 1447
 1448    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1449        self.stack.push(selection);
 1450    }
 1451
 1452    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1453        self.stack.pop()
 1454    }
 1455}
 1456
 1457enum SelectSyntaxNodeScrollBehavior {
 1458    CursorTop,
 1459    FitSelection,
 1460    CursorBottom,
 1461}
 1462
 1463#[derive(Debug)]
 1464pub(crate) struct NavigationData {
 1465    cursor_anchor: Anchor,
 1466    cursor_position: Point,
 1467    scroll_anchor: ScrollAnchor,
 1468    scroll_top_row: u32,
 1469}
 1470
 1471#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1472pub enum GotoDefinitionKind {
 1473    Symbol,
 1474    Declaration,
 1475    Type,
 1476    Implementation,
 1477}
 1478
 1479#[derive(Debug, Clone)]
 1480enum InlayHintRefreshReason {
 1481    ModifiersChanged(bool),
 1482    Toggle(bool),
 1483    SettingsChange(InlayHintSettings),
 1484    NewLinesShown,
 1485    BufferEdited(HashSet<Arc<Language>>),
 1486    RefreshRequested,
 1487    ExcerptsRemoved(Vec<ExcerptId>),
 1488}
 1489
 1490impl InlayHintRefreshReason {
 1491    fn description(&self) -> &'static str {
 1492        match self {
 1493            Self::ModifiersChanged(_) => "modifiers changed",
 1494            Self::Toggle(_) => "toggle",
 1495            Self::SettingsChange(_) => "settings change",
 1496            Self::NewLinesShown => "new lines shown",
 1497            Self::BufferEdited(_) => "buffer edited",
 1498            Self::RefreshRequested => "refresh requested",
 1499            Self::ExcerptsRemoved(_) => "excerpts removed",
 1500        }
 1501    }
 1502}
 1503
 1504pub enum FormatTarget {
 1505    Buffers,
 1506    Ranges(Vec<Range<MultiBufferPoint>>),
 1507}
 1508
 1509pub(crate) struct FocusedBlock {
 1510    id: BlockId,
 1511    focus_handle: WeakFocusHandle,
 1512}
 1513
 1514#[derive(Clone)]
 1515enum JumpData {
 1516    MultiBufferRow {
 1517        row: MultiBufferRow,
 1518        line_offset_from_top: u32,
 1519    },
 1520    MultiBufferPoint {
 1521        excerpt_id: ExcerptId,
 1522        position: Point,
 1523        anchor: text::Anchor,
 1524        line_offset_from_top: u32,
 1525    },
 1526}
 1527
 1528pub enum MultibufferSelectionMode {
 1529    First,
 1530    All,
 1531}
 1532
 1533#[derive(Clone, Copy, Debug, Default)]
 1534pub struct RewrapOptions {
 1535    pub override_language_settings: bool,
 1536    pub preserve_existing_whitespace: bool,
 1537}
 1538
 1539impl Editor {
 1540    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1541        let buffer = cx.new(|cx| Buffer::local("", cx));
 1542        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1543        Self::new(
 1544            EditorMode::SingleLine { auto_width: false },
 1545            buffer,
 1546            None,
 1547            window,
 1548            cx,
 1549        )
 1550    }
 1551
 1552    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1553        let buffer = cx.new(|cx| Buffer::local("", cx));
 1554        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1555        Self::new(EditorMode::full(), buffer, None, window, cx)
 1556    }
 1557
 1558    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1559        let buffer = cx.new(|cx| Buffer::local("", cx));
 1560        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1561        Self::new(
 1562            EditorMode::SingleLine { auto_width: true },
 1563            buffer,
 1564            None,
 1565            window,
 1566            cx,
 1567        )
 1568    }
 1569
 1570    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1571        let buffer = cx.new(|cx| Buffer::local("", cx));
 1572        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1573        Self::new(
 1574            EditorMode::AutoHeight { max_lines },
 1575            buffer,
 1576            None,
 1577            window,
 1578            cx,
 1579        )
 1580    }
 1581
 1582    pub fn for_buffer(
 1583        buffer: Entity<Buffer>,
 1584        project: Option<Entity<Project>>,
 1585        window: &mut Window,
 1586        cx: &mut Context<Self>,
 1587    ) -> Self {
 1588        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1589        Self::new(EditorMode::full(), buffer, project, window, cx)
 1590    }
 1591
 1592    pub fn for_multibuffer(
 1593        buffer: Entity<MultiBuffer>,
 1594        project: Option<Entity<Project>>,
 1595        window: &mut Window,
 1596        cx: &mut Context<Self>,
 1597    ) -> Self {
 1598        Self::new(EditorMode::full(), buffer, project, window, cx)
 1599    }
 1600
 1601    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1602        let mut clone = Self::new(
 1603            self.mode.clone(),
 1604            self.buffer.clone(),
 1605            self.project.clone(),
 1606            window,
 1607            cx,
 1608        );
 1609        self.display_map.update(cx, |display_map, cx| {
 1610            let snapshot = display_map.snapshot(cx);
 1611            clone.display_map.update(cx, |display_map, cx| {
 1612                display_map.set_state(&snapshot, cx);
 1613            });
 1614        });
 1615        clone.folds_did_change(cx);
 1616        clone.selections.clone_state(&self.selections);
 1617        clone.scroll_manager.clone_state(&self.scroll_manager);
 1618        clone.searchable = self.searchable;
 1619        clone.read_only = self.read_only;
 1620        clone
 1621    }
 1622
 1623    pub fn new(
 1624        mode: EditorMode,
 1625        buffer: Entity<MultiBuffer>,
 1626        project: Option<Entity<Project>>,
 1627        window: &mut Window,
 1628        cx: &mut Context<Self>,
 1629    ) -> Self {
 1630        Editor::new_internal(mode, buffer, project, None, window, cx)
 1631    }
 1632
 1633    fn new_internal(
 1634        mode: EditorMode,
 1635        buffer: Entity<MultiBuffer>,
 1636        project: Option<Entity<Project>>,
 1637        display_map: Option<Entity<DisplayMap>>,
 1638        window: &mut Window,
 1639        cx: &mut Context<Self>,
 1640    ) -> Self {
 1641        debug_assert!(
 1642            display_map.is_none() || mode.is_minimap(),
 1643            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1644        );
 1645
 1646        let full_mode = mode.is_full();
 1647        let diagnostics_max_severity = if full_mode {
 1648            EditorSettings::get_global(cx)
 1649                .diagnostics_max_severity
 1650                .unwrap_or(DiagnosticSeverity::Hint)
 1651        } else {
 1652            DiagnosticSeverity::Off
 1653        };
 1654        let style = window.text_style();
 1655        let font_size = style.font_size.to_pixels(window.rem_size());
 1656        let editor = cx.entity().downgrade();
 1657        let fold_placeholder = FoldPlaceholder {
 1658            constrain_width: true,
 1659            render: Arc::new(move |fold_id, fold_range, cx| {
 1660                let editor = editor.clone();
 1661                div()
 1662                    .id(fold_id)
 1663                    .bg(cx.theme().colors().ghost_element_background)
 1664                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1665                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1666                    .rounded_xs()
 1667                    .size_full()
 1668                    .cursor_pointer()
 1669                    .child("")
 1670                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1671                    .on_click(move |_, _window, cx| {
 1672                        editor
 1673                            .update(cx, |editor, cx| {
 1674                                editor.unfold_ranges(
 1675                                    &[fold_range.start..fold_range.end],
 1676                                    true,
 1677                                    false,
 1678                                    cx,
 1679                                );
 1680                                cx.stop_propagation();
 1681                            })
 1682                            .ok();
 1683                    })
 1684                    .into_any()
 1685            }),
 1686            merge_adjacent: true,
 1687            ..FoldPlaceholder::default()
 1688        };
 1689        let display_map = display_map.unwrap_or_else(|| {
 1690            cx.new(|cx| {
 1691                DisplayMap::new(
 1692                    buffer.clone(),
 1693                    style.font(),
 1694                    font_size,
 1695                    None,
 1696                    FILE_HEADER_HEIGHT,
 1697                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1698                    fold_placeholder,
 1699                    diagnostics_max_severity,
 1700                    cx,
 1701                )
 1702            })
 1703        });
 1704
 1705        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1706
 1707        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1708
 1709        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1710            .then(|| language_settings::SoftWrap::None);
 1711
 1712        let mut project_subscriptions = Vec::new();
 1713        if mode.is_full() {
 1714            if let Some(project) = project.as_ref() {
 1715                project_subscriptions.push(cx.subscribe_in(
 1716                    project,
 1717                    window,
 1718                    |editor, _, event, window, cx| match event {
 1719                        project::Event::RefreshCodeLens => {
 1720                            // we always query lens with actions, without storing them, always refreshing them
 1721                        }
 1722                        project::Event::RefreshInlayHints => {
 1723                            editor
 1724                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1725                        }
 1726                        project::Event::LanguageServerAdded(..)
 1727                        | project::Event::LanguageServerRemoved(..) => {
 1728                            if editor.tasks_update_task.is_none() {
 1729                                editor.tasks_update_task =
 1730                                    Some(editor.refresh_runnables(window, cx));
 1731                            }
 1732                            editor.pull_diagnostics(None, window, cx);
 1733                        }
 1734                        project::Event::SnippetEdit(id, snippet_edits) => {
 1735                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1736                                let focus_handle = editor.focus_handle(cx);
 1737                                if focus_handle.is_focused(window) {
 1738                                    let snapshot = buffer.read(cx).snapshot();
 1739                                    for (range, snippet) in snippet_edits {
 1740                                        let editor_range =
 1741                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1742                                        editor
 1743                                            .insert_snippet(
 1744                                                &[editor_range],
 1745                                                snippet.clone(),
 1746                                                window,
 1747                                                cx,
 1748                                            )
 1749                                            .ok();
 1750                                    }
 1751                                }
 1752                            }
 1753                        }
 1754                        _ => {}
 1755                    },
 1756                ));
 1757                if let Some(task_inventory) = project
 1758                    .read(cx)
 1759                    .task_store()
 1760                    .read(cx)
 1761                    .task_inventory()
 1762                    .cloned()
 1763                {
 1764                    project_subscriptions.push(cx.observe_in(
 1765                        &task_inventory,
 1766                        window,
 1767                        |editor, _, window, cx| {
 1768                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1769                        },
 1770                    ));
 1771                };
 1772
 1773                project_subscriptions.push(cx.subscribe_in(
 1774                    &project.read(cx).breakpoint_store(),
 1775                    window,
 1776                    |editor, _, event, window, cx| match event {
 1777                        BreakpointStoreEvent::ClearDebugLines => {
 1778                            editor.clear_row_highlights::<ActiveDebugLine>();
 1779                            editor.refresh_inline_values(cx);
 1780                        }
 1781                        BreakpointStoreEvent::SetDebugLine => {
 1782                            if editor.go_to_active_debug_line(window, cx) {
 1783                                cx.stop_propagation();
 1784                            }
 1785
 1786                            editor.refresh_inline_values(cx);
 1787                        }
 1788                        _ => {}
 1789                    },
 1790                ));
 1791            }
 1792        }
 1793
 1794        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1795
 1796        let inlay_hint_settings =
 1797            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1798        let focus_handle = cx.focus_handle();
 1799        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1800            .detach();
 1801        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1802            .detach();
 1803        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1804            .detach();
 1805        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1806            .detach();
 1807        cx.observe_pending_input(window, Self::observe_pending_input)
 1808            .detach();
 1809
 1810        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1811            Some(false)
 1812        } else {
 1813            None
 1814        };
 1815
 1816        let breakpoint_store = match (&mode, project.as_ref()) {
 1817            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1818            _ => None,
 1819        };
 1820
 1821        let mut code_action_providers = Vec::new();
 1822        let mut load_uncommitted_diff = None;
 1823        if let Some(project) = project.clone() {
 1824            load_uncommitted_diff = Some(
 1825                update_uncommitted_diff_for_buffer(
 1826                    cx.entity(),
 1827                    &project,
 1828                    buffer.read(cx).all_buffers(),
 1829                    buffer.clone(),
 1830                    cx,
 1831                )
 1832                .shared(),
 1833            );
 1834            code_action_providers.push(Rc::new(project) as Rc<_>);
 1835        }
 1836
 1837        let mut editor = Self {
 1838            focus_handle,
 1839            show_cursor_when_unfocused: false,
 1840            last_focused_descendant: None,
 1841            buffer: buffer.clone(),
 1842            display_map: display_map.clone(),
 1843            selections,
 1844            scroll_manager: ScrollManager::new(cx),
 1845            columnar_selection_tail: None,
 1846            columnar_display_point: None,
 1847            add_selections_state: None,
 1848            select_next_state: None,
 1849            select_prev_state: None,
 1850            selection_history: SelectionHistory::default(),
 1851            defer_selection_effects: false,
 1852            deferred_selection_effects_state: None,
 1853            autoclose_regions: Vec::new(),
 1854            snippet_stack: InvalidationStack::default(),
 1855            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1856            ime_transaction: None,
 1857            active_diagnostics: ActiveDiagnostic::None,
 1858            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1859            inline_diagnostics_update: Task::ready(()),
 1860            inline_diagnostics: Vec::new(),
 1861            soft_wrap_mode_override,
 1862            diagnostics_max_severity,
 1863            hard_wrap: None,
 1864            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1865            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1866            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1867            project,
 1868            blink_manager: blink_manager.clone(),
 1869            show_local_selections: true,
 1870            show_scrollbars: ScrollbarAxes {
 1871                horizontal: full_mode,
 1872                vertical: full_mode,
 1873            },
 1874            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1875            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1876            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1877            show_gutter: mode.is_full(),
 1878            show_line_numbers: None,
 1879            use_relative_line_numbers: None,
 1880            disable_expand_excerpt_buttons: false,
 1881            show_git_diff_gutter: None,
 1882            show_code_actions: None,
 1883            show_runnables: None,
 1884            show_breakpoints: None,
 1885            show_wrap_guides: None,
 1886            show_indent_guides,
 1887            placeholder_text: None,
 1888            highlight_order: 0,
 1889            highlighted_rows: HashMap::default(),
 1890            background_highlights: TreeMap::default(),
 1891            gutter_highlights: TreeMap::default(),
 1892            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1893            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1894            nav_history: None,
 1895            context_menu: RefCell::new(None),
 1896            context_menu_options: None,
 1897            mouse_context_menu: None,
 1898            completion_tasks: Vec::new(),
 1899            inline_blame_popover: None,
 1900            signature_help_state: SignatureHelpState::default(),
 1901            auto_signature_help: None,
 1902            find_all_references_task_sources: Vec::new(),
 1903            next_completion_id: 0,
 1904            next_inlay_id: 0,
 1905            code_action_providers,
 1906            available_code_actions: None,
 1907            code_actions_task: None,
 1908            quick_selection_highlight_task: None,
 1909            debounced_selection_highlight_task: None,
 1910            document_highlights_task: None,
 1911            linked_editing_range_task: None,
 1912            pending_rename: None,
 1913            searchable: true,
 1914            cursor_shape: EditorSettings::get_global(cx)
 1915                .cursor_shape
 1916                .unwrap_or_default(),
 1917            current_line_highlight: None,
 1918            autoindent_mode: Some(AutoindentMode::EachLine),
 1919            collapse_matches: false,
 1920            workspace: None,
 1921            input_enabled: true,
 1922            use_modal_editing: mode.is_full(),
 1923            read_only: mode.is_minimap(),
 1924            use_autoclose: true,
 1925            use_auto_surround: true,
 1926            auto_replace_emoji_shortcode: false,
 1927            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1928            leader_id: None,
 1929            remote_id: None,
 1930            hover_state: HoverState::default(),
 1931            pending_mouse_down: None,
 1932            hovered_link_state: None,
 1933            edit_prediction_provider: None,
 1934            active_inline_completion: None,
 1935            stale_inline_completion_in_menu: None,
 1936            edit_prediction_preview: EditPredictionPreview::Inactive {
 1937                released_too_fast: false,
 1938            },
 1939            inline_diagnostics_enabled: mode.is_full(),
 1940            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1941            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1942
 1943            gutter_hovered: false,
 1944            pixel_position_of_newest_cursor: None,
 1945            last_bounds: None,
 1946            last_position_map: None,
 1947            expect_bounds_change: None,
 1948            gutter_dimensions: GutterDimensions::default(),
 1949            style: None,
 1950            show_cursor_names: false,
 1951            hovered_cursors: HashMap::default(),
 1952            next_editor_action_id: EditorActionId::default(),
 1953            editor_actions: Rc::default(),
 1954            inline_completions_hidden_for_vim_mode: false,
 1955            show_inline_completions_override: None,
 1956            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1957            edit_prediction_settings: EditPredictionSettings::Disabled,
 1958            edit_prediction_indent_conflict: false,
 1959            edit_prediction_requires_modifier_in_indent_conflict: true,
 1960            custom_context_menu: None,
 1961            show_git_blame_gutter: false,
 1962            show_git_blame_inline: false,
 1963            show_selection_menu: None,
 1964            show_git_blame_inline_delay_task: None,
 1965            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1966            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1967            serialize_dirty_buffers: !mode.is_minimap()
 1968                && ProjectSettings::get_global(cx)
 1969                    .session
 1970                    .restore_unsaved_buffers,
 1971            blame: None,
 1972            blame_subscription: None,
 1973            tasks: BTreeMap::default(),
 1974
 1975            breakpoint_store,
 1976            gutter_breakpoint_indicator: (None, None),
 1977            _subscriptions: vec![
 1978                cx.observe(&buffer, Self::on_buffer_changed),
 1979                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1980                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1981                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1982                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1983                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1984                cx.observe_window_activation(window, |editor, window, cx| {
 1985                    let active = window.is_window_active();
 1986                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1987                        if active {
 1988                            blink_manager.enable(cx);
 1989                        } else {
 1990                            blink_manager.disable(cx);
 1991                        }
 1992                    });
 1993                    if active {
 1994                        editor.show_mouse_cursor();
 1995                    }
 1996                }),
 1997            ],
 1998            tasks_update_task: None,
 1999            pull_diagnostics_task: Task::ready(()),
 2000            linked_edit_ranges: Default::default(),
 2001            in_project_search: false,
 2002            previous_search_ranges: None,
 2003            breadcrumb_header: None,
 2004            focused_block: None,
 2005            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2006            addons: HashMap::default(),
 2007            registered_buffers: HashMap::default(),
 2008            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2009            selection_mark_mode: false,
 2010            toggle_fold_multiple_buffers: Task::ready(()),
 2011            serialize_selections: Task::ready(()),
 2012            serialize_folds: Task::ready(()),
 2013            text_style_refinement: None,
 2014            load_diff_task: load_uncommitted_diff,
 2015            temporary_diff_override: false,
 2016            mouse_cursor_hidden: false,
 2017            minimap: None,
 2018            hide_mouse_mode: EditorSettings::get_global(cx)
 2019                .hide_mouse
 2020                .unwrap_or_default(),
 2021            change_list: ChangeList::new(),
 2022            mode,
 2023            selection_drag_state: SelectionDragState::None,
 2024            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2025        };
 2026        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2027            editor
 2028                ._subscriptions
 2029                .push(cx.observe(breakpoints, |_, _, cx| {
 2030                    cx.notify();
 2031                }));
 2032        }
 2033        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2034        editor._subscriptions.extend(project_subscriptions);
 2035
 2036        editor._subscriptions.push(cx.subscribe_in(
 2037            &cx.entity(),
 2038            window,
 2039            |editor, _, e: &EditorEvent, window, cx| match e {
 2040                EditorEvent::ScrollPositionChanged { local, .. } => {
 2041                    if *local {
 2042                        let new_anchor = editor.scroll_manager.anchor();
 2043                        let snapshot = editor.snapshot(window, cx);
 2044                        editor.update_restoration_data(cx, move |data| {
 2045                            data.scroll_position = (
 2046                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2047                                new_anchor.offset,
 2048                            );
 2049                        });
 2050                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2051                        editor.inline_blame_popover.take();
 2052                    }
 2053                }
 2054                EditorEvent::Edited { .. } => {
 2055                    if !vim_enabled(cx) {
 2056                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2057                        let pop_state = editor
 2058                            .change_list
 2059                            .last()
 2060                            .map(|previous| {
 2061                                previous.len() == selections.len()
 2062                                    && previous.iter().enumerate().all(|(ix, p)| {
 2063                                        p.to_display_point(&map).row()
 2064                                            == selections[ix].head().row()
 2065                                    })
 2066                            })
 2067                            .unwrap_or(false);
 2068                        let new_positions = selections
 2069                            .into_iter()
 2070                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2071                            .collect();
 2072                        editor
 2073                            .change_list
 2074                            .push_to_change_list(pop_state, new_positions);
 2075                    }
 2076                }
 2077                _ => (),
 2078            },
 2079        ));
 2080
 2081        if let Some(dap_store) = editor
 2082            .project
 2083            .as_ref()
 2084            .map(|project| project.read(cx).dap_store())
 2085        {
 2086            let weak_editor = cx.weak_entity();
 2087
 2088            editor
 2089                ._subscriptions
 2090                .push(
 2091                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2092                        let session_entity = cx.entity();
 2093                        weak_editor
 2094                            .update(cx, |editor, cx| {
 2095                                editor._subscriptions.push(
 2096                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2097                                );
 2098                            })
 2099                            .ok();
 2100                    }),
 2101                );
 2102
 2103            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2104                editor
 2105                    ._subscriptions
 2106                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2107            }
 2108        }
 2109
 2110        // skip adding the initial selection to selection history
 2111        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2112        editor.end_selection(window, cx);
 2113        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2114
 2115        editor.scroll_manager.show_scrollbars(window, cx);
 2116        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2117
 2118        if full_mode {
 2119            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2120            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2121
 2122            if editor.git_blame_inline_enabled {
 2123                editor.start_git_blame_inline(false, window, cx);
 2124            }
 2125
 2126            editor.go_to_active_debug_line(window, cx);
 2127
 2128            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2129                if let Some(project) = editor.project.as_ref() {
 2130                    let handle = project.update(cx, |project, cx| {
 2131                        project.register_buffer_with_language_servers(&buffer, cx)
 2132                    });
 2133                    editor
 2134                        .registered_buffers
 2135                        .insert(buffer.read(cx).remote_id(), handle);
 2136                }
 2137            }
 2138
 2139            editor.minimap =
 2140                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2141            editor.pull_diagnostics(None, window, cx);
 2142        }
 2143
 2144        editor.report_editor_event("Editor Opened", None, cx);
 2145        editor
 2146    }
 2147
 2148    pub fn deploy_mouse_context_menu(
 2149        &mut self,
 2150        position: gpui::Point<Pixels>,
 2151        context_menu: Entity<ContextMenu>,
 2152        window: &mut Window,
 2153        cx: &mut Context<Self>,
 2154    ) {
 2155        self.mouse_context_menu = Some(MouseContextMenu::new(
 2156            self,
 2157            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2158            context_menu,
 2159            window,
 2160            cx,
 2161        ));
 2162    }
 2163
 2164    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2165        self.mouse_context_menu
 2166            .as_ref()
 2167            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2168    }
 2169
 2170    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2171        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2172    }
 2173
 2174    fn key_context_internal(
 2175        &self,
 2176        has_active_edit_prediction: bool,
 2177        window: &Window,
 2178        cx: &App,
 2179    ) -> KeyContext {
 2180        let mut key_context = KeyContext::new_with_defaults();
 2181        key_context.add("Editor");
 2182        let mode = match self.mode {
 2183            EditorMode::SingleLine { .. } => "single_line",
 2184            EditorMode::AutoHeight { .. } => "auto_height",
 2185            EditorMode::Minimap { .. } => "minimap",
 2186            EditorMode::Full { .. } => "full",
 2187        };
 2188
 2189        if EditorSettings::jupyter_enabled(cx) {
 2190            key_context.add("jupyter");
 2191        }
 2192
 2193        key_context.set("mode", mode);
 2194        if self.pending_rename.is_some() {
 2195            key_context.add("renaming");
 2196        }
 2197
 2198        match self.context_menu.borrow().as_ref() {
 2199            Some(CodeContextMenu::Completions(_)) => {
 2200                key_context.add("menu");
 2201                key_context.add("showing_completions");
 2202            }
 2203            Some(CodeContextMenu::CodeActions(_)) => {
 2204                key_context.add("menu");
 2205                key_context.add("showing_code_actions")
 2206            }
 2207            None => {}
 2208        }
 2209
 2210        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2211        if !self.focus_handle(cx).contains_focused(window, cx)
 2212            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2213        {
 2214            for addon in self.addons.values() {
 2215                addon.extend_key_context(&mut key_context, cx)
 2216            }
 2217        }
 2218
 2219        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2220            if let Some(extension) = singleton_buffer
 2221                .read(cx)
 2222                .file()
 2223                .and_then(|file| file.path().extension()?.to_str())
 2224            {
 2225                key_context.set("extension", extension.to_string());
 2226            }
 2227        } else {
 2228            key_context.add("multibuffer");
 2229        }
 2230
 2231        if has_active_edit_prediction {
 2232            if self.edit_prediction_in_conflict() {
 2233                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2234            } else {
 2235                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2236                key_context.add("copilot_suggestion");
 2237            }
 2238        }
 2239
 2240        if self.selection_mark_mode {
 2241            key_context.add("selection_mode");
 2242        }
 2243
 2244        key_context
 2245    }
 2246
 2247    fn show_mouse_cursor(&mut self) {
 2248        self.mouse_cursor_hidden = false;
 2249    }
 2250
 2251    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2252        self.mouse_cursor_hidden = match origin {
 2253            HideMouseCursorOrigin::TypingAction => {
 2254                matches!(
 2255                    self.hide_mouse_mode,
 2256                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2257                )
 2258            }
 2259            HideMouseCursorOrigin::MovementAction => {
 2260                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2261            }
 2262        };
 2263    }
 2264
 2265    pub fn edit_prediction_in_conflict(&self) -> bool {
 2266        if !self.show_edit_predictions_in_menu() {
 2267            return false;
 2268        }
 2269
 2270        let showing_completions = self
 2271            .context_menu
 2272            .borrow()
 2273            .as_ref()
 2274            .map_or(false, |context| {
 2275                matches!(context, CodeContextMenu::Completions(_))
 2276            });
 2277
 2278        showing_completions
 2279            || self.edit_prediction_requires_modifier()
 2280            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2281            // bindings to insert tab characters.
 2282            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2283    }
 2284
 2285    pub fn accept_edit_prediction_keybind(
 2286        &self,
 2287        accept_partial: bool,
 2288        window: &Window,
 2289        cx: &App,
 2290    ) -> AcceptEditPredictionBinding {
 2291        let key_context = self.key_context_internal(true, window, cx);
 2292        let in_conflict = self.edit_prediction_in_conflict();
 2293
 2294        let bindings = if accept_partial {
 2295            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2296        } else {
 2297            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2298        };
 2299
 2300        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2301        // just the first one.
 2302        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2303            !in_conflict
 2304                || binding
 2305                    .keystrokes()
 2306                    .first()
 2307                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2308        }))
 2309    }
 2310
 2311    pub fn new_file(
 2312        workspace: &mut Workspace,
 2313        _: &workspace::NewFile,
 2314        window: &mut Window,
 2315        cx: &mut Context<Workspace>,
 2316    ) {
 2317        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2318            "Failed to create buffer",
 2319            window,
 2320            cx,
 2321            |e, _, _| match e.error_code() {
 2322                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2323                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2324                e.error_tag("required").unwrap_or("the latest version")
 2325            )),
 2326                _ => None,
 2327            },
 2328        );
 2329    }
 2330
 2331    pub fn new_in_workspace(
 2332        workspace: &mut Workspace,
 2333        window: &mut Window,
 2334        cx: &mut Context<Workspace>,
 2335    ) -> Task<Result<Entity<Editor>>> {
 2336        let project = workspace.project().clone();
 2337        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2338
 2339        cx.spawn_in(window, async move |workspace, cx| {
 2340            let buffer = create.await?;
 2341            workspace.update_in(cx, |workspace, window, cx| {
 2342                let editor =
 2343                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2344                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2345                editor
 2346            })
 2347        })
 2348    }
 2349
 2350    fn new_file_vertical(
 2351        workspace: &mut Workspace,
 2352        _: &workspace::NewFileSplitVertical,
 2353        window: &mut Window,
 2354        cx: &mut Context<Workspace>,
 2355    ) {
 2356        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2357    }
 2358
 2359    fn new_file_horizontal(
 2360        workspace: &mut Workspace,
 2361        _: &workspace::NewFileSplitHorizontal,
 2362        window: &mut Window,
 2363        cx: &mut Context<Workspace>,
 2364    ) {
 2365        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2366    }
 2367
 2368    fn new_file_in_direction(
 2369        workspace: &mut Workspace,
 2370        direction: SplitDirection,
 2371        window: &mut Window,
 2372        cx: &mut Context<Workspace>,
 2373    ) {
 2374        let project = workspace.project().clone();
 2375        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2376
 2377        cx.spawn_in(window, async move |workspace, cx| {
 2378            let buffer = create.await?;
 2379            workspace.update_in(cx, move |workspace, window, cx| {
 2380                workspace.split_item(
 2381                    direction,
 2382                    Box::new(
 2383                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2384                    ),
 2385                    window,
 2386                    cx,
 2387                )
 2388            })?;
 2389            anyhow::Ok(())
 2390        })
 2391        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2392            match e.error_code() {
 2393                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2394                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2395                e.error_tag("required").unwrap_or("the latest version")
 2396            )),
 2397                _ => None,
 2398            }
 2399        });
 2400    }
 2401
 2402    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2403        self.leader_id
 2404    }
 2405
 2406    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2407        &self.buffer
 2408    }
 2409
 2410    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2411        self.workspace.as_ref()?.0.upgrade()
 2412    }
 2413
 2414    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2415        self.buffer().read(cx).title(cx)
 2416    }
 2417
 2418    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2419        let git_blame_gutter_max_author_length = self
 2420            .render_git_blame_gutter(cx)
 2421            .then(|| {
 2422                if let Some(blame) = self.blame.as_ref() {
 2423                    let max_author_length =
 2424                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2425                    Some(max_author_length)
 2426                } else {
 2427                    None
 2428                }
 2429            })
 2430            .flatten();
 2431
 2432        EditorSnapshot {
 2433            mode: self.mode.clone(),
 2434            show_gutter: self.show_gutter,
 2435            show_line_numbers: self.show_line_numbers,
 2436            show_git_diff_gutter: self.show_git_diff_gutter,
 2437            show_code_actions: self.show_code_actions,
 2438            show_runnables: self.show_runnables,
 2439            show_breakpoints: self.show_breakpoints,
 2440            git_blame_gutter_max_author_length,
 2441            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2442            scroll_anchor: self.scroll_manager.anchor(),
 2443            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2444            placeholder_text: self.placeholder_text.clone(),
 2445            is_focused: self.focus_handle.is_focused(window),
 2446            current_line_highlight: self
 2447                .current_line_highlight
 2448                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2449            gutter_hovered: self.gutter_hovered,
 2450        }
 2451    }
 2452
 2453    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2454        self.buffer.read(cx).language_at(point, cx)
 2455    }
 2456
 2457    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2458        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2459    }
 2460
 2461    pub fn active_excerpt(
 2462        &self,
 2463        cx: &App,
 2464    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2465        self.buffer
 2466            .read(cx)
 2467            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2468    }
 2469
 2470    pub fn mode(&self) -> &EditorMode {
 2471        &self.mode
 2472    }
 2473
 2474    pub fn set_mode(&mut self, mode: EditorMode) {
 2475        self.mode = mode;
 2476    }
 2477
 2478    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2479        self.collaboration_hub.as_deref()
 2480    }
 2481
 2482    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2483        self.collaboration_hub = Some(hub);
 2484    }
 2485
 2486    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2487        self.in_project_search = in_project_search;
 2488    }
 2489
 2490    pub fn set_custom_context_menu(
 2491        &mut self,
 2492        f: impl 'static
 2493        + Fn(
 2494            &mut Self,
 2495            DisplayPoint,
 2496            &mut Window,
 2497            &mut Context<Self>,
 2498        ) -> Option<Entity<ui::ContextMenu>>,
 2499    ) {
 2500        self.custom_context_menu = Some(Box::new(f))
 2501    }
 2502
 2503    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2504        self.completion_provider = provider;
 2505    }
 2506
 2507    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2508        self.semantics_provider.clone()
 2509    }
 2510
 2511    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2512        self.semantics_provider = provider;
 2513    }
 2514
 2515    pub fn set_edit_prediction_provider<T>(
 2516        &mut self,
 2517        provider: Option<Entity<T>>,
 2518        window: &mut Window,
 2519        cx: &mut Context<Self>,
 2520    ) where
 2521        T: EditPredictionProvider,
 2522    {
 2523        self.edit_prediction_provider =
 2524            provider.map(|provider| RegisteredInlineCompletionProvider {
 2525                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2526                    if this.focus_handle.is_focused(window) {
 2527                        this.update_visible_inline_completion(window, cx);
 2528                    }
 2529                }),
 2530                provider: Arc::new(provider),
 2531            });
 2532        self.update_edit_prediction_settings(cx);
 2533        self.refresh_inline_completion(false, false, window, cx);
 2534    }
 2535
 2536    pub fn placeholder_text(&self) -> Option<&str> {
 2537        self.placeholder_text.as_deref()
 2538    }
 2539
 2540    pub fn set_placeholder_text(
 2541        &mut self,
 2542        placeholder_text: impl Into<Arc<str>>,
 2543        cx: &mut Context<Self>,
 2544    ) {
 2545        let placeholder_text = Some(placeholder_text.into());
 2546        if self.placeholder_text != placeholder_text {
 2547            self.placeholder_text = placeholder_text;
 2548            cx.notify();
 2549        }
 2550    }
 2551
 2552    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2553        self.cursor_shape = cursor_shape;
 2554
 2555        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2556        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2557
 2558        cx.notify();
 2559    }
 2560
 2561    pub fn set_current_line_highlight(
 2562        &mut self,
 2563        current_line_highlight: Option<CurrentLineHighlight>,
 2564    ) {
 2565        self.current_line_highlight = current_line_highlight;
 2566    }
 2567
 2568    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2569        self.collapse_matches = collapse_matches;
 2570    }
 2571
 2572    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2573        let buffers = self.buffer.read(cx).all_buffers();
 2574        let Some(project) = self.project.as_ref() else {
 2575            return;
 2576        };
 2577        project.update(cx, |project, cx| {
 2578            for buffer in buffers {
 2579                self.registered_buffers
 2580                    .entry(buffer.read(cx).remote_id())
 2581                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2582            }
 2583        })
 2584    }
 2585
 2586    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2587        if self.collapse_matches {
 2588            return range.start..range.start;
 2589        }
 2590        range.clone()
 2591    }
 2592
 2593    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2594        if self.display_map.read(cx).clip_at_line_ends != clip {
 2595            self.display_map
 2596                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2597        }
 2598    }
 2599
 2600    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2601        self.input_enabled = input_enabled;
 2602    }
 2603
 2604    pub fn set_inline_completions_hidden_for_vim_mode(
 2605        &mut self,
 2606        hidden: bool,
 2607        window: &mut Window,
 2608        cx: &mut Context<Self>,
 2609    ) {
 2610        if hidden != self.inline_completions_hidden_for_vim_mode {
 2611            self.inline_completions_hidden_for_vim_mode = hidden;
 2612            if hidden {
 2613                self.update_visible_inline_completion(window, cx);
 2614            } else {
 2615                self.refresh_inline_completion(true, false, window, cx);
 2616            }
 2617        }
 2618    }
 2619
 2620    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2621        self.menu_inline_completions_policy = value;
 2622    }
 2623
 2624    pub fn set_autoindent(&mut self, autoindent: bool) {
 2625        if autoindent {
 2626            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2627        } else {
 2628            self.autoindent_mode = None;
 2629        }
 2630    }
 2631
 2632    pub fn read_only(&self, cx: &App) -> bool {
 2633        self.read_only || self.buffer.read(cx).read_only()
 2634    }
 2635
 2636    pub fn set_read_only(&mut self, read_only: bool) {
 2637        self.read_only = read_only;
 2638    }
 2639
 2640    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2641        self.use_autoclose = autoclose;
 2642    }
 2643
 2644    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2645        self.use_auto_surround = auto_surround;
 2646    }
 2647
 2648    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2649        self.auto_replace_emoji_shortcode = auto_replace;
 2650    }
 2651
 2652    pub fn toggle_edit_predictions(
 2653        &mut self,
 2654        _: &ToggleEditPrediction,
 2655        window: &mut Window,
 2656        cx: &mut Context<Self>,
 2657    ) {
 2658        if self.show_inline_completions_override.is_some() {
 2659            self.set_show_edit_predictions(None, window, cx);
 2660        } else {
 2661            let show_edit_predictions = !self.edit_predictions_enabled();
 2662            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2663        }
 2664    }
 2665
 2666    pub fn set_show_edit_predictions(
 2667        &mut self,
 2668        show_edit_predictions: Option<bool>,
 2669        window: &mut Window,
 2670        cx: &mut Context<Self>,
 2671    ) {
 2672        self.show_inline_completions_override = show_edit_predictions;
 2673        self.update_edit_prediction_settings(cx);
 2674
 2675        if let Some(false) = show_edit_predictions {
 2676            self.discard_inline_completion(false, cx);
 2677        } else {
 2678            self.refresh_inline_completion(false, true, window, cx);
 2679        }
 2680    }
 2681
 2682    fn inline_completions_disabled_in_scope(
 2683        &self,
 2684        buffer: &Entity<Buffer>,
 2685        buffer_position: language::Anchor,
 2686        cx: &App,
 2687    ) -> bool {
 2688        let snapshot = buffer.read(cx).snapshot();
 2689        let settings = snapshot.settings_at(buffer_position, cx);
 2690
 2691        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2692            return false;
 2693        };
 2694
 2695        scope.override_name().map_or(false, |scope_name| {
 2696            settings
 2697                .edit_predictions_disabled_in
 2698                .iter()
 2699                .any(|s| s == scope_name)
 2700        })
 2701    }
 2702
 2703    pub fn set_use_modal_editing(&mut self, to: bool) {
 2704        self.use_modal_editing = to;
 2705    }
 2706
 2707    pub fn use_modal_editing(&self) -> bool {
 2708        self.use_modal_editing
 2709    }
 2710
 2711    fn selections_did_change(
 2712        &mut self,
 2713        local: bool,
 2714        old_cursor_position: &Anchor,
 2715        should_update_completions: bool,
 2716        window: &mut Window,
 2717        cx: &mut Context<Self>,
 2718    ) {
 2719        window.invalidate_character_coordinates();
 2720
 2721        // Copy selections to primary selection buffer
 2722        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2723        if local {
 2724            let selections = self.selections.all::<usize>(cx);
 2725            let buffer_handle = self.buffer.read(cx).read(cx);
 2726
 2727            let mut text = String::new();
 2728            for (index, selection) in selections.iter().enumerate() {
 2729                let text_for_selection = buffer_handle
 2730                    .text_for_range(selection.start..selection.end)
 2731                    .collect::<String>();
 2732
 2733                text.push_str(&text_for_selection);
 2734                if index != selections.len() - 1 {
 2735                    text.push('\n');
 2736                }
 2737            }
 2738
 2739            if !text.is_empty() {
 2740                cx.write_to_primary(ClipboardItem::new_string(text));
 2741            }
 2742        }
 2743
 2744        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2745            self.buffer.update(cx, |buffer, cx| {
 2746                buffer.set_active_selections(
 2747                    &self.selections.disjoint_anchors(),
 2748                    self.selections.line_mode,
 2749                    self.cursor_shape,
 2750                    cx,
 2751                )
 2752            });
 2753        }
 2754        let display_map = self
 2755            .display_map
 2756            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2757        let buffer = &display_map.buffer_snapshot;
 2758        if self.selections.count() == 1 {
 2759            self.add_selections_state = None;
 2760        }
 2761        self.select_next_state = None;
 2762        self.select_prev_state = None;
 2763        self.select_syntax_node_history.try_clear();
 2764        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2765        self.snippet_stack
 2766            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2767        self.take_rename(false, window, cx);
 2768
 2769        let newest_selection = self.selections.newest_anchor();
 2770        let new_cursor_position = newest_selection.head();
 2771        let selection_start = newest_selection.start;
 2772
 2773        self.push_to_nav_history(
 2774            *old_cursor_position,
 2775            Some(new_cursor_position.to_point(buffer)),
 2776            false,
 2777            cx,
 2778        );
 2779
 2780        if local {
 2781            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2782                if !self.registered_buffers.contains_key(&buffer_id) {
 2783                    if let Some(project) = self.project.as_ref() {
 2784                        project.update(cx, |project, cx| {
 2785                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2786                                return;
 2787                            };
 2788                            self.registered_buffers.insert(
 2789                                buffer_id,
 2790                                project.register_buffer_with_language_servers(&buffer, cx),
 2791                            );
 2792                        })
 2793                    }
 2794                }
 2795            }
 2796
 2797            let mut context_menu = self.context_menu.borrow_mut();
 2798            let completion_menu = match context_menu.as_ref() {
 2799                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2800                Some(CodeContextMenu::CodeActions(_)) => {
 2801                    *context_menu = None;
 2802                    None
 2803                }
 2804                None => None,
 2805            };
 2806            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2807            drop(context_menu);
 2808
 2809            if should_update_completions {
 2810                if let Some(completion_position) = completion_position {
 2811                    let start_offset = selection_start.to_offset(buffer);
 2812                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2813                    let continue_showing = if position_matches {
 2814                        if self.snippet_stack.is_empty() {
 2815                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2816                        } else {
 2817                            // Snippet choices can be shown even when the cursor is in whitespace.
 2818                            // Dismissing the menu when actions like backspace
 2819                            true
 2820                        }
 2821                    } else {
 2822                        false
 2823                    };
 2824
 2825                    if continue_showing {
 2826                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2827                    } else {
 2828                        self.hide_context_menu(window, cx);
 2829                    }
 2830                }
 2831            }
 2832
 2833            hide_hover(self, cx);
 2834
 2835            if old_cursor_position.to_display_point(&display_map).row()
 2836                != new_cursor_position.to_display_point(&display_map).row()
 2837            {
 2838                self.available_code_actions.take();
 2839            }
 2840            self.refresh_code_actions(window, cx);
 2841            self.refresh_document_highlights(cx);
 2842            self.refresh_selected_text_highlights(false, window, cx);
 2843            refresh_matching_bracket_highlights(self, window, cx);
 2844            self.update_visible_inline_completion(window, cx);
 2845            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2846            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2847            self.inline_blame_popover.take();
 2848            if self.git_blame_inline_enabled {
 2849                self.start_inline_blame_timer(window, cx);
 2850            }
 2851        }
 2852
 2853        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2854        cx.emit(EditorEvent::SelectionsChanged { local });
 2855
 2856        let selections = &self.selections.disjoint;
 2857        if selections.len() == 1 {
 2858            cx.emit(SearchEvent::ActiveMatchChanged)
 2859        }
 2860        if local {
 2861            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2862                let inmemory_selections = selections
 2863                    .iter()
 2864                    .map(|s| {
 2865                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2866                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2867                    })
 2868                    .collect();
 2869                self.update_restoration_data(cx, |data| {
 2870                    data.selections = inmemory_selections;
 2871                });
 2872
 2873                if WorkspaceSettings::get(None, cx).restore_on_startup
 2874                    != RestoreOnStartupBehavior::None
 2875                {
 2876                    if let Some(workspace_id) =
 2877                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2878                    {
 2879                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2880                        let selections = selections.clone();
 2881                        let background_executor = cx.background_executor().clone();
 2882                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2883                        self.serialize_selections = cx.background_spawn(async move {
 2884                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2885                    let db_selections = selections
 2886                        .iter()
 2887                        .map(|selection| {
 2888                            (
 2889                                selection.start.to_offset(&snapshot),
 2890                                selection.end.to_offset(&snapshot),
 2891                            )
 2892                        })
 2893                        .collect();
 2894
 2895                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2896                        .await
 2897                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2898                        .log_err();
 2899                });
 2900                    }
 2901                }
 2902            }
 2903        }
 2904
 2905        cx.notify();
 2906    }
 2907
 2908    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2909        use text::ToOffset as _;
 2910        use text::ToPoint as _;
 2911
 2912        if self.mode.is_minimap()
 2913            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2914        {
 2915            return;
 2916        }
 2917
 2918        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2919            return;
 2920        };
 2921
 2922        let snapshot = singleton.read(cx).snapshot();
 2923        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2924            let display_snapshot = display_map.snapshot(cx);
 2925
 2926            display_snapshot
 2927                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2928                .map(|fold| {
 2929                    fold.range.start.text_anchor.to_point(&snapshot)
 2930                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2931                })
 2932                .collect()
 2933        });
 2934        self.update_restoration_data(cx, |data| {
 2935            data.folds = inmemory_folds;
 2936        });
 2937
 2938        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2939            return;
 2940        };
 2941        let background_executor = cx.background_executor().clone();
 2942        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2943        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2944            display_map
 2945                .snapshot(cx)
 2946                .folds_in_range(0..snapshot.len())
 2947                .map(|fold| {
 2948                    (
 2949                        fold.range.start.text_anchor.to_offset(&snapshot),
 2950                        fold.range.end.text_anchor.to_offset(&snapshot),
 2951                    )
 2952                })
 2953                .collect()
 2954        });
 2955        self.serialize_folds = cx.background_spawn(async move {
 2956            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2957            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2958                .await
 2959                .with_context(|| {
 2960                    format!(
 2961                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2962                    )
 2963                })
 2964                .log_err();
 2965        });
 2966    }
 2967
 2968    pub fn sync_selections(
 2969        &mut self,
 2970        other: Entity<Editor>,
 2971        cx: &mut Context<Self>,
 2972    ) -> gpui::Subscription {
 2973        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2974        self.selections.change_with(cx, |selections| {
 2975            selections.select_anchors(other_selections);
 2976        });
 2977
 2978        let other_subscription =
 2979            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2980                EditorEvent::SelectionsChanged { local: true } => {
 2981                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2982                    if other_selections.is_empty() {
 2983                        return;
 2984                    }
 2985                    this.selections.change_with(cx, |selections| {
 2986                        selections.select_anchors(other_selections);
 2987                    });
 2988                }
 2989                _ => {}
 2990            });
 2991
 2992        let this_subscription =
 2993            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2994                EditorEvent::SelectionsChanged { local: true } => {
 2995                    let these_selections = this.selections.disjoint.to_vec();
 2996                    if these_selections.is_empty() {
 2997                        return;
 2998                    }
 2999                    other.update(cx, |other_editor, cx| {
 3000                        other_editor.selections.change_with(cx, |selections| {
 3001                            selections.select_anchors(these_selections);
 3002                        })
 3003                    });
 3004                }
 3005                _ => {}
 3006            });
 3007
 3008        Subscription::join(other_subscription, this_subscription)
 3009    }
 3010
 3011    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3012    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3013    /// effects of selection change occur at the end of the transaction.
 3014    pub fn change_selections<R>(
 3015        &mut self,
 3016        autoscroll: Option<Autoscroll>,
 3017        window: &mut Window,
 3018        cx: &mut Context<Self>,
 3019        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3020    ) -> R {
 3021        self.change_selections_inner(true, autoscroll, window, cx, change)
 3022    }
 3023
 3024    pub(crate) fn change_selections_without_updating_completions<R>(
 3025        &mut self,
 3026        autoscroll: Option<Autoscroll>,
 3027        window: &mut Window,
 3028        cx: &mut Context<Self>,
 3029        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3030    ) -> R {
 3031        self.change_selections_inner(false, autoscroll, window, cx, change)
 3032    }
 3033
 3034    fn change_selections_inner<R>(
 3035        &mut self,
 3036        should_update_completions: bool,
 3037        autoscroll: Option<Autoscroll>,
 3038        window: &mut Window,
 3039        cx: &mut Context<Self>,
 3040        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3041    ) -> R {
 3042        if let Some(state) = &mut self.deferred_selection_effects_state {
 3043            state.autoscroll = autoscroll.or(state.autoscroll);
 3044            state.should_update_completions = should_update_completions;
 3045            let (changed, result) = self.selections.change_with(cx, change);
 3046            state.changed |= changed;
 3047            return result;
 3048        }
 3049        let mut state = DeferredSelectionEffectsState {
 3050            changed: false,
 3051            should_update_completions,
 3052            autoscroll,
 3053            old_cursor_position: self.selections.newest_anchor().head(),
 3054            history_entry: SelectionHistoryEntry {
 3055                selections: self.selections.disjoint_anchors(),
 3056                select_next_state: self.select_next_state.clone(),
 3057                select_prev_state: self.select_prev_state.clone(),
 3058                add_selections_state: self.add_selections_state.clone(),
 3059            },
 3060        };
 3061        let (changed, result) = self.selections.change_with(cx, change);
 3062        state.changed = state.changed || changed;
 3063        if self.defer_selection_effects {
 3064            self.deferred_selection_effects_state = Some(state);
 3065        } else {
 3066            self.apply_selection_effects(state, window, cx);
 3067        }
 3068        result
 3069    }
 3070
 3071    /// Defers the effects of selection change, so that the effects of multiple calls to
 3072    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3073    /// to selection history and the state of popovers based on selection position aren't
 3074    /// erroneously updated.
 3075    pub fn with_selection_effects_deferred<R>(
 3076        &mut self,
 3077        window: &mut Window,
 3078        cx: &mut Context<Self>,
 3079        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3080    ) -> R {
 3081        let already_deferred = self.defer_selection_effects;
 3082        self.defer_selection_effects = true;
 3083        let result = update(self, window, cx);
 3084        if !already_deferred {
 3085            self.defer_selection_effects = false;
 3086            if let Some(state) = self.deferred_selection_effects_state.take() {
 3087                self.apply_selection_effects(state, window, cx);
 3088            }
 3089        }
 3090        result
 3091    }
 3092
 3093    fn apply_selection_effects(
 3094        &mut self,
 3095        state: DeferredSelectionEffectsState,
 3096        window: &mut Window,
 3097        cx: &mut Context<Self>,
 3098    ) {
 3099        if state.changed {
 3100            self.selection_history.push(state.history_entry);
 3101
 3102            if let Some(autoscroll) = state.autoscroll {
 3103                self.request_autoscroll(autoscroll, cx);
 3104            }
 3105
 3106            let old_cursor_position = &state.old_cursor_position;
 3107
 3108            self.selections_did_change(
 3109                true,
 3110                &old_cursor_position,
 3111                state.should_update_completions,
 3112                window,
 3113                cx,
 3114            );
 3115
 3116            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3117                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3118            }
 3119        }
 3120    }
 3121
 3122    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3123    where
 3124        I: IntoIterator<Item = (Range<S>, T)>,
 3125        S: ToOffset,
 3126        T: Into<Arc<str>>,
 3127    {
 3128        if self.read_only(cx) {
 3129            return;
 3130        }
 3131
 3132        self.buffer
 3133            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3134    }
 3135
 3136    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3137    where
 3138        I: IntoIterator<Item = (Range<S>, T)>,
 3139        S: ToOffset,
 3140        T: Into<Arc<str>>,
 3141    {
 3142        if self.read_only(cx) {
 3143            return;
 3144        }
 3145
 3146        self.buffer.update(cx, |buffer, cx| {
 3147            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3148        });
 3149    }
 3150
 3151    pub fn edit_with_block_indent<I, S, T>(
 3152        &mut self,
 3153        edits: I,
 3154        original_indent_columns: Vec<Option<u32>>,
 3155        cx: &mut Context<Self>,
 3156    ) where
 3157        I: IntoIterator<Item = (Range<S>, T)>,
 3158        S: ToOffset,
 3159        T: Into<Arc<str>>,
 3160    {
 3161        if self.read_only(cx) {
 3162            return;
 3163        }
 3164
 3165        self.buffer.update(cx, |buffer, cx| {
 3166            buffer.edit(
 3167                edits,
 3168                Some(AutoindentMode::Block {
 3169                    original_indent_columns,
 3170                }),
 3171                cx,
 3172            )
 3173        });
 3174    }
 3175
 3176    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3177        self.hide_context_menu(window, cx);
 3178
 3179        match phase {
 3180            SelectPhase::Begin {
 3181                position,
 3182                add,
 3183                click_count,
 3184            } => self.begin_selection(position, add, click_count, window, cx),
 3185            SelectPhase::BeginColumnar {
 3186                position,
 3187                goal_column,
 3188                reset,
 3189            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3190            SelectPhase::Extend {
 3191                position,
 3192                click_count,
 3193            } => self.extend_selection(position, click_count, window, cx),
 3194            SelectPhase::Update {
 3195                position,
 3196                goal_column,
 3197                scroll_delta,
 3198            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3199            SelectPhase::End => self.end_selection(window, cx),
 3200        }
 3201    }
 3202
 3203    fn extend_selection(
 3204        &mut self,
 3205        position: DisplayPoint,
 3206        click_count: usize,
 3207        window: &mut Window,
 3208        cx: &mut Context<Self>,
 3209    ) {
 3210        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3211        let tail = self.selections.newest::<usize>(cx).tail();
 3212        self.begin_selection(position, false, click_count, window, cx);
 3213
 3214        let position = position.to_offset(&display_map, Bias::Left);
 3215        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3216
 3217        let mut pending_selection = self
 3218            .selections
 3219            .pending_anchor()
 3220            .expect("extend_selection not called with pending selection");
 3221        if position >= tail {
 3222            pending_selection.start = tail_anchor;
 3223        } else {
 3224            pending_selection.end = tail_anchor;
 3225            pending_selection.reversed = true;
 3226        }
 3227
 3228        let mut pending_mode = self.selections.pending_mode().unwrap();
 3229        match &mut pending_mode {
 3230            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3231            _ => {}
 3232        }
 3233
 3234        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3235
 3236        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3237            s.set_pending(pending_selection, pending_mode)
 3238        });
 3239    }
 3240
 3241    fn begin_selection(
 3242        &mut self,
 3243        position: DisplayPoint,
 3244        add: bool,
 3245        click_count: usize,
 3246        window: &mut Window,
 3247        cx: &mut Context<Self>,
 3248    ) {
 3249        if !self.focus_handle.is_focused(window) {
 3250            self.last_focused_descendant = None;
 3251            window.focus(&self.focus_handle);
 3252        }
 3253
 3254        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3255        let buffer = &display_map.buffer_snapshot;
 3256        let position = display_map.clip_point(position, Bias::Left);
 3257
 3258        let start;
 3259        let end;
 3260        let mode;
 3261        let mut auto_scroll;
 3262        match click_count {
 3263            1 => {
 3264                start = buffer.anchor_before(position.to_point(&display_map));
 3265                end = start;
 3266                mode = SelectMode::Character;
 3267                auto_scroll = true;
 3268            }
 3269            2 => {
 3270                let range = movement::surrounding_word(&display_map, position);
 3271                start = buffer.anchor_before(range.start.to_point(&display_map));
 3272                end = buffer.anchor_before(range.end.to_point(&display_map));
 3273                mode = SelectMode::Word(start..end);
 3274                auto_scroll = true;
 3275            }
 3276            3 => {
 3277                let position = display_map
 3278                    .clip_point(position, Bias::Left)
 3279                    .to_point(&display_map);
 3280                let line_start = display_map.prev_line_boundary(position).0;
 3281                let next_line_start = buffer.clip_point(
 3282                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3283                    Bias::Left,
 3284                );
 3285                start = buffer.anchor_before(line_start);
 3286                end = buffer.anchor_before(next_line_start);
 3287                mode = SelectMode::Line(start..end);
 3288                auto_scroll = true;
 3289            }
 3290            _ => {
 3291                start = buffer.anchor_before(0);
 3292                end = buffer.anchor_before(buffer.len());
 3293                mode = SelectMode::All;
 3294                auto_scroll = false;
 3295            }
 3296        }
 3297        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3298
 3299        let point_to_delete: Option<usize> = {
 3300            let selected_points: Vec<Selection<Point>> =
 3301                self.selections.disjoint_in_range(start..end, cx);
 3302
 3303            if !add || click_count > 1 {
 3304                None
 3305            } else if !selected_points.is_empty() {
 3306                Some(selected_points[0].id)
 3307            } else {
 3308                let clicked_point_already_selected =
 3309                    self.selections.disjoint.iter().find(|selection| {
 3310                        selection.start.to_point(buffer) == start.to_point(buffer)
 3311                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3312                    });
 3313
 3314                clicked_point_already_selected.map(|selection| selection.id)
 3315            }
 3316        };
 3317
 3318        let selections_count = self.selections.count();
 3319
 3320        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3321            if let Some(point_to_delete) = point_to_delete {
 3322                s.delete(point_to_delete);
 3323
 3324                if selections_count == 1 {
 3325                    s.set_pending_anchor_range(start..end, mode);
 3326                }
 3327            } else {
 3328                if !add {
 3329                    s.clear_disjoint();
 3330                }
 3331
 3332                s.set_pending_anchor_range(start..end, mode);
 3333            }
 3334        });
 3335    }
 3336
 3337    fn begin_columnar_selection(
 3338        &mut self,
 3339        position: DisplayPoint,
 3340        goal_column: u32,
 3341        reset: bool,
 3342        window: &mut Window,
 3343        cx: &mut Context<Self>,
 3344    ) {
 3345        if !self.focus_handle.is_focused(window) {
 3346            self.last_focused_descendant = None;
 3347            window.focus(&self.focus_handle);
 3348        }
 3349
 3350        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3351
 3352        if reset {
 3353            let pointer_position = display_map
 3354                .buffer_snapshot
 3355                .anchor_before(position.to_point(&display_map));
 3356
 3357            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3358                s.clear_disjoint();
 3359                s.set_pending_anchor_range(
 3360                    pointer_position..pointer_position,
 3361                    SelectMode::Character,
 3362                );
 3363            });
 3364            if position.column() != goal_column {
 3365                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3366            } else {
 3367                self.columnar_display_point = None;
 3368            }
 3369        }
 3370
 3371        let tail = self.selections.newest::<Point>(cx).tail();
 3372        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3373
 3374        if !reset {
 3375            self.columnar_display_point = None;
 3376            self.select_columns(
 3377                tail.to_display_point(&display_map),
 3378                position,
 3379                goal_column,
 3380                &display_map,
 3381                window,
 3382                cx,
 3383            );
 3384        }
 3385    }
 3386
 3387    fn update_selection(
 3388        &mut self,
 3389        position: DisplayPoint,
 3390        goal_column: u32,
 3391        scroll_delta: gpui::Point<f32>,
 3392        window: &mut Window,
 3393        cx: &mut Context<Self>,
 3394    ) {
 3395        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3396
 3397        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3398            let tail = self
 3399                .columnar_display_point
 3400                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3401            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3402        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3403            let buffer = self.buffer.read(cx).snapshot(cx);
 3404            let head;
 3405            let tail;
 3406            let mode = self.selections.pending_mode().unwrap();
 3407            match &mode {
 3408                SelectMode::Character => {
 3409                    head = position.to_point(&display_map);
 3410                    tail = pending.tail().to_point(&buffer);
 3411                }
 3412                SelectMode::Word(original_range) => {
 3413                    let original_display_range = original_range.start.to_display_point(&display_map)
 3414                        ..original_range.end.to_display_point(&display_map);
 3415                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3416                        ..original_display_range.end.to_point(&display_map);
 3417                    if movement::is_inside_word(&display_map, position)
 3418                        || original_display_range.contains(&position)
 3419                    {
 3420                        let word_range = movement::surrounding_word(&display_map, position);
 3421                        if word_range.start < original_display_range.start {
 3422                            head = word_range.start.to_point(&display_map);
 3423                        } else {
 3424                            head = word_range.end.to_point(&display_map);
 3425                        }
 3426                    } else {
 3427                        head = position.to_point(&display_map);
 3428                    }
 3429
 3430                    if head <= original_buffer_range.start {
 3431                        tail = original_buffer_range.end;
 3432                    } else {
 3433                        tail = original_buffer_range.start;
 3434                    }
 3435                }
 3436                SelectMode::Line(original_range) => {
 3437                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3438
 3439                    let position = display_map
 3440                        .clip_point(position, Bias::Left)
 3441                        .to_point(&display_map);
 3442                    let line_start = display_map.prev_line_boundary(position).0;
 3443                    let next_line_start = buffer.clip_point(
 3444                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3445                        Bias::Left,
 3446                    );
 3447
 3448                    if line_start < original_range.start {
 3449                        head = line_start
 3450                    } else {
 3451                        head = next_line_start
 3452                    }
 3453
 3454                    if head <= original_range.start {
 3455                        tail = original_range.end;
 3456                    } else {
 3457                        tail = original_range.start;
 3458                    }
 3459                }
 3460                SelectMode::All => {
 3461                    return;
 3462                }
 3463            };
 3464
 3465            if head < tail {
 3466                pending.start = buffer.anchor_before(head);
 3467                pending.end = buffer.anchor_before(tail);
 3468                pending.reversed = true;
 3469            } else {
 3470                pending.start = buffer.anchor_before(tail);
 3471                pending.end = buffer.anchor_before(head);
 3472                pending.reversed = false;
 3473            }
 3474
 3475            self.change_selections(None, window, cx, |s| {
 3476                s.set_pending(pending, mode);
 3477            });
 3478        } else {
 3479            log::error!("update_selection dispatched with no pending selection");
 3480            return;
 3481        }
 3482
 3483        self.apply_scroll_delta(scroll_delta, window, cx);
 3484        cx.notify();
 3485    }
 3486
 3487    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3488        self.columnar_selection_tail.take();
 3489        if self.selections.pending_anchor().is_some() {
 3490            let selections = self.selections.all::<usize>(cx);
 3491            self.change_selections(None, window, cx, |s| {
 3492                s.select(selections);
 3493                s.clear_pending();
 3494            });
 3495        }
 3496    }
 3497
 3498    fn select_columns(
 3499        &mut self,
 3500        tail: DisplayPoint,
 3501        head: DisplayPoint,
 3502        goal_column: u32,
 3503        display_map: &DisplaySnapshot,
 3504        window: &mut Window,
 3505        cx: &mut Context<Self>,
 3506    ) {
 3507        let start_row = cmp::min(tail.row(), head.row());
 3508        let end_row = cmp::max(tail.row(), head.row());
 3509        let start_column = cmp::min(tail.column(), goal_column);
 3510        let end_column = cmp::max(tail.column(), goal_column);
 3511        let reversed = start_column < tail.column();
 3512
 3513        let selection_ranges = (start_row.0..=end_row.0)
 3514            .map(DisplayRow)
 3515            .filter_map(|row| {
 3516                if !display_map.is_block_line(row) {
 3517                    let start = display_map
 3518                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3519                        .to_point(display_map);
 3520                    let end = display_map
 3521                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3522                        .to_point(display_map);
 3523                    if reversed {
 3524                        Some(end..start)
 3525                    } else {
 3526                        Some(start..end)
 3527                    }
 3528                } else {
 3529                    None
 3530                }
 3531            })
 3532            .collect::<Vec<_>>();
 3533
 3534        let mut non_empty_ranges = selection_ranges
 3535            .iter()
 3536            .filter(|selection_range| selection_range.start != selection_range.end)
 3537            .peekable();
 3538
 3539        let ranges = if non_empty_ranges.peek().is_some() {
 3540            non_empty_ranges.cloned().collect()
 3541        } else {
 3542            selection_ranges
 3543        };
 3544
 3545        self.change_selections(None, window, cx, |s| {
 3546            s.select_ranges(ranges);
 3547        });
 3548        cx.notify();
 3549    }
 3550
 3551    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3552        self.selections
 3553            .all_adjusted(cx)
 3554            .iter()
 3555            .any(|selection| !selection.is_empty())
 3556    }
 3557
 3558    pub fn has_pending_nonempty_selection(&self) -> bool {
 3559        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3560            Some(Selection { start, end, .. }) => start != end,
 3561            None => false,
 3562        };
 3563
 3564        pending_nonempty_selection
 3565            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3566    }
 3567
 3568    pub fn has_pending_selection(&self) -> bool {
 3569        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3570    }
 3571
 3572    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3573        self.selection_mark_mode = false;
 3574        self.selection_drag_state = SelectionDragState::None;
 3575
 3576        if self.clear_expanded_diff_hunks(cx) {
 3577            cx.notify();
 3578            return;
 3579        }
 3580        if self.dismiss_menus_and_popups(true, window, cx) {
 3581            return;
 3582        }
 3583
 3584        if self.mode.is_full()
 3585            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3586        {
 3587            return;
 3588        }
 3589
 3590        cx.propagate();
 3591    }
 3592
 3593    pub fn dismiss_menus_and_popups(
 3594        &mut self,
 3595        is_user_requested: bool,
 3596        window: &mut Window,
 3597        cx: &mut Context<Self>,
 3598    ) -> bool {
 3599        if self.take_rename(false, window, cx).is_some() {
 3600            return true;
 3601        }
 3602
 3603        if hide_hover(self, cx) {
 3604            return true;
 3605        }
 3606
 3607        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3608            return true;
 3609        }
 3610
 3611        if self.hide_context_menu(window, cx).is_some() {
 3612            return true;
 3613        }
 3614
 3615        if self.mouse_context_menu.take().is_some() {
 3616            return true;
 3617        }
 3618
 3619        if is_user_requested && self.discard_inline_completion(true, cx) {
 3620            return true;
 3621        }
 3622
 3623        if self.snippet_stack.pop().is_some() {
 3624            return true;
 3625        }
 3626
 3627        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3628            self.dismiss_diagnostics(cx);
 3629            return true;
 3630        }
 3631
 3632        false
 3633    }
 3634
 3635    fn linked_editing_ranges_for(
 3636        &self,
 3637        selection: Range<text::Anchor>,
 3638        cx: &App,
 3639    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3640        if self.linked_edit_ranges.is_empty() {
 3641            return None;
 3642        }
 3643        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3644            selection.end.buffer_id.and_then(|end_buffer_id| {
 3645                if selection.start.buffer_id != Some(end_buffer_id) {
 3646                    return None;
 3647                }
 3648                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3649                let snapshot = buffer.read(cx).snapshot();
 3650                self.linked_edit_ranges
 3651                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3652                    .map(|ranges| (ranges, snapshot, buffer))
 3653            })?;
 3654        use text::ToOffset as TO;
 3655        // find offset from the start of current range to current cursor position
 3656        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3657
 3658        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3659        let start_difference = start_offset - start_byte_offset;
 3660        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3661        let end_difference = end_offset - start_byte_offset;
 3662        // Current range has associated linked ranges.
 3663        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3664        for range in linked_ranges.iter() {
 3665            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3666            let end_offset = start_offset + end_difference;
 3667            let start_offset = start_offset + start_difference;
 3668            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3669                continue;
 3670            }
 3671            if self.selections.disjoint_anchor_ranges().any(|s| {
 3672                if s.start.buffer_id != selection.start.buffer_id
 3673                    || s.end.buffer_id != selection.end.buffer_id
 3674                {
 3675                    return false;
 3676                }
 3677                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3678                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3679            }) {
 3680                continue;
 3681            }
 3682            let start = buffer_snapshot.anchor_after(start_offset);
 3683            let end = buffer_snapshot.anchor_after(end_offset);
 3684            linked_edits
 3685                .entry(buffer.clone())
 3686                .or_default()
 3687                .push(start..end);
 3688        }
 3689        Some(linked_edits)
 3690    }
 3691
 3692    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3693        let text: Arc<str> = text.into();
 3694
 3695        if self.read_only(cx) {
 3696            return;
 3697        }
 3698
 3699        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3700
 3701        let selections = self.selections.all_adjusted(cx);
 3702        let mut bracket_inserted = false;
 3703        let mut edits = Vec::new();
 3704        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3705        let mut new_selections = Vec::with_capacity(selections.len());
 3706        let mut new_autoclose_regions = Vec::new();
 3707        let snapshot = self.buffer.read(cx).read(cx);
 3708        let mut clear_linked_edit_ranges = false;
 3709
 3710        for (selection, autoclose_region) in
 3711            self.selections_with_autoclose_regions(selections, &snapshot)
 3712        {
 3713            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3714                // Determine if the inserted text matches the opening or closing
 3715                // bracket of any of this language's bracket pairs.
 3716                let mut bracket_pair = None;
 3717                let mut is_bracket_pair_start = false;
 3718                let mut is_bracket_pair_end = false;
 3719                if !text.is_empty() {
 3720                    let mut bracket_pair_matching_end = None;
 3721                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3722                    //  and they are removing the character that triggered IME popup.
 3723                    for (pair, enabled) in scope.brackets() {
 3724                        if !pair.close && !pair.surround {
 3725                            continue;
 3726                        }
 3727
 3728                        if enabled && pair.start.ends_with(text.as_ref()) {
 3729                            let prefix_len = pair.start.len() - text.len();
 3730                            let preceding_text_matches_prefix = prefix_len == 0
 3731                                || (selection.start.column >= (prefix_len as u32)
 3732                                    && snapshot.contains_str_at(
 3733                                        Point::new(
 3734                                            selection.start.row,
 3735                                            selection.start.column - (prefix_len as u32),
 3736                                        ),
 3737                                        &pair.start[..prefix_len],
 3738                                    ));
 3739                            if preceding_text_matches_prefix {
 3740                                bracket_pair = Some(pair.clone());
 3741                                is_bracket_pair_start = true;
 3742                                break;
 3743                            }
 3744                        }
 3745                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3746                        {
 3747                            // take first bracket pair matching end, but don't break in case a later bracket
 3748                            // pair matches start
 3749                            bracket_pair_matching_end = Some(pair.clone());
 3750                        }
 3751                    }
 3752                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3753                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3754                        is_bracket_pair_end = true;
 3755                    }
 3756                }
 3757
 3758                if let Some(bracket_pair) = bracket_pair {
 3759                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3760                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3761                    let auto_surround =
 3762                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3763                    if selection.is_empty() {
 3764                        if is_bracket_pair_start {
 3765                            // If the inserted text is a suffix of an opening bracket and the
 3766                            // selection is preceded by the rest of the opening bracket, then
 3767                            // insert the closing bracket.
 3768                            let following_text_allows_autoclose = snapshot
 3769                                .chars_at(selection.start)
 3770                                .next()
 3771                                .map_or(true, |c| scope.should_autoclose_before(c));
 3772
 3773                            let preceding_text_allows_autoclose = selection.start.column == 0
 3774                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3775                                    true,
 3776                                    |c| {
 3777                                        bracket_pair.start != bracket_pair.end
 3778                                            || !snapshot
 3779                                                .char_classifier_at(selection.start)
 3780                                                .is_word(c)
 3781                                    },
 3782                                );
 3783
 3784                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3785                                && bracket_pair.start.len() == 1
 3786                            {
 3787                                let target = bracket_pair.start.chars().next().unwrap();
 3788                                let current_line_count = snapshot
 3789                                    .reversed_chars_at(selection.start)
 3790                                    .take_while(|&c| c != '\n')
 3791                                    .filter(|&c| c == target)
 3792                                    .count();
 3793                                current_line_count % 2 == 1
 3794                            } else {
 3795                                false
 3796                            };
 3797
 3798                            if autoclose
 3799                                && bracket_pair.close
 3800                                && following_text_allows_autoclose
 3801                                && preceding_text_allows_autoclose
 3802                                && !is_closing_quote
 3803                            {
 3804                                let anchor = snapshot.anchor_before(selection.end);
 3805                                new_selections.push((selection.map(|_| anchor), text.len()));
 3806                                new_autoclose_regions.push((
 3807                                    anchor,
 3808                                    text.len(),
 3809                                    selection.id,
 3810                                    bracket_pair.clone(),
 3811                                ));
 3812                                edits.push((
 3813                                    selection.range(),
 3814                                    format!("{}{}", text, bracket_pair.end).into(),
 3815                                ));
 3816                                bracket_inserted = true;
 3817                                continue;
 3818                            }
 3819                        }
 3820
 3821                        if let Some(region) = autoclose_region {
 3822                            // If the selection is followed by an auto-inserted closing bracket,
 3823                            // then don't insert that closing bracket again; just move the selection
 3824                            // past the closing bracket.
 3825                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3826                                && text.as_ref() == region.pair.end.as_str();
 3827                            if should_skip {
 3828                                let anchor = snapshot.anchor_after(selection.end);
 3829                                new_selections
 3830                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3831                                continue;
 3832                            }
 3833                        }
 3834
 3835                        let always_treat_brackets_as_autoclosed = snapshot
 3836                            .language_settings_at(selection.start, cx)
 3837                            .always_treat_brackets_as_autoclosed;
 3838                        if always_treat_brackets_as_autoclosed
 3839                            && is_bracket_pair_end
 3840                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3841                        {
 3842                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3843                            // and the inserted text is a closing bracket and the selection is followed
 3844                            // by the closing bracket then move the selection past the closing bracket.
 3845                            let anchor = snapshot.anchor_after(selection.end);
 3846                            new_selections.push((selection.map(|_| anchor), text.len()));
 3847                            continue;
 3848                        }
 3849                    }
 3850                    // If an opening bracket is 1 character long and is typed while
 3851                    // text is selected, then surround that text with the bracket pair.
 3852                    else if auto_surround
 3853                        && bracket_pair.surround
 3854                        && is_bracket_pair_start
 3855                        && bracket_pair.start.chars().count() == 1
 3856                    {
 3857                        edits.push((selection.start..selection.start, text.clone()));
 3858                        edits.push((
 3859                            selection.end..selection.end,
 3860                            bracket_pair.end.as_str().into(),
 3861                        ));
 3862                        bracket_inserted = true;
 3863                        new_selections.push((
 3864                            Selection {
 3865                                id: selection.id,
 3866                                start: snapshot.anchor_after(selection.start),
 3867                                end: snapshot.anchor_before(selection.end),
 3868                                reversed: selection.reversed,
 3869                                goal: selection.goal,
 3870                            },
 3871                            0,
 3872                        ));
 3873                        continue;
 3874                    }
 3875                }
 3876            }
 3877
 3878            if self.auto_replace_emoji_shortcode
 3879                && selection.is_empty()
 3880                && text.as_ref().ends_with(':')
 3881            {
 3882                if let Some(possible_emoji_short_code) =
 3883                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3884                {
 3885                    if !possible_emoji_short_code.is_empty() {
 3886                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3887                            let emoji_shortcode_start = Point::new(
 3888                                selection.start.row,
 3889                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3890                            );
 3891
 3892                            // Remove shortcode from buffer
 3893                            edits.push((
 3894                                emoji_shortcode_start..selection.start,
 3895                                "".to_string().into(),
 3896                            ));
 3897                            new_selections.push((
 3898                                Selection {
 3899                                    id: selection.id,
 3900                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3901                                    end: snapshot.anchor_before(selection.start),
 3902                                    reversed: selection.reversed,
 3903                                    goal: selection.goal,
 3904                                },
 3905                                0,
 3906                            ));
 3907
 3908                            // Insert emoji
 3909                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3910                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3911                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3912
 3913                            continue;
 3914                        }
 3915                    }
 3916                }
 3917            }
 3918
 3919            // If not handling any auto-close operation, then just replace the selected
 3920            // text with the given input and move the selection to the end of the
 3921            // newly inserted text.
 3922            let anchor = snapshot.anchor_after(selection.end);
 3923            if !self.linked_edit_ranges.is_empty() {
 3924                let start_anchor = snapshot.anchor_before(selection.start);
 3925
 3926                let is_word_char = text.chars().next().map_or(true, |char| {
 3927                    let classifier = snapshot
 3928                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3929                        .ignore_punctuation(true);
 3930                    classifier.is_word(char)
 3931                });
 3932
 3933                if is_word_char {
 3934                    if let Some(ranges) = self
 3935                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3936                    {
 3937                        for (buffer, edits) in ranges {
 3938                            linked_edits
 3939                                .entry(buffer.clone())
 3940                                .or_default()
 3941                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3942                        }
 3943                    }
 3944                } else {
 3945                    clear_linked_edit_ranges = true;
 3946                }
 3947            }
 3948
 3949            new_selections.push((selection.map(|_| anchor), 0));
 3950            edits.push((selection.start..selection.end, text.clone()));
 3951        }
 3952
 3953        drop(snapshot);
 3954
 3955        self.transact(window, cx, |this, window, cx| {
 3956            if clear_linked_edit_ranges {
 3957                this.linked_edit_ranges.clear();
 3958            }
 3959            let initial_buffer_versions =
 3960                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3961
 3962            this.buffer.update(cx, |buffer, cx| {
 3963                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3964            });
 3965            for (buffer, edits) in linked_edits {
 3966                buffer.update(cx, |buffer, cx| {
 3967                    let snapshot = buffer.snapshot();
 3968                    let edits = edits
 3969                        .into_iter()
 3970                        .map(|(range, text)| {
 3971                            use text::ToPoint as TP;
 3972                            let end_point = TP::to_point(&range.end, &snapshot);
 3973                            let start_point = TP::to_point(&range.start, &snapshot);
 3974                            (start_point..end_point, text)
 3975                        })
 3976                        .sorted_by_key(|(range, _)| range.start);
 3977                    buffer.edit(edits, None, cx);
 3978                })
 3979            }
 3980            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3981            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3982            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3983            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3984                .zip(new_selection_deltas)
 3985                .map(|(selection, delta)| Selection {
 3986                    id: selection.id,
 3987                    start: selection.start + delta,
 3988                    end: selection.end + delta,
 3989                    reversed: selection.reversed,
 3990                    goal: SelectionGoal::None,
 3991                })
 3992                .collect::<Vec<_>>();
 3993
 3994            let mut i = 0;
 3995            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3996                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3997                let start = map.buffer_snapshot.anchor_before(position);
 3998                let end = map.buffer_snapshot.anchor_after(position);
 3999                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4000                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4001                        Ordering::Less => i += 1,
 4002                        Ordering::Greater => break,
 4003                        Ordering::Equal => {
 4004                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4005                                Ordering::Less => i += 1,
 4006                                Ordering::Equal => break,
 4007                                Ordering::Greater => break,
 4008                            }
 4009                        }
 4010                    }
 4011                }
 4012                this.autoclose_regions.insert(
 4013                    i,
 4014                    AutocloseRegion {
 4015                        selection_id,
 4016                        range: start..end,
 4017                        pair,
 4018                    },
 4019                );
 4020            }
 4021
 4022            let had_active_inline_completion = this.has_active_inline_completion();
 4023            this.change_selections_without_updating_completions(
 4024                Some(Autoscroll::fit()),
 4025                window,
 4026                cx,
 4027                |s| s.select(new_selections),
 4028            );
 4029
 4030            if !bracket_inserted {
 4031                if let Some(on_type_format_task) =
 4032                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4033                {
 4034                    on_type_format_task.detach_and_log_err(cx);
 4035                }
 4036            }
 4037
 4038            let editor_settings = EditorSettings::get_global(cx);
 4039            if bracket_inserted
 4040                && (editor_settings.auto_signature_help
 4041                    || editor_settings.show_signature_help_after_edits)
 4042            {
 4043                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4044            }
 4045
 4046            let trigger_in_words =
 4047                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4048            if this.hard_wrap.is_some() {
 4049                let latest: Range<Point> = this.selections.newest(cx).range();
 4050                if latest.is_empty()
 4051                    && this
 4052                        .buffer()
 4053                        .read(cx)
 4054                        .snapshot(cx)
 4055                        .line_len(MultiBufferRow(latest.start.row))
 4056                        == latest.start.column
 4057                {
 4058                    this.rewrap_impl(
 4059                        RewrapOptions {
 4060                            override_language_settings: true,
 4061                            preserve_existing_whitespace: true,
 4062                        },
 4063                        cx,
 4064                    )
 4065                }
 4066            }
 4067            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4068            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4069            this.refresh_inline_completion(true, false, window, cx);
 4070            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4071        });
 4072    }
 4073
 4074    fn find_possible_emoji_shortcode_at_position(
 4075        snapshot: &MultiBufferSnapshot,
 4076        position: Point,
 4077    ) -> Option<String> {
 4078        let mut chars = Vec::new();
 4079        let mut found_colon = false;
 4080        for char in snapshot.reversed_chars_at(position).take(100) {
 4081            // Found a possible emoji shortcode in the middle of the buffer
 4082            if found_colon {
 4083                if char.is_whitespace() {
 4084                    chars.reverse();
 4085                    return Some(chars.iter().collect());
 4086                }
 4087                // If the previous character is not a whitespace, we are in the middle of a word
 4088                // and we only want to complete the shortcode if the word is made up of other emojis
 4089                let mut containing_word = String::new();
 4090                for ch in snapshot
 4091                    .reversed_chars_at(position)
 4092                    .skip(chars.len() + 1)
 4093                    .take(100)
 4094                {
 4095                    if ch.is_whitespace() {
 4096                        break;
 4097                    }
 4098                    containing_word.push(ch);
 4099                }
 4100                let containing_word = containing_word.chars().rev().collect::<String>();
 4101                if util::word_consists_of_emojis(containing_word.as_str()) {
 4102                    chars.reverse();
 4103                    return Some(chars.iter().collect());
 4104                }
 4105            }
 4106
 4107            if char.is_whitespace() || !char.is_ascii() {
 4108                return None;
 4109            }
 4110            if char == ':' {
 4111                found_colon = true;
 4112            } else {
 4113                chars.push(char);
 4114            }
 4115        }
 4116        // Found a possible emoji shortcode at the beginning of the buffer
 4117        chars.reverse();
 4118        Some(chars.iter().collect())
 4119    }
 4120
 4121    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4122        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4123        self.transact(window, cx, |this, window, cx| {
 4124            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4125                let selections = this.selections.all::<usize>(cx);
 4126                let multi_buffer = this.buffer.read(cx);
 4127                let buffer = multi_buffer.snapshot(cx);
 4128                selections
 4129                    .iter()
 4130                    .map(|selection| {
 4131                        let start_point = selection.start.to_point(&buffer);
 4132                        let mut existing_indent =
 4133                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4134                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4135                        let start = selection.start;
 4136                        let end = selection.end;
 4137                        let selection_is_empty = start == end;
 4138                        let language_scope = buffer.language_scope_at(start);
 4139                        let (
 4140                            comment_delimiter,
 4141                            doc_delimiter,
 4142                            insert_extra_newline,
 4143                            indent_on_newline,
 4144                            indent_on_extra_newline,
 4145                        ) = if let Some(language) = &language_scope {
 4146                            let mut insert_extra_newline =
 4147                                insert_extra_newline_brackets(&buffer, start..end, language)
 4148                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4149
 4150                            // Comment extension on newline is allowed only for cursor selections
 4151                            let comment_delimiter = maybe!({
 4152                                if !selection_is_empty {
 4153                                    return None;
 4154                                }
 4155
 4156                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4157                                    return None;
 4158                                }
 4159
 4160                                let delimiters = language.line_comment_prefixes();
 4161                                let max_len_of_delimiter =
 4162                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4163                                let (snapshot, range) =
 4164                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4165
 4166                                let num_of_whitespaces = snapshot
 4167                                    .chars_for_range(range.clone())
 4168                                    .take_while(|c| c.is_whitespace())
 4169                                    .count();
 4170                                let comment_candidate = snapshot
 4171                                    .chars_for_range(range)
 4172                                    .skip(num_of_whitespaces)
 4173                                    .take(max_len_of_delimiter)
 4174                                    .collect::<String>();
 4175                                let (delimiter, trimmed_len) = delimiters
 4176                                    .iter()
 4177                                    .filter_map(|delimiter| {
 4178                                        let prefix = delimiter.trim_end();
 4179                                        if comment_candidate.starts_with(prefix) {
 4180                                            Some((delimiter, prefix.len()))
 4181                                        } else {
 4182                                            None
 4183                                        }
 4184                                    })
 4185                                    .max_by_key(|(_, len)| *len)?;
 4186
 4187                                let cursor_is_placed_after_comment_marker =
 4188                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4189                                if cursor_is_placed_after_comment_marker {
 4190                                    Some(delimiter.clone())
 4191                                } else {
 4192                                    None
 4193                                }
 4194                            });
 4195
 4196                            let mut indent_on_newline = IndentSize::spaces(0);
 4197                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4198
 4199                            let doc_delimiter = maybe!({
 4200                                if !selection_is_empty {
 4201                                    return None;
 4202                                }
 4203
 4204                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4205                                    return None;
 4206                                }
 4207
 4208                                let DocumentationConfig {
 4209                                    start: start_tag,
 4210                                    end: end_tag,
 4211                                    prefix: delimiter,
 4212                                    tab_size: len,
 4213                                } = language.documentation()?;
 4214
 4215                                let is_within_block_comment = buffer
 4216                                    .language_scope_at(start_point)
 4217                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4218                                if !is_within_block_comment {
 4219                                    return None;
 4220                                }
 4221
 4222                                let (snapshot, range) =
 4223                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4224
 4225                                let num_of_whitespaces = snapshot
 4226                                    .chars_for_range(range.clone())
 4227                                    .take_while(|c| c.is_whitespace())
 4228                                    .count();
 4229
 4230                                // 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.
 4231                                let column = start_point.column;
 4232                                let cursor_is_after_start_tag = {
 4233                                    let start_tag_len = start_tag.len();
 4234                                    let start_tag_line = snapshot
 4235                                        .chars_for_range(range.clone())
 4236                                        .skip(num_of_whitespaces)
 4237                                        .take(start_tag_len)
 4238                                        .collect::<String>();
 4239                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4240                                        num_of_whitespaces + start_tag_len <= column as usize
 4241                                    } else {
 4242                                        false
 4243                                    }
 4244                                };
 4245
 4246                                let cursor_is_after_delimiter = {
 4247                                    let delimiter_trim = delimiter.trim_end();
 4248                                    let delimiter_line = snapshot
 4249                                        .chars_for_range(range.clone())
 4250                                        .skip(num_of_whitespaces)
 4251                                        .take(delimiter_trim.len())
 4252                                        .collect::<String>();
 4253                                    if delimiter_line.starts_with(delimiter_trim) {
 4254                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4255                                    } else {
 4256                                        false
 4257                                    }
 4258                                };
 4259
 4260                                let cursor_is_before_end_tag_if_exists = {
 4261                                    let mut char_position = 0u32;
 4262                                    let mut end_tag_offset = None;
 4263
 4264                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4265                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4266                                            let chars_before_match =
 4267                                                chunk[..byte_pos].chars().count() as u32;
 4268                                            end_tag_offset =
 4269                                                Some(char_position + chars_before_match);
 4270                                            break 'outer;
 4271                                        }
 4272                                        char_position += chunk.chars().count() as u32;
 4273                                    }
 4274
 4275                                    if let Some(end_tag_offset) = end_tag_offset {
 4276                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4277                                        if cursor_is_after_start_tag {
 4278                                            if cursor_is_before_end_tag {
 4279                                                insert_extra_newline = true;
 4280                                            }
 4281                                            let cursor_is_at_start_of_end_tag =
 4282                                                column == end_tag_offset;
 4283                                            if cursor_is_at_start_of_end_tag {
 4284                                                indent_on_extra_newline.len = (*len).into();
 4285                                            }
 4286                                        }
 4287                                        cursor_is_before_end_tag
 4288                                    } else {
 4289                                        true
 4290                                    }
 4291                                };
 4292
 4293                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4294                                    && cursor_is_before_end_tag_if_exists
 4295                                {
 4296                                    if cursor_is_after_start_tag {
 4297                                        indent_on_newline.len = (*len).into();
 4298                                    }
 4299                                    Some(delimiter.clone())
 4300                                } else {
 4301                                    None
 4302                                }
 4303                            });
 4304
 4305                            (
 4306                                comment_delimiter,
 4307                                doc_delimiter,
 4308                                insert_extra_newline,
 4309                                indent_on_newline,
 4310                                indent_on_extra_newline,
 4311                            )
 4312                        } else {
 4313                            (
 4314                                None,
 4315                                None,
 4316                                false,
 4317                                IndentSize::default(),
 4318                                IndentSize::default(),
 4319                            )
 4320                        };
 4321
 4322                        let prevent_auto_indent = doc_delimiter.is_some();
 4323                        let delimiter = comment_delimiter.or(doc_delimiter);
 4324
 4325                        let capacity_for_delimiter =
 4326                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4327                        let mut new_text = String::with_capacity(
 4328                            1 + capacity_for_delimiter
 4329                                + existing_indent.len as usize
 4330                                + indent_on_newline.len as usize
 4331                                + indent_on_extra_newline.len as usize,
 4332                        );
 4333                        new_text.push('\n');
 4334                        new_text.extend(existing_indent.chars());
 4335                        new_text.extend(indent_on_newline.chars());
 4336
 4337                        if let Some(delimiter) = &delimiter {
 4338                            new_text.push_str(delimiter);
 4339                        }
 4340
 4341                        if insert_extra_newline {
 4342                            new_text.push('\n');
 4343                            new_text.extend(existing_indent.chars());
 4344                            new_text.extend(indent_on_extra_newline.chars());
 4345                        }
 4346
 4347                        let anchor = buffer.anchor_after(end);
 4348                        let new_selection = selection.map(|_| anchor);
 4349                        (
 4350                            ((start..end, new_text), prevent_auto_indent),
 4351                            (insert_extra_newline, new_selection),
 4352                        )
 4353                    })
 4354                    .unzip()
 4355            };
 4356
 4357            let mut auto_indent_edits = Vec::new();
 4358            let mut edits = Vec::new();
 4359            for (edit, prevent_auto_indent) in edits_with_flags {
 4360                if prevent_auto_indent {
 4361                    edits.push(edit);
 4362                } else {
 4363                    auto_indent_edits.push(edit);
 4364                }
 4365            }
 4366            if !edits.is_empty() {
 4367                this.edit(edits, cx);
 4368            }
 4369            if !auto_indent_edits.is_empty() {
 4370                this.edit_with_autoindent(auto_indent_edits, cx);
 4371            }
 4372
 4373            let buffer = this.buffer.read(cx).snapshot(cx);
 4374            let new_selections = selection_info
 4375                .into_iter()
 4376                .map(|(extra_newline_inserted, new_selection)| {
 4377                    let mut cursor = new_selection.end.to_point(&buffer);
 4378                    if extra_newline_inserted {
 4379                        cursor.row -= 1;
 4380                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4381                    }
 4382                    new_selection.map(|_| cursor)
 4383                })
 4384                .collect();
 4385
 4386            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4387                s.select(new_selections)
 4388            });
 4389            this.refresh_inline_completion(true, false, window, cx);
 4390        });
 4391    }
 4392
 4393    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4394        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4395
 4396        let buffer = self.buffer.read(cx);
 4397        let snapshot = buffer.snapshot(cx);
 4398
 4399        let mut edits = Vec::new();
 4400        let mut rows = Vec::new();
 4401
 4402        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4403            let cursor = selection.head();
 4404            let row = cursor.row;
 4405
 4406            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4407
 4408            let newline = "\n".to_string();
 4409            edits.push((start_of_line..start_of_line, newline));
 4410
 4411            rows.push(row + rows_inserted as u32);
 4412        }
 4413
 4414        self.transact(window, cx, |editor, window, cx| {
 4415            editor.edit(edits, cx);
 4416
 4417            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4418                let mut index = 0;
 4419                s.move_cursors_with(|map, _, _| {
 4420                    let row = rows[index];
 4421                    index += 1;
 4422
 4423                    let point = Point::new(row, 0);
 4424                    let boundary = map.next_line_boundary(point).1;
 4425                    let clipped = map.clip_point(boundary, Bias::Left);
 4426
 4427                    (clipped, SelectionGoal::None)
 4428                });
 4429            });
 4430
 4431            let mut indent_edits = Vec::new();
 4432            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4433            for row in rows {
 4434                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4435                for (row, indent) in indents {
 4436                    if indent.len == 0 {
 4437                        continue;
 4438                    }
 4439
 4440                    let text = match indent.kind {
 4441                        IndentKind::Space => " ".repeat(indent.len as usize),
 4442                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4443                    };
 4444                    let point = Point::new(row.0, 0);
 4445                    indent_edits.push((point..point, text));
 4446                }
 4447            }
 4448            editor.edit(indent_edits, cx);
 4449        });
 4450    }
 4451
 4452    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4453        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4454
 4455        let buffer = self.buffer.read(cx);
 4456        let snapshot = buffer.snapshot(cx);
 4457
 4458        let mut edits = Vec::new();
 4459        let mut rows = Vec::new();
 4460        let mut rows_inserted = 0;
 4461
 4462        for selection in self.selections.all_adjusted(cx) {
 4463            let cursor = selection.head();
 4464            let row = cursor.row;
 4465
 4466            let point = Point::new(row + 1, 0);
 4467            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4468
 4469            let newline = "\n".to_string();
 4470            edits.push((start_of_line..start_of_line, newline));
 4471
 4472            rows_inserted += 1;
 4473            rows.push(row + rows_inserted);
 4474        }
 4475
 4476        self.transact(window, cx, |editor, window, cx| {
 4477            editor.edit(edits, cx);
 4478
 4479            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4480                let mut index = 0;
 4481                s.move_cursors_with(|map, _, _| {
 4482                    let row = rows[index];
 4483                    index += 1;
 4484
 4485                    let point = Point::new(row, 0);
 4486                    let boundary = map.next_line_boundary(point).1;
 4487                    let clipped = map.clip_point(boundary, Bias::Left);
 4488
 4489                    (clipped, SelectionGoal::None)
 4490                });
 4491            });
 4492
 4493            let mut indent_edits = Vec::new();
 4494            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4495            for row in rows {
 4496                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4497                for (row, indent) in indents {
 4498                    if indent.len == 0 {
 4499                        continue;
 4500                    }
 4501
 4502                    let text = match indent.kind {
 4503                        IndentKind::Space => " ".repeat(indent.len as usize),
 4504                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4505                    };
 4506                    let point = Point::new(row.0, 0);
 4507                    indent_edits.push((point..point, text));
 4508                }
 4509            }
 4510            editor.edit(indent_edits, cx);
 4511        });
 4512    }
 4513
 4514    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4515        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4516            original_indent_columns: Vec::new(),
 4517        });
 4518        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4519    }
 4520
 4521    fn insert_with_autoindent_mode(
 4522        &mut self,
 4523        text: &str,
 4524        autoindent_mode: Option<AutoindentMode>,
 4525        window: &mut Window,
 4526        cx: &mut Context<Self>,
 4527    ) {
 4528        if self.read_only(cx) {
 4529            return;
 4530        }
 4531
 4532        let text: Arc<str> = text.into();
 4533        self.transact(window, cx, |this, window, cx| {
 4534            let old_selections = this.selections.all_adjusted(cx);
 4535            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4536                let anchors = {
 4537                    let snapshot = buffer.read(cx);
 4538                    old_selections
 4539                        .iter()
 4540                        .map(|s| {
 4541                            let anchor = snapshot.anchor_after(s.head());
 4542                            s.map(|_| anchor)
 4543                        })
 4544                        .collect::<Vec<_>>()
 4545                };
 4546                buffer.edit(
 4547                    old_selections
 4548                        .iter()
 4549                        .map(|s| (s.start..s.end, text.clone())),
 4550                    autoindent_mode,
 4551                    cx,
 4552                );
 4553                anchors
 4554            });
 4555
 4556            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4557                s.select_anchors(selection_anchors);
 4558            });
 4559
 4560            cx.notify();
 4561        });
 4562    }
 4563
 4564    fn trigger_completion_on_input(
 4565        &mut self,
 4566        text: &str,
 4567        trigger_in_words: bool,
 4568        window: &mut Window,
 4569        cx: &mut Context<Self>,
 4570    ) {
 4571        let completions_source = self
 4572            .context_menu
 4573            .borrow()
 4574            .as_ref()
 4575            .and_then(|menu| match menu {
 4576                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4577                CodeContextMenu::CodeActions(_) => None,
 4578            });
 4579
 4580        match completions_source {
 4581            Some(CompletionsMenuSource::Words) => {
 4582                self.show_word_completions(&ShowWordCompletions, window, cx)
 4583            }
 4584            Some(CompletionsMenuSource::Normal)
 4585            | Some(CompletionsMenuSource::SnippetChoices)
 4586            | None
 4587                if self.is_completion_trigger(
 4588                    text,
 4589                    trigger_in_words,
 4590                    completions_source.is_some(),
 4591                    cx,
 4592                ) =>
 4593            {
 4594                self.show_completions(
 4595                    &ShowCompletions {
 4596                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4597                    },
 4598                    window,
 4599                    cx,
 4600                )
 4601            }
 4602            _ => {
 4603                self.hide_context_menu(window, cx);
 4604            }
 4605        }
 4606    }
 4607
 4608    fn is_completion_trigger(
 4609        &self,
 4610        text: &str,
 4611        trigger_in_words: bool,
 4612        menu_is_open: bool,
 4613        cx: &mut Context<Self>,
 4614    ) -> bool {
 4615        let position = self.selections.newest_anchor().head();
 4616        let multibuffer = self.buffer.read(cx);
 4617        let Some(buffer) = position
 4618            .buffer_id
 4619            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4620        else {
 4621            return false;
 4622        };
 4623
 4624        if let Some(completion_provider) = &self.completion_provider {
 4625            completion_provider.is_completion_trigger(
 4626                &buffer,
 4627                position.text_anchor,
 4628                text,
 4629                trigger_in_words,
 4630                menu_is_open,
 4631                cx,
 4632            )
 4633        } else {
 4634            false
 4635        }
 4636    }
 4637
 4638    /// If any empty selections is touching the start of its innermost containing autoclose
 4639    /// region, expand it to select the brackets.
 4640    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4641        let selections = self.selections.all::<usize>(cx);
 4642        let buffer = self.buffer.read(cx).read(cx);
 4643        let new_selections = self
 4644            .selections_with_autoclose_regions(selections, &buffer)
 4645            .map(|(mut selection, region)| {
 4646                if !selection.is_empty() {
 4647                    return selection;
 4648                }
 4649
 4650                if let Some(region) = region {
 4651                    let mut range = region.range.to_offset(&buffer);
 4652                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4653                        range.start -= region.pair.start.len();
 4654                        if buffer.contains_str_at(range.start, &region.pair.start)
 4655                            && buffer.contains_str_at(range.end, &region.pair.end)
 4656                        {
 4657                            range.end += region.pair.end.len();
 4658                            selection.start = range.start;
 4659                            selection.end = range.end;
 4660
 4661                            return selection;
 4662                        }
 4663                    }
 4664                }
 4665
 4666                let always_treat_brackets_as_autoclosed = buffer
 4667                    .language_settings_at(selection.start, cx)
 4668                    .always_treat_brackets_as_autoclosed;
 4669
 4670                if !always_treat_brackets_as_autoclosed {
 4671                    return selection;
 4672                }
 4673
 4674                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4675                    for (pair, enabled) in scope.brackets() {
 4676                        if !enabled || !pair.close {
 4677                            continue;
 4678                        }
 4679
 4680                        if buffer.contains_str_at(selection.start, &pair.end) {
 4681                            let pair_start_len = pair.start.len();
 4682                            if buffer.contains_str_at(
 4683                                selection.start.saturating_sub(pair_start_len),
 4684                                &pair.start,
 4685                            ) {
 4686                                selection.start -= pair_start_len;
 4687                                selection.end += pair.end.len();
 4688
 4689                                return selection;
 4690                            }
 4691                        }
 4692                    }
 4693                }
 4694
 4695                selection
 4696            })
 4697            .collect();
 4698
 4699        drop(buffer);
 4700        self.change_selections(None, window, cx, |selections| {
 4701            selections.select(new_selections)
 4702        });
 4703    }
 4704
 4705    /// Iterate the given selections, and for each one, find the smallest surrounding
 4706    /// autoclose region. This uses the ordering of the selections and the autoclose
 4707    /// regions to avoid repeated comparisons.
 4708    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4709        &'a self,
 4710        selections: impl IntoIterator<Item = Selection<D>>,
 4711        buffer: &'a MultiBufferSnapshot,
 4712    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4713        let mut i = 0;
 4714        let mut regions = self.autoclose_regions.as_slice();
 4715        selections.into_iter().map(move |selection| {
 4716            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4717
 4718            let mut enclosing = None;
 4719            while let Some(pair_state) = regions.get(i) {
 4720                if pair_state.range.end.to_offset(buffer) < range.start {
 4721                    regions = &regions[i + 1..];
 4722                    i = 0;
 4723                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4724                    break;
 4725                } else {
 4726                    if pair_state.selection_id == selection.id {
 4727                        enclosing = Some(pair_state);
 4728                    }
 4729                    i += 1;
 4730                }
 4731            }
 4732
 4733            (selection, enclosing)
 4734        })
 4735    }
 4736
 4737    /// Remove any autoclose regions that no longer contain their selection.
 4738    fn invalidate_autoclose_regions(
 4739        &mut self,
 4740        mut selections: &[Selection<Anchor>],
 4741        buffer: &MultiBufferSnapshot,
 4742    ) {
 4743        self.autoclose_regions.retain(|state| {
 4744            let mut i = 0;
 4745            while let Some(selection) = selections.get(i) {
 4746                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4747                    selections = &selections[1..];
 4748                    continue;
 4749                }
 4750                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4751                    break;
 4752                }
 4753                if selection.id == state.selection_id {
 4754                    return true;
 4755                } else {
 4756                    i += 1;
 4757                }
 4758            }
 4759            false
 4760        });
 4761    }
 4762
 4763    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4764        let offset = position.to_offset(buffer);
 4765        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4766        if offset > word_range.start && kind == Some(CharKind::Word) {
 4767            Some(
 4768                buffer
 4769                    .text_for_range(word_range.start..offset)
 4770                    .collect::<String>(),
 4771            )
 4772        } else {
 4773            None
 4774        }
 4775    }
 4776
 4777    pub fn toggle_inline_values(
 4778        &mut self,
 4779        _: &ToggleInlineValues,
 4780        _: &mut Window,
 4781        cx: &mut Context<Self>,
 4782    ) {
 4783        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4784
 4785        self.refresh_inline_values(cx);
 4786    }
 4787
 4788    pub fn toggle_inlay_hints(
 4789        &mut self,
 4790        _: &ToggleInlayHints,
 4791        _: &mut Window,
 4792        cx: &mut Context<Self>,
 4793    ) {
 4794        self.refresh_inlay_hints(
 4795            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4796            cx,
 4797        );
 4798    }
 4799
 4800    pub fn inlay_hints_enabled(&self) -> bool {
 4801        self.inlay_hint_cache.enabled
 4802    }
 4803
 4804    pub fn inline_values_enabled(&self) -> bool {
 4805        self.inline_value_cache.enabled
 4806    }
 4807
 4808    #[cfg(any(test, feature = "test-support"))]
 4809    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4810        self.display_map
 4811            .read(cx)
 4812            .current_inlays()
 4813            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4814            .cloned()
 4815            .collect()
 4816    }
 4817
 4818    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4819        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4820            return;
 4821        }
 4822
 4823        let reason_description = reason.description();
 4824        let ignore_debounce = matches!(
 4825            reason,
 4826            InlayHintRefreshReason::SettingsChange(_)
 4827                | InlayHintRefreshReason::Toggle(_)
 4828                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4829                | InlayHintRefreshReason::ModifiersChanged(_)
 4830        );
 4831        let (invalidate_cache, required_languages) = match reason {
 4832            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4833                match self.inlay_hint_cache.modifiers_override(enabled) {
 4834                    Some(enabled) => {
 4835                        if enabled {
 4836                            (InvalidationStrategy::RefreshRequested, None)
 4837                        } else {
 4838                            self.splice_inlays(
 4839                                &self
 4840                                    .visible_inlay_hints(cx)
 4841                                    .iter()
 4842                                    .map(|inlay| inlay.id)
 4843                                    .collect::<Vec<InlayId>>(),
 4844                                Vec::new(),
 4845                                cx,
 4846                            );
 4847                            return;
 4848                        }
 4849                    }
 4850                    None => return,
 4851                }
 4852            }
 4853            InlayHintRefreshReason::Toggle(enabled) => {
 4854                if self.inlay_hint_cache.toggle(enabled) {
 4855                    if enabled {
 4856                        (InvalidationStrategy::RefreshRequested, None)
 4857                    } else {
 4858                        self.splice_inlays(
 4859                            &self
 4860                                .visible_inlay_hints(cx)
 4861                                .iter()
 4862                                .map(|inlay| inlay.id)
 4863                                .collect::<Vec<InlayId>>(),
 4864                            Vec::new(),
 4865                            cx,
 4866                        );
 4867                        return;
 4868                    }
 4869                } else {
 4870                    return;
 4871                }
 4872            }
 4873            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4874                match self.inlay_hint_cache.update_settings(
 4875                    &self.buffer,
 4876                    new_settings,
 4877                    self.visible_inlay_hints(cx),
 4878                    cx,
 4879                ) {
 4880                    ControlFlow::Break(Some(InlaySplice {
 4881                        to_remove,
 4882                        to_insert,
 4883                    })) => {
 4884                        self.splice_inlays(&to_remove, to_insert, cx);
 4885                        return;
 4886                    }
 4887                    ControlFlow::Break(None) => return,
 4888                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4889                }
 4890            }
 4891            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4892                if let Some(InlaySplice {
 4893                    to_remove,
 4894                    to_insert,
 4895                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4896                {
 4897                    self.splice_inlays(&to_remove, to_insert, cx);
 4898                }
 4899                self.display_map.update(cx, |display_map, _| {
 4900                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4901                });
 4902                return;
 4903            }
 4904            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4905            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4906                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4907            }
 4908            InlayHintRefreshReason::RefreshRequested => {
 4909                (InvalidationStrategy::RefreshRequested, None)
 4910            }
 4911        };
 4912
 4913        if let Some(InlaySplice {
 4914            to_remove,
 4915            to_insert,
 4916        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4917            reason_description,
 4918            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4919            invalidate_cache,
 4920            ignore_debounce,
 4921            cx,
 4922        ) {
 4923            self.splice_inlays(&to_remove, to_insert, cx);
 4924        }
 4925    }
 4926
 4927    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4928        self.display_map
 4929            .read(cx)
 4930            .current_inlays()
 4931            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4932            .cloned()
 4933            .collect()
 4934    }
 4935
 4936    pub fn excerpts_for_inlay_hints_query(
 4937        &self,
 4938        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4939        cx: &mut Context<Editor>,
 4940    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4941        let Some(project) = self.project.as_ref() else {
 4942            return HashMap::default();
 4943        };
 4944        let project = project.read(cx);
 4945        let multi_buffer = self.buffer().read(cx);
 4946        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4947        let multi_buffer_visible_start = self
 4948            .scroll_manager
 4949            .anchor()
 4950            .anchor
 4951            .to_point(&multi_buffer_snapshot);
 4952        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4953            multi_buffer_visible_start
 4954                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4955            Bias::Left,
 4956        );
 4957        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4958        multi_buffer_snapshot
 4959            .range_to_buffer_ranges(multi_buffer_visible_range)
 4960            .into_iter()
 4961            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4962            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4963                let buffer_file = project::File::from_dyn(buffer.file())?;
 4964                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4965                let worktree_entry = buffer_worktree
 4966                    .read(cx)
 4967                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4968                if worktree_entry.is_ignored {
 4969                    return None;
 4970                }
 4971
 4972                let language = buffer.language()?;
 4973                if let Some(restrict_to_languages) = restrict_to_languages {
 4974                    if !restrict_to_languages.contains(language) {
 4975                        return None;
 4976                    }
 4977                }
 4978                Some((
 4979                    excerpt_id,
 4980                    (
 4981                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4982                        buffer.version().clone(),
 4983                        excerpt_visible_range,
 4984                    ),
 4985                ))
 4986            })
 4987            .collect()
 4988    }
 4989
 4990    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4991        TextLayoutDetails {
 4992            text_system: window.text_system().clone(),
 4993            editor_style: self.style.clone().unwrap(),
 4994            rem_size: window.rem_size(),
 4995            scroll_anchor: self.scroll_manager.anchor(),
 4996            visible_rows: self.visible_line_count(),
 4997            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4998        }
 4999    }
 5000
 5001    pub fn splice_inlays(
 5002        &self,
 5003        to_remove: &[InlayId],
 5004        to_insert: Vec<Inlay>,
 5005        cx: &mut Context<Self>,
 5006    ) {
 5007        self.display_map.update(cx, |display_map, cx| {
 5008            display_map.splice_inlays(to_remove, to_insert, cx)
 5009        });
 5010        cx.notify();
 5011    }
 5012
 5013    fn trigger_on_type_formatting(
 5014        &self,
 5015        input: String,
 5016        window: &mut Window,
 5017        cx: &mut Context<Self>,
 5018    ) -> Option<Task<Result<()>>> {
 5019        if input.len() != 1 {
 5020            return None;
 5021        }
 5022
 5023        let project = self.project.as_ref()?;
 5024        let position = self.selections.newest_anchor().head();
 5025        let (buffer, buffer_position) = self
 5026            .buffer
 5027            .read(cx)
 5028            .text_anchor_for_position(position, cx)?;
 5029
 5030        let settings = language_settings::language_settings(
 5031            buffer
 5032                .read(cx)
 5033                .language_at(buffer_position)
 5034                .map(|l| l.name()),
 5035            buffer.read(cx).file(),
 5036            cx,
 5037        );
 5038        if !settings.use_on_type_format {
 5039            return None;
 5040        }
 5041
 5042        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5043        // hence we do LSP request & edit on host side only — add formats to host's history.
 5044        let push_to_lsp_host_history = true;
 5045        // If this is not the host, append its history with new edits.
 5046        let push_to_client_history = project.read(cx).is_via_collab();
 5047
 5048        let on_type_formatting = project.update(cx, |project, cx| {
 5049            project.on_type_format(
 5050                buffer.clone(),
 5051                buffer_position,
 5052                input,
 5053                push_to_lsp_host_history,
 5054                cx,
 5055            )
 5056        });
 5057        Some(cx.spawn_in(window, async move |editor, cx| {
 5058            if let Some(transaction) = on_type_formatting.await? {
 5059                if push_to_client_history {
 5060                    buffer
 5061                        .update(cx, |buffer, _| {
 5062                            buffer.push_transaction(transaction, Instant::now());
 5063                            buffer.finalize_last_transaction();
 5064                        })
 5065                        .ok();
 5066                }
 5067                editor.update(cx, |editor, cx| {
 5068                    editor.refresh_document_highlights(cx);
 5069                })?;
 5070            }
 5071            Ok(())
 5072        }))
 5073    }
 5074
 5075    pub fn show_word_completions(
 5076        &mut self,
 5077        _: &ShowWordCompletions,
 5078        window: &mut Window,
 5079        cx: &mut Context<Self>,
 5080    ) {
 5081        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5082    }
 5083
 5084    pub fn show_completions(
 5085        &mut self,
 5086        options: &ShowCompletions,
 5087        window: &mut Window,
 5088        cx: &mut Context<Self>,
 5089    ) {
 5090        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5091    }
 5092
 5093    fn open_or_update_completions_menu(
 5094        &mut self,
 5095        requested_source: Option<CompletionsMenuSource>,
 5096        trigger: Option<&str>,
 5097        window: &mut Window,
 5098        cx: &mut Context<Self>,
 5099    ) {
 5100        if self.pending_rename.is_some() {
 5101            return;
 5102        }
 5103
 5104        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5105
 5106        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5107        // inserted and selected. To handle that case, the start of the selection is used so that
 5108        // the menu starts with all choices.
 5109        let position = self
 5110            .selections
 5111            .newest_anchor()
 5112            .start
 5113            .bias_right(&multibuffer_snapshot);
 5114        if position.diff_base_anchor.is_some() {
 5115            return;
 5116        }
 5117        let (buffer, buffer_position) =
 5118            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5119                output
 5120            } else {
 5121                return;
 5122            };
 5123        let buffer_snapshot = buffer.read(cx).snapshot();
 5124
 5125        let query: Option<Arc<String>> =
 5126            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5127
 5128        drop(multibuffer_snapshot);
 5129
 5130        let provider = match requested_source {
 5131            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5132            Some(CompletionsMenuSource::Words) => None,
 5133            Some(CompletionsMenuSource::SnippetChoices) => {
 5134                log::error!("bug: SnippetChoices requested_source is not handled");
 5135                None
 5136            }
 5137        };
 5138
 5139        let sort_completions = provider
 5140            .as_ref()
 5141            .map_or(false, |provider| provider.sort_completions());
 5142
 5143        let filter_completions = provider
 5144            .as_ref()
 5145            .map_or(true, |provider| provider.filter_completions());
 5146
 5147        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5148            if filter_completions {
 5149                menu.filter(query.clone(), provider.clone(), window, cx);
 5150            }
 5151            // When `is_incomplete` is false, no need to re-query completions when the current query
 5152            // is a suffix of the initial query.
 5153            if !menu.is_incomplete {
 5154                // If the new query is a suffix of the old query (typing more characters) and
 5155                // the previous result was complete, the existing completions can be filtered.
 5156                //
 5157                // Note that this is always true for snippet completions.
 5158                let query_matches = match (&menu.initial_query, &query) {
 5159                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5160                    (None, _) => true,
 5161                    _ => false,
 5162                };
 5163                if query_matches {
 5164                    let position_matches = if menu.initial_position == position {
 5165                        true
 5166                    } else {
 5167                        let snapshot = self.buffer.read(cx).read(cx);
 5168                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5169                    };
 5170                    if position_matches {
 5171                        return;
 5172                    }
 5173                }
 5174            }
 5175        };
 5176
 5177        let trigger_kind = match trigger {
 5178            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5179                CompletionTriggerKind::TRIGGER_CHARACTER
 5180            }
 5181            _ => CompletionTriggerKind::INVOKED,
 5182        };
 5183        let completion_context = CompletionContext {
 5184            trigger_character: trigger.and_then(|trigger| {
 5185                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5186                    Some(String::from(trigger))
 5187                } else {
 5188                    None
 5189                }
 5190            }),
 5191            trigger_kind,
 5192        };
 5193
 5194        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5195            buffer_snapshot.surrounding_word(buffer_position)
 5196        {
 5197            let word_to_exclude = buffer_snapshot
 5198                .text_for_range(word_range.clone())
 5199                .collect::<String>();
 5200            (
 5201                buffer_snapshot.anchor_before(word_range.start)
 5202                    ..buffer_snapshot.anchor_after(buffer_position),
 5203                Some(word_to_exclude),
 5204            )
 5205        } else {
 5206            (buffer_position..buffer_position, None)
 5207        };
 5208
 5209        let language = buffer_snapshot
 5210            .language_at(buffer_position)
 5211            .map(|language| language.name());
 5212
 5213        let completion_settings =
 5214            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5215
 5216        let show_completion_documentation = buffer_snapshot
 5217            .settings_at(buffer_position, cx)
 5218            .show_completion_documentation;
 5219
 5220        // The document can be large, so stay in reasonable bounds when searching for words,
 5221        // otherwise completion pop-up might be slow to appear.
 5222        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5223        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5224        let min_word_search = buffer_snapshot.clip_point(
 5225            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5226            Bias::Left,
 5227        );
 5228        let max_word_search = buffer_snapshot.clip_point(
 5229            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5230            Bias::Right,
 5231        );
 5232        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5233            ..buffer_snapshot.point_to_offset(max_word_search);
 5234
 5235        let skip_digits = query
 5236            .as_ref()
 5237            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5238
 5239        let (mut words, provider_responses) = match &provider {
 5240            Some(provider) => {
 5241                let provider_responses = provider.completions(
 5242                    position.excerpt_id,
 5243                    &buffer,
 5244                    buffer_position,
 5245                    completion_context,
 5246                    window,
 5247                    cx,
 5248                );
 5249
 5250                let words = match completion_settings.words {
 5251                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5252                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5253                        .background_spawn(async move {
 5254                            buffer_snapshot.words_in_range(WordsQuery {
 5255                                fuzzy_contents: None,
 5256                                range: word_search_range,
 5257                                skip_digits,
 5258                            })
 5259                        }),
 5260                };
 5261
 5262                (words, provider_responses)
 5263            }
 5264            None => (
 5265                cx.background_spawn(async move {
 5266                    buffer_snapshot.words_in_range(WordsQuery {
 5267                        fuzzy_contents: None,
 5268                        range: word_search_range,
 5269                        skip_digits,
 5270                    })
 5271                }),
 5272                Task::ready(Ok(Vec::new())),
 5273            ),
 5274        };
 5275
 5276        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5277
 5278        let id = post_inc(&mut self.next_completion_id);
 5279        let task = cx.spawn_in(window, async move |editor, cx| {
 5280            let Ok(()) = editor.update(cx, |this, _| {
 5281                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5282            }) else {
 5283                return;
 5284            };
 5285
 5286            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5287            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5288            let mut completions = Vec::new();
 5289            let mut is_incomplete = false;
 5290            if let Some(provider_responses) = provider_responses.await.log_err() {
 5291                if !provider_responses.is_empty() {
 5292                    for response in provider_responses {
 5293                        completions.extend(response.completions);
 5294                        is_incomplete = is_incomplete || response.is_incomplete;
 5295                    }
 5296                    if completion_settings.words == WordsCompletionMode::Fallback {
 5297                        words = Task::ready(BTreeMap::default());
 5298                    }
 5299                }
 5300            }
 5301
 5302            let mut words = words.await;
 5303            if let Some(word_to_exclude) = &word_to_exclude {
 5304                words.remove(word_to_exclude);
 5305            }
 5306            for lsp_completion in &completions {
 5307                words.remove(&lsp_completion.new_text);
 5308            }
 5309            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5310                replace_range: word_replace_range.clone(),
 5311                new_text: word.clone(),
 5312                label: CodeLabel::plain(word, None),
 5313                icon_path: None,
 5314                documentation: None,
 5315                source: CompletionSource::BufferWord {
 5316                    word_range,
 5317                    resolved: false,
 5318                },
 5319                insert_text_mode: Some(InsertTextMode::AS_IS),
 5320                confirm: None,
 5321            }));
 5322
 5323            let menu = if completions.is_empty() {
 5324                None
 5325            } else {
 5326                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5327                    let languages = editor
 5328                        .workspace
 5329                        .as_ref()
 5330                        .and_then(|(workspace, _)| workspace.upgrade())
 5331                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5332                    let menu = CompletionsMenu::new(
 5333                        id,
 5334                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5335                        sort_completions,
 5336                        show_completion_documentation,
 5337                        position,
 5338                        query.clone(),
 5339                        is_incomplete,
 5340                        buffer.clone(),
 5341                        completions.into(),
 5342                        snippet_sort_order,
 5343                        languages,
 5344                        language,
 5345                        cx,
 5346                    );
 5347
 5348                    let query = if filter_completions { query } else { None };
 5349                    let matches_task = if let Some(query) = query {
 5350                        menu.do_async_filtering(query, cx)
 5351                    } else {
 5352                        Task::ready(menu.unfiltered_matches())
 5353                    };
 5354                    (menu, matches_task)
 5355                }) else {
 5356                    return;
 5357                };
 5358
 5359                let matches = matches_task.await;
 5360
 5361                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5362                    // Newer menu already set, so exit.
 5363                    match editor.context_menu.borrow().as_ref() {
 5364                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5365                            if prev_menu.id > id {
 5366                                return;
 5367                            }
 5368                        }
 5369                        _ => {}
 5370                    };
 5371
 5372                    // Only valid to take prev_menu because it the new menu is immediately set
 5373                    // below, or the menu is hidden.
 5374                    match editor.context_menu.borrow_mut().take() {
 5375                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5376                            let position_matches =
 5377                                if prev_menu.initial_position == menu.initial_position {
 5378                                    true
 5379                                } else {
 5380                                    let snapshot = editor.buffer.read(cx).read(cx);
 5381                                    prev_menu.initial_position.to_offset(&snapshot)
 5382                                        == menu.initial_position.to_offset(&snapshot)
 5383                                };
 5384                            if position_matches {
 5385                                // Preserve markdown cache before `set_filter_results` because it will
 5386                                // try to populate the documentation cache.
 5387                                menu.preserve_markdown_cache(prev_menu);
 5388                            }
 5389                        }
 5390                        _ => {}
 5391                    };
 5392
 5393                    menu.set_filter_results(matches, provider, window, cx);
 5394                }) else {
 5395                    return;
 5396                };
 5397
 5398                menu.visible().then_some(menu)
 5399            };
 5400
 5401            editor
 5402                .update_in(cx, |editor, window, cx| {
 5403                    if editor.focus_handle.is_focused(window) {
 5404                        if let Some(menu) = menu {
 5405                            *editor.context_menu.borrow_mut() =
 5406                                Some(CodeContextMenu::Completions(menu));
 5407
 5408                            crate::hover_popover::hide_hover(editor, cx);
 5409                            if editor.show_edit_predictions_in_menu() {
 5410                                editor.update_visible_inline_completion(window, cx);
 5411                            } else {
 5412                                editor.discard_inline_completion(false, cx);
 5413                            }
 5414
 5415                            cx.notify();
 5416                            return;
 5417                        }
 5418                    }
 5419
 5420                    if editor.completion_tasks.len() <= 1 {
 5421                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5422                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5423                        // If it was already hidden and we don't show inline completions in the menu, we should
 5424                        // also show the inline-completion when available.
 5425                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5426                            editor.update_visible_inline_completion(window, cx);
 5427                        }
 5428                    }
 5429                })
 5430                .ok();
 5431        });
 5432
 5433        self.completion_tasks.push((id, task));
 5434    }
 5435
 5436    #[cfg(feature = "test-support")]
 5437    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5438        let menu = self.context_menu.borrow();
 5439        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5440            let completions = menu.completions.borrow();
 5441            Some(completions.to_vec())
 5442        } else {
 5443            None
 5444        }
 5445    }
 5446
 5447    pub fn with_completions_menu_matching_id<R>(
 5448        &self,
 5449        id: CompletionId,
 5450        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5451    ) -> R {
 5452        let mut context_menu = self.context_menu.borrow_mut();
 5453        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5454            return f(None);
 5455        };
 5456        if completions_menu.id != id {
 5457            return f(None);
 5458        }
 5459        f(Some(completions_menu))
 5460    }
 5461
 5462    pub fn confirm_completion(
 5463        &mut self,
 5464        action: &ConfirmCompletion,
 5465        window: &mut Window,
 5466        cx: &mut Context<Self>,
 5467    ) -> Option<Task<Result<()>>> {
 5468        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5469        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5470    }
 5471
 5472    pub fn confirm_completion_insert(
 5473        &mut self,
 5474        _: &ConfirmCompletionInsert,
 5475        window: &mut Window,
 5476        cx: &mut Context<Self>,
 5477    ) -> Option<Task<Result<()>>> {
 5478        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5479        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5480    }
 5481
 5482    pub fn confirm_completion_replace(
 5483        &mut self,
 5484        _: &ConfirmCompletionReplace,
 5485        window: &mut Window,
 5486        cx: &mut Context<Self>,
 5487    ) -> Option<Task<Result<()>>> {
 5488        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5489        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5490    }
 5491
 5492    pub fn compose_completion(
 5493        &mut self,
 5494        action: &ComposeCompletion,
 5495        window: &mut Window,
 5496        cx: &mut Context<Self>,
 5497    ) -> Option<Task<Result<()>>> {
 5498        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5499        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5500    }
 5501
 5502    fn do_completion(
 5503        &mut self,
 5504        item_ix: Option<usize>,
 5505        intent: CompletionIntent,
 5506        window: &mut Window,
 5507        cx: &mut Context<Editor>,
 5508    ) -> Option<Task<Result<()>>> {
 5509        use language::ToOffset as _;
 5510
 5511        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5512        else {
 5513            return None;
 5514        };
 5515
 5516        let candidate_id = {
 5517            let entries = completions_menu.entries.borrow();
 5518            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5519            if self.show_edit_predictions_in_menu() {
 5520                self.discard_inline_completion(true, cx);
 5521            }
 5522            mat.candidate_id
 5523        };
 5524
 5525        let completion = completions_menu
 5526            .completions
 5527            .borrow()
 5528            .get(candidate_id)?
 5529            .clone();
 5530        cx.stop_propagation();
 5531
 5532        let buffer_handle = completions_menu.buffer.clone();
 5533
 5534        let CompletionEdit {
 5535            new_text,
 5536            snippet,
 5537            replace_range,
 5538        } = process_completion_for_edit(
 5539            &completion,
 5540            intent,
 5541            &buffer_handle,
 5542            &completions_menu.initial_position.text_anchor,
 5543            cx,
 5544        );
 5545
 5546        let buffer = buffer_handle.read(cx);
 5547        let snapshot = self.buffer.read(cx).snapshot(cx);
 5548        let newest_anchor = self.selections.newest_anchor();
 5549        let replace_range_multibuffer = {
 5550            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5551            let multibuffer_anchor = snapshot
 5552                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5553                .unwrap()
 5554                ..snapshot
 5555                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5556                    .unwrap();
 5557            multibuffer_anchor.start.to_offset(&snapshot)
 5558                ..multibuffer_anchor.end.to_offset(&snapshot)
 5559        };
 5560        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5561            return None;
 5562        }
 5563
 5564        let old_text = buffer
 5565            .text_for_range(replace_range.clone())
 5566            .collect::<String>();
 5567        let lookbehind = newest_anchor
 5568            .start
 5569            .text_anchor
 5570            .to_offset(buffer)
 5571            .saturating_sub(replace_range.start);
 5572        let lookahead = replace_range
 5573            .end
 5574            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5575        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5576        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5577
 5578        let selections = self.selections.all::<usize>(cx);
 5579        let mut ranges = Vec::new();
 5580        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5581
 5582        for selection in &selections {
 5583            let range = if selection.id == newest_anchor.id {
 5584                replace_range_multibuffer.clone()
 5585            } else {
 5586                let mut range = selection.range();
 5587
 5588                // if prefix is present, don't duplicate it
 5589                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5590                    range.start = range.start.saturating_sub(lookbehind);
 5591
 5592                    // if suffix is also present, mimic the newest cursor and replace it
 5593                    if selection.id != newest_anchor.id
 5594                        && snapshot.contains_str_at(range.end, suffix)
 5595                    {
 5596                        range.end += lookahead;
 5597                    }
 5598                }
 5599                range
 5600            };
 5601
 5602            ranges.push(range.clone());
 5603
 5604            if !self.linked_edit_ranges.is_empty() {
 5605                let start_anchor = snapshot.anchor_before(range.start);
 5606                let end_anchor = snapshot.anchor_after(range.end);
 5607                if let Some(ranges) = self
 5608                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5609                {
 5610                    for (buffer, edits) in ranges {
 5611                        linked_edits
 5612                            .entry(buffer.clone())
 5613                            .or_default()
 5614                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5615                    }
 5616                }
 5617            }
 5618        }
 5619
 5620        let common_prefix_len = old_text
 5621            .chars()
 5622            .zip(new_text.chars())
 5623            .take_while(|(a, b)| a == b)
 5624            .map(|(a, _)| a.len_utf8())
 5625            .sum::<usize>();
 5626
 5627        cx.emit(EditorEvent::InputHandled {
 5628            utf16_range_to_replace: None,
 5629            text: new_text[common_prefix_len..].into(),
 5630        });
 5631
 5632        self.transact(window, cx, |this, window, cx| {
 5633            if let Some(mut snippet) = snippet {
 5634                snippet.text = new_text.to_string();
 5635                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5636            } else {
 5637                this.buffer.update(cx, |buffer, cx| {
 5638                    let auto_indent = match completion.insert_text_mode {
 5639                        Some(InsertTextMode::AS_IS) => None,
 5640                        _ => this.autoindent_mode.clone(),
 5641                    };
 5642                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5643                    buffer.edit(edits, auto_indent, cx);
 5644                });
 5645            }
 5646            for (buffer, edits) in linked_edits {
 5647                buffer.update(cx, |buffer, cx| {
 5648                    let snapshot = buffer.snapshot();
 5649                    let edits = edits
 5650                        .into_iter()
 5651                        .map(|(range, text)| {
 5652                            use text::ToPoint as TP;
 5653                            let end_point = TP::to_point(&range.end, &snapshot);
 5654                            let start_point = TP::to_point(&range.start, &snapshot);
 5655                            (start_point..end_point, text)
 5656                        })
 5657                        .sorted_by_key(|(range, _)| range.start);
 5658                    buffer.edit(edits, None, cx);
 5659                })
 5660            }
 5661
 5662            this.refresh_inline_completion(true, false, window, cx);
 5663        });
 5664
 5665        let show_new_completions_on_confirm = completion
 5666            .confirm
 5667            .as_ref()
 5668            .map_or(false, |confirm| confirm(intent, window, cx));
 5669        if show_new_completions_on_confirm {
 5670            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5671        }
 5672
 5673        let provider = self.completion_provider.as_ref()?;
 5674        drop(completion);
 5675        let apply_edits = provider.apply_additional_edits_for_completion(
 5676            buffer_handle,
 5677            completions_menu.completions.clone(),
 5678            candidate_id,
 5679            true,
 5680            cx,
 5681        );
 5682
 5683        let editor_settings = EditorSettings::get_global(cx);
 5684        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5685            // After the code completion is finished, users often want to know what signatures are needed.
 5686            // so we should automatically call signature_help
 5687            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5688        }
 5689
 5690        Some(cx.foreground_executor().spawn(async move {
 5691            apply_edits.await?;
 5692            Ok(())
 5693        }))
 5694    }
 5695
 5696    pub fn toggle_code_actions(
 5697        &mut self,
 5698        action: &ToggleCodeActions,
 5699        window: &mut Window,
 5700        cx: &mut Context<Self>,
 5701    ) {
 5702        let quick_launch = action.quick_launch;
 5703        let mut context_menu = self.context_menu.borrow_mut();
 5704        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5705            if code_actions.deployed_from == action.deployed_from {
 5706                // Toggle if we're selecting the same one
 5707                *context_menu = None;
 5708                cx.notify();
 5709                return;
 5710            } else {
 5711                // Otherwise, clear it and start a new one
 5712                *context_menu = None;
 5713                cx.notify();
 5714            }
 5715        }
 5716        drop(context_menu);
 5717        let snapshot = self.snapshot(window, cx);
 5718        let deployed_from = action.deployed_from.clone();
 5719        let action = action.clone();
 5720        self.completion_tasks.clear();
 5721        self.discard_inline_completion(false, cx);
 5722
 5723        let multibuffer_point = match &action.deployed_from {
 5724            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5725                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5726            }
 5727            _ => self.selections.newest::<Point>(cx).head(),
 5728        };
 5729        let Some((buffer, buffer_row)) = snapshot
 5730            .buffer_snapshot
 5731            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5732            .and_then(|(buffer_snapshot, range)| {
 5733                self.buffer()
 5734                    .read(cx)
 5735                    .buffer(buffer_snapshot.remote_id())
 5736                    .map(|buffer| (buffer, range.start.row))
 5737            })
 5738        else {
 5739            return;
 5740        };
 5741        let buffer_id = buffer.read(cx).remote_id();
 5742        let tasks = self
 5743            .tasks
 5744            .get(&(buffer_id, buffer_row))
 5745            .map(|t| Arc::new(t.to_owned()));
 5746
 5747        if !self.focus_handle.is_focused(window) {
 5748            return;
 5749        }
 5750        let project = self.project.clone();
 5751
 5752        let code_actions_task = match deployed_from {
 5753            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5754            _ => self.code_actions(buffer_row, window, cx),
 5755        };
 5756
 5757        let runnable_task = match deployed_from {
 5758            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5759            _ => {
 5760                let mut task_context_task = Task::ready(None);
 5761                if let Some(tasks) = &tasks {
 5762                    if let Some(project) = project {
 5763                        task_context_task =
 5764                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5765                    }
 5766                }
 5767
 5768                cx.spawn_in(window, {
 5769                    let buffer = buffer.clone();
 5770                    async move |editor, cx| {
 5771                        let task_context = task_context_task.await;
 5772
 5773                        let resolved_tasks =
 5774                            tasks
 5775                                .zip(task_context.clone())
 5776                                .map(|(tasks, task_context)| ResolvedTasks {
 5777                                    templates: tasks.resolve(&task_context).collect(),
 5778                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5779                                        multibuffer_point.row,
 5780                                        tasks.column,
 5781                                    )),
 5782                                });
 5783                        let debug_scenarios = editor
 5784                            .update(cx, |editor, cx| {
 5785                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5786                            })?
 5787                            .await;
 5788                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5789                    }
 5790                })
 5791            }
 5792        };
 5793
 5794        cx.spawn_in(window, async move |editor, cx| {
 5795            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5796            let code_actions = code_actions_task.await;
 5797            let spawn_straight_away = quick_launch
 5798                && resolved_tasks
 5799                    .as_ref()
 5800                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5801                && code_actions
 5802                    .as_ref()
 5803                    .map_or(true, |actions| actions.is_empty())
 5804                && debug_scenarios.is_empty();
 5805
 5806            editor.update_in(cx, |editor, window, cx| {
 5807                crate::hover_popover::hide_hover(editor, cx);
 5808                *editor.context_menu.borrow_mut() =
 5809                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5810                        buffer,
 5811                        actions: CodeActionContents::new(
 5812                            resolved_tasks,
 5813                            code_actions,
 5814                            debug_scenarios,
 5815                            task_context.unwrap_or_default(),
 5816                        ),
 5817                        selected_item: Default::default(),
 5818                        scroll_handle: UniformListScrollHandle::default(),
 5819                        deployed_from,
 5820                    }));
 5821                if spawn_straight_away {
 5822                    if let Some(task) = editor.confirm_code_action(
 5823                        &ConfirmCodeAction { item_ix: Some(0) },
 5824                        window,
 5825                        cx,
 5826                    ) {
 5827                        cx.notify();
 5828                        return task;
 5829                    }
 5830                }
 5831
 5832                Task::ready(Ok(()))
 5833            })
 5834        })
 5835        .detach_and_log_err(cx);
 5836    }
 5837
 5838    fn debug_scenarios(
 5839        &mut self,
 5840        resolved_tasks: &Option<ResolvedTasks>,
 5841        buffer: &Entity<Buffer>,
 5842        cx: &mut App,
 5843    ) -> Task<Vec<task::DebugScenario>> {
 5844        if cx.has_flag::<DebuggerFeatureFlag>() {
 5845            maybe!({
 5846                let project = self.project.as_ref()?;
 5847                let dap_store = project.read(cx).dap_store();
 5848                let mut scenarios = vec![];
 5849                let resolved_tasks = resolved_tasks.as_ref()?;
 5850                let buffer = buffer.read(cx);
 5851                let language = buffer.language()?;
 5852                let file = buffer.file();
 5853                let debug_adapter = language_settings(language.name().into(), file, cx)
 5854                    .debuggers
 5855                    .first()
 5856                    .map(SharedString::from)
 5857                    .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 5858
 5859                dap_store.update(cx, |dap_store, cx| {
 5860                    for (_, task) in &resolved_tasks.templates {
 5861                        let maybe_scenario = dap_store.debug_scenario_for_build_task(
 5862                            task.original_task().clone(),
 5863                            debug_adapter.clone().into(),
 5864                            task.display_label().to_owned().into(),
 5865                            cx,
 5866                        );
 5867                        scenarios.push(maybe_scenario);
 5868                    }
 5869                });
 5870                Some(cx.background_spawn(async move {
 5871                    let scenarios = futures::future::join_all(scenarios)
 5872                        .await
 5873                        .into_iter()
 5874                        .flatten()
 5875                        .collect::<Vec<_>>();
 5876                    scenarios
 5877                }))
 5878            })
 5879            .unwrap_or_else(|| Task::ready(vec![]))
 5880        } else {
 5881            Task::ready(vec![])
 5882        }
 5883    }
 5884
 5885    fn code_actions(
 5886        &mut self,
 5887        buffer_row: u32,
 5888        window: &mut Window,
 5889        cx: &mut Context<Self>,
 5890    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 5891        let mut task = self.code_actions_task.take();
 5892        cx.spawn_in(window, async move |editor, cx| {
 5893            while let Some(prev_task) = task {
 5894                prev_task.await.log_err();
 5895                task = editor
 5896                    .update(cx, |this, _| this.code_actions_task.take())
 5897                    .ok()?;
 5898            }
 5899
 5900            editor
 5901                .update(cx, |editor, cx| {
 5902                    editor
 5903                        .available_code_actions
 5904                        .clone()
 5905                        .and_then(|(location, code_actions)| {
 5906                            let snapshot = location.buffer.read(cx).snapshot();
 5907                            let point_range = location.range.to_point(&snapshot);
 5908                            let point_range = point_range.start.row..=point_range.end.row;
 5909                            if point_range.contains(&buffer_row) {
 5910                                Some(code_actions)
 5911                            } else {
 5912                                None
 5913                            }
 5914                        })
 5915                })
 5916                .ok()
 5917                .flatten()
 5918        })
 5919    }
 5920
 5921    pub fn confirm_code_action(
 5922        &mut self,
 5923        action: &ConfirmCodeAction,
 5924        window: &mut Window,
 5925        cx: &mut Context<Self>,
 5926    ) -> Option<Task<Result<()>>> {
 5927        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5928
 5929        let actions_menu =
 5930            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5931                menu
 5932            } else {
 5933                return None;
 5934            };
 5935
 5936        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5937        let action = actions_menu.actions.get(action_ix)?;
 5938        let title = action.label();
 5939        let buffer = actions_menu.buffer;
 5940        let workspace = self.workspace()?;
 5941
 5942        match action {
 5943            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5944                workspace.update(cx, |workspace, cx| {
 5945                    workspace.schedule_resolved_task(
 5946                        task_source_kind,
 5947                        resolved_task,
 5948                        false,
 5949                        window,
 5950                        cx,
 5951                    );
 5952
 5953                    Some(Task::ready(Ok(())))
 5954                })
 5955            }
 5956            CodeActionsItem::CodeAction {
 5957                excerpt_id,
 5958                action,
 5959                provider,
 5960            } => {
 5961                let apply_code_action =
 5962                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5963                let workspace = workspace.downgrade();
 5964                Some(cx.spawn_in(window, async move |editor, cx| {
 5965                    let project_transaction = apply_code_action.await?;
 5966                    Self::open_project_transaction(
 5967                        &editor,
 5968                        workspace,
 5969                        project_transaction,
 5970                        title,
 5971                        cx,
 5972                    )
 5973                    .await
 5974                }))
 5975            }
 5976            CodeActionsItem::DebugScenario(scenario) => {
 5977                let context = actions_menu.actions.context.clone();
 5978
 5979                workspace.update(cx, |workspace, cx| {
 5980                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5981                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5982                });
 5983                Some(Task::ready(Ok(())))
 5984            }
 5985        }
 5986    }
 5987
 5988    pub async fn open_project_transaction(
 5989        this: &WeakEntity<Editor>,
 5990        workspace: WeakEntity<Workspace>,
 5991        transaction: ProjectTransaction,
 5992        title: String,
 5993        cx: &mut AsyncWindowContext,
 5994    ) -> Result<()> {
 5995        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5996        cx.update(|_, cx| {
 5997            entries.sort_unstable_by_key(|(buffer, _)| {
 5998                buffer.read(cx).file().map(|f| f.path().clone())
 5999            });
 6000        })?;
 6001
 6002        // If the project transaction's edits are all contained within this editor, then
 6003        // avoid opening a new editor to display them.
 6004
 6005        if let Some((buffer, transaction)) = entries.first() {
 6006            if entries.len() == 1 {
 6007                let excerpt = this.update(cx, |editor, cx| {
 6008                    editor
 6009                        .buffer()
 6010                        .read(cx)
 6011                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6012                })?;
 6013                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6014                    if excerpted_buffer == *buffer {
 6015                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6016                            let excerpt_range = excerpt_range.to_offset(buffer);
 6017                            buffer
 6018                                .edited_ranges_for_transaction::<usize>(transaction)
 6019                                .all(|range| {
 6020                                    excerpt_range.start <= range.start
 6021                                        && excerpt_range.end >= range.end
 6022                                })
 6023                        })?;
 6024
 6025                        if all_edits_within_excerpt {
 6026                            return Ok(());
 6027                        }
 6028                    }
 6029                }
 6030            }
 6031        } else {
 6032            return Ok(());
 6033        }
 6034
 6035        let mut ranges_to_highlight = Vec::new();
 6036        let excerpt_buffer = cx.new(|cx| {
 6037            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6038            for (buffer_handle, transaction) in &entries {
 6039                let edited_ranges = buffer_handle
 6040                    .read(cx)
 6041                    .edited_ranges_for_transaction::<Point>(transaction)
 6042                    .collect::<Vec<_>>();
 6043                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6044                    PathKey::for_buffer(buffer_handle, cx),
 6045                    buffer_handle.clone(),
 6046                    edited_ranges,
 6047                    DEFAULT_MULTIBUFFER_CONTEXT,
 6048                    cx,
 6049                );
 6050
 6051                ranges_to_highlight.extend(ranges);
 6052            }
 6053            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6054            multibuffer
 6055        })?;
 6056
 6057        workspace.update_in(cx, |workspace, window, cx| {
 6058            let project = workspace.project().clone();
 6059            let editor =
 6060                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6061            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6062            editor.update(cx, |editor, cx| {
 6063                editor.highlight_background::<Self>(
 6064                    &ranges_to_highlight,
 6065                    |theme| theme.colors().editor_highlighted_line_background,
 6066                    cx,
 6067                );
 6068            });
 6069        })?;
 6070
 6071        Ok(())
 6072    }
 6073
 6074    pub fn clear_code_action_providers(&mut self) {
 6075        self.code_action_providers.clear();
 6076        self.available_code_actions.take();
 6077    }
 6078
 6079    pub fn add_code_action_provider(
 6080        &mut self,
 6081        provider: Rc<dyn CodeActionProvider>,
 6082        window: &mut Window,
 6083        cx: &mut Context<Self>,
 6084    ) {
 6085        if self
 6086            .code_action_providers
 6087            .iter()
 6088            .any(|existing_provider| existing_provider.id() == provider.id())
 6089        {
 6090            return;
 6091        }
 6092
 6093        self.code_action_providers.push(provider);
 6094        self.refresh_code_actions(window, cx);
 6095    }
 6096
 6097    pub fn remove_code_action_provider(
 6098        &mut self,
 6099        id: Arc<str>,
 6100        window: &mut Window,
 6101        cx: &mut Context<Self>,
 6102    ) {
 6103        self.code_action_providers
 6104            .retain(|provider| provider.id() != id);
 6105        self.refresh_code_actions(window, cx);
 6106    }
 6107
 6108    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6109        !self.code_action_providers.is_empty()
 6110            && EditorSettings::get_global(cx).toolbar.code_actions
 6111    }
 6112
 6113    pub fn has_available_code_actions(&self) -> bool {
 6114        self.available_code_actions
 6115            .as_ref()
 6116            .is_some_and(|(_, actions)| !actions.is_empty())
 6117    }
 6118
 6119    fn render_inline_code_actions(
 6120        &self,
 6121        icon_size: ui::IconSize,
 6122        display_row: DisplayRow,
 6123        is_active: bool,
 6124        cx: &mut Context<Self>,
 6125    ) -> AnyElement {
 6126        let show_tooltip = !self.context_menu_visible();
 6127        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6128            .icon_size(icon_size)
 6129            .shape(ui::IconButtonShape::Square)
 6130            .style(ButtonStyle::Transparent)
 6131            .icon_color(ui::Color::Hidden)
 6132            .toggle_state(is_active)
 6133            .when(show_tooltip, |this| {
 6134                this.tooltip({
 6135                    let focus_handle = self.focus_handle.clone();
 6136                    move |window, cx| {
 6137                        Tooltip::for_action_in(
 6138                            "Toggle Code Actions",
 6139                            &ToggleCodeActions {
 6140                                deployed_from: None,
 6141                                quick_launch: false,
 6142                            },
 6143                            &focus_handle,
 6144                            window,
 6145                            cx,
 6146                        )
 6147                    }
 6148                })
 6149            })
 6150            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6151                window.focus(&editor.focus_handle(cx));
 6152                editor.toggle_code_actions(
 6153                    &crate::actions::ToggleCodeActions {
 6154                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6155                            display_row,
 6156                        )),
 6157                        quick_launch: false,
 6158                    },
 6159                    window,
 6160                    cx,
 6161                );
 6162            }))
 6163            .into_any_element()
 6164    }
 6165
 6166    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6167        &self.context_menu
 6168    }
 6169
 6170    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6171        let newest_selection = self.selections.newest_anchor().clone();
 6172        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6173        let buffer = self.buffer.read(cx);
 6174        if newest_selection.head().diff_base_anchor.is_some() {
 6175            return None;
 6176        }
 6177        let (start_buffer, start) =
 6178            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6179        let (end_buffer, end) =
 6180            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6181        if start_buffer != end_buffer {
 6182            return None;
 6183        }
 6184
 6185        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6186            cx.background_executor()
 6187                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6188                .await;
 6189
 6190            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6191                let providers = this.code_action_providers.clone();
 6192                let tasks = this
 6193                    .code_action_providers
 6194                    .iter()
 6195                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6196                    .collect::<Vec<_>>();
 6197                (providers, tasks)
 6198            })?;
 6199
 6200            let mut actions = Vec::new();
 6201            for (provider, provider_actions) in
 6202                providers.into_iter().zip(future::join_all(tasks).await)
 6203            {
 6204                if let Some(provider_actions) = provider_actions.log_err() {
 6205                    actions.extend(provider_actions.into_iter().map(|action| {
 6206                        AvailableCodeAction {
 6207                            excerpt_id: newest_selection.start.excerpt_id,
 6208                            action,
 6209                            provider: provider.clone(),
 6210                        }
 6211                    }));
 6212                }
 6213            }
 6214
 6215            this.update(cx, |this, cx| {
 6216                this.available_code_actions = if actions.is_empty() {
 6217                    None
 6218                } else {
 6219                    Some((
 6220                        Location {
 6221                            buffer: start_buffer,
 6222                            range: start..end,
 6223                        },
 6224                        actions.into(),
 6225                    ))
 6226                };
 6227                cx.notify();
 6228            })
 6229        }));
 6230        None
 6231    }
 6232
 6233    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6234        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6235            self.show_git_blame_inline = false;
 6236
 6237            self.show_git_blame_inline_delay_task =
 6238                Some(cx.spawn_in(window, async move |this, cx| {
 6239                    cx.background_executor().timer(delay).await;
 6240
 6241                    this.update(cx, |this, cx| {
 6242                        this.show_git_blame_inline = true;
 6243                        cx.notify();
 6244                    })
 6245                    .log_err();
 6246                }));
 6247        }
 6248    }
 6249
 6250    fn show_blame_popover(
 6251        &mut self,
 6252        blame_entry: &BlameEntry,
 6253        position: gpui::Point<Pixels>,
 6254        cx: &mut Context<Self>,
 6255    ) {
 6256        if let Some(state) = &mut self.inline_blame_popover {
 6257            state.hide_task.take();
 6258            cx.notify();
 6259        } else {
 6260            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6261            let show_task = cx.spawn(async move |editor, cx| {
 6262                cx.background_executor()
 6263                    .timer(std::time::Duration::from_millis(delay))
 6264                    .await;
 6265                editor
 6266                    .update(cx, |editor, cx| {
 6267                        if let Some(state) = &mut editor.inline_blame_popover {
 6268                            state.show_task = None;
 6269                            cx.notify();
 6270                        }
 6271                    })
 6272                    .ok();
 6273            });
 6274            let Some(blame) = self.blame.as_ref() else {
 6275                return;
 6276            };
 6277            let blame = blame.read(cx);
 6278            let details = blame.details_for_entry(&blame_entry);
 6279            let markdown = cx.new(|cx| {
 6280                Markdown::new(
 6281                    details
 6282                        .as_ref()
 6283                        .map(|message| message.message.clone())
 6284                        .unwrap_or_default(),
 6285                    None,
 6286                    None,
 6287                    cx,
 6288                )
 6289            });
 6290            self.inline_blame_popover = Some(InlineBlamePopover {
 6291                position,
 6292                show_task: Some(show_task),
 6293                hide_task: None,
 6294                popover_bounds: None,
 6295                popover_state: InlineBlamePopoverState {
 6296                    scroll_handle: ScrollHandle::new(),
 6297                    commit_message: details,
 6298                    markdown,
 6299                },
 6300            });
 6301        }
 6302    }
 6303
 6304    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6305        if let Some(state) = &mut self.inline_blame_popover {
 6306            if state.show_task.is_some() {
 6307                self.inline_blame_popover.take();
 6308                cx.notify();
 6309            } else {
 6310                let hide_task = cx.spawn(async move |editor, cx| {
 6311                    cx.background_executor()
 6312                        .timer(std::time::Duration::from_millis(100))
 6313                        .await;
 6314                    editor
 6315                        .update(cx, |editor, cx| {
 6316                            editor.inline_blame_popover.take();
 6317                            cx.notify();
 6318                        })
 6319                        .ok();
 6320                });
 6321                state.hide_task = Some(hide_task);
 6322            }
 6323        }
 6324    }
 6325
 6326    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6327        if self.pending_rename.is_some() {
 6328            return None;
 6329        }
 6330
 6331        let provider = self.semantics_provider.clone()?;
 6332        let buffer = self.buffer.read(cx);
 6333        let newest_selection = self.selections.newest_anchor().clone();
 6334        let cursor_position = newest_selection.head();
 6335        let (cursor_buffer, cursor_buffer_position) =
 6336            buffer.text_anchor_for_position(cursor_position, cx)?;
 6337        let (tail_buffer, tail_buffer_position) =
 6338            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6339        if cursor_buffer != tail_buffer {
 6340            return None;
 6341        }
 6342
 6343        let snapshot = cursor_buffer.read(cx).snapshot();
 6344        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6345        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6346        if start_word_range != end_word_range {
 6347            self.document_highlights_task.take();
 6348            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6349            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6350            return None;
 6351        }
 6352
 6353        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6354        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6355            cx.background_executor()
 6356                .timer(Duration::from_millis(debounce))
 6357                .await;
 6358
 6359            let highlights = if let Some(highlights) = cx
 6360                .update(|cx| {
 6361                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6362                })
 6363                .ok()
 6364                .flatten()
 6365            {
 6366                highlights.await.log_err()
 6367            } else {
 6368                None
 6369            };
 6370
 6371            if let Some(highlights) = highlights {
 6372                this.update(cx, |this, cx| {
 6373                    if this.pending_rename.is_some() {
 6374                        return;
 6375                    }
 6376
 6377                    let buffer_id = cursor_position.buffer_id;
 6378                    let buffer = this.buffer.read(cx);
 6379                    if !buffer
 6380                        .text_anchor_for_position(cursor_position, cx)
 6381                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6382                    {
 6383                        return;
 6384                    }
 6385
 6386                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6387                    let mut write_ranges = Vec::new();
 6388                    let mut read_ranges = Vec::new();
 6389                    for highlight in highlights {
 6390                        for (excerpt_id, excerpt_range) in
 6391                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6392                        {
 6393                            let start = highlight
 6394                                .range
 6395                                .start
 6396                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6397                            let end = highlight
 6398                                .range
 6399                                .end
 6400                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6401                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6402                                continue;
 6403                            }
 6404
 6405                            let range = Anchor {
 6406                                buffer_id,
 6407                                excerpt_id,
 6408                                text_anchor: start,
 6409                                diff_base_anchor: None,
 6410                            }..Anchor {
 6411                                buffer_id,
 6412                                excerpt_id,
 6413                                text_anchor: end,
 6414                                diff_base_anchor: None,
 6415                            };
 6416                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6417                                write_ranges.push(range);
 6418                            } else {
 6419                                read_ranges.push(range);
 6420                            }
 6421                        }
 6422                    }
 6423
 6424                    this.highlight_background::<DocumentHighlightRead>(
 6425                        &read_ranges,
 6426                        |theme| theme.colors().editor_document_highlight_read_background,
 6427                        cx,
 6428                    );
 6429                    this.highlight_background::<DocumentHighlightWrite>(
 6430                        &write_ranges,
 6431                        |theme| theme.colors().editor_document_highlight_write_background,
 6432                        cx,
 6433                    );
 6434                    cx.notify();
 6435                })
 6436                .log_err();
 6437            }
 6438        }));
 6439        None
 6440    }
 6441
 6442    fn prepare_highlight_query_from_selection(
 6443        &mut self,
 6444        cx: &mut Context<Editor>,
 6445    ) -> Option<(String, Range<Anchor>)> {
 6446        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6447            return None;
 6448        }
 6449        if !EditorSettings::get_global(cx).selection_highlight {
 6450            return None;
 6451        }
 6452        if self.selections.count() != 1 || self.selections.line_mode {
 6453            return None;
 6454        }
 6455        let selection = self.selections.newest::<Point>(cx);
 6456        if selection.is_empty() || selection.start.row != selection.end.row {
 6457            return None;
 6458        }
 6459        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6460        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6461        let query = multi_buffer_snapshot
 6462            .text_for_range(selection_anchor_range.clone())
 6463            .collect::<String>();
 6464        if query.trim().is_empty() {
 6465            return None;
 6466        }
 6467        Some((query, selection_anchor_range))
 6468    }
 6469
 6470    fn update_selection_occurrence_highlights(
 6471        &mut self,
 6472        query_text: String,
 6473        query_range: Range<Anchor>,
 6474        multi_buffer_range_to_query: Range<Point>,
 6475        use_debounce: bool,
 6476        window: &mut Window,
 6477        cx: &mut Context<Editor>,
 6478    ) -> Task<()> {
 6479        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6480        cx.spawn_in(window, async move |editor, cx| {
 6481            if use_debounce {
 6482                cx.background_executor()
 6483                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6484                    .await;
 6485            }
 6486            let match_task = cx.background_spawn(async move {
 6487                let buffer_ranges = multi_buffer_snapshot
 6488                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6489                    .into_iter()
 6490                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6491                let mut match_ranges = Vec::new();
 6492                let Ok(regex) = project::search::SearchQuery::text(
 6493                    query_text.clone(),
 6494                    false,
 6495                    false,
 6496                    false,
 6497                    Default::default(),
 6498                    Default::default(),
 6499                    false,
 6500                    None,
 6501                ) else {
 6502                    return Vec::default();
 6503                };
 6504                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6505                    match_ranges.extend(
 6506                        regex
 6507                            .search(&buffer_snapshot, Some(search_range.clone()))
 6508                            .await
 6509                            .into_iter()
 6510                            .filter_map(|match_range| {
 6511                                let match_start = buffer_snapshot
 6512                                    .anchor_after(search_range.start + match_range.start);
 6513                                let match_end = buffer_snapshot
 6514                                    .anchor_before(search_range.start + match_range.end);
 6515                                let match_anchor_range = Anchor::range_in_buffer(
 6516                                    excerpt_id,
 6517                                    buffer_snapshot.remote_id(),
 6518                                    match_start..match_end,
 6519                                );
 6520                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6521                            }),
 6522                    );
 6523                }
 6524                match_ranges
 6525            });
 6526            let match_ranges = match_task.await;
 6527            editor
 6528                .update_in(cx, |editor, _, cx| {
 6529                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6530                    if !match_ranges.is_empty() {
 6531                        editor.highlight_background::<SelectedTextHighlight>(
 6532                            &match_ranges,
 6533                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6534                            cx,
 6535                        )
 6536                    }
 6537                })
 6538                .log_err();
 6539        })
 6540    }
 6541
 6542    fn refresh_selected_text_highlights(
 6543        &mut self,
 6544        on_buffer_edit: bool,
 6545        window: &mut Window,
 6546        cx: &mut Context<Editor>,
 6547    ) {
 6548        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6549        else {
 6550            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6551            self.quick_selection_highlight_task.take();
 6552            self.debounced_selection_highlight_task.take();
 6553            return;
 6554        };
 6555        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6556        if on_buffer_edit
 6557            || self
 6558                .quick_selection_highlight_task
 6559                .as_ref()
 6560                .map_or(true, |(prev_anchor_range, _)| {
 6561                    prev_anchor_range != &query_range
 6562                })
 6563        {
 6564            let multi_buffer_visible_start = self
 6565                .scroll_manager
 6566                .anchor()
 6567                .anchor
 6568                .to_point(&multi_buffer_snapshot);
 6569            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6570                multi_buffer_visible_start
 6571                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6572                Bias::Left,
 6573            );
 6574            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6575            self.quick_selection_highlight_task = Some((
 6576                query_range.clone(),
 6577                self.update_selection_occurrence_highlights(
 6578                    query_text.clone(),
 6579                    query_range.clone(),
 6580                    multi_buffer_visible_range,
 6581                    false,
 6582                    window,
 6583                    cx,
 6584                ),
 6585            ));
 6586        }
 6587        if on_buffer_edit
 6588            || self
 6589                .debounced_selection_highlight_task
 6590                .as_ref()
 6591                .map_or(true, |(prev_anchor_range, _)| {
 6592                    prev_anchor_range != &query_range
 6593                })
 6594        {
 6595            let multi_buffer_start = multi_buffer_snapshot
 6596                .anchor_before(0)
 6597                .to_point(&multi_buffer_snapshot);
 6598            let multi_buffer_end = multi_buffer_snapshot
 6599                .anchor_after(multi_buffer_snapshot.len())
 6600                .to_point(&multi_buffer_snapshot);
 6601            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6602            self.debounced_selection_highlight_task = Some((
 6603                query_range.clone(),
 6604                self.update_selection_occurrence_highlights(
 6605                    query_text,
 6606                    query_range,
 6607                    multi_buffer_full_range,
 6608                    true,
 6609                    window,
 6610                    cx,
 6611                ),
 6612            ));
 6613        }
 6614    }
 6615
 6616    pub fn refresh_inline_completion(
 6617        &mut self,
 6618        debounce: bool,
 6619        user_requested: bool,
 6620        window: &mut Window,
 6621        cx: &mut Context<Self>,
 6622    ) -> Option<()> {
 6623        let provider = self.edit_prediction_provider()?;
 6624        let cursor = self.selections.newest_anchor().head();
 6625        let (buffer, cursor_buffer_position) =
 6626            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6627
 6628        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6629            self.discard_inline_completion(false, cx);
 6630            return None;
 6631        }
 6632
 6633        if !user_requested
 6634            && (!self.should_show_edit_predictions()
 6635                || !self.is_focused(window)
 6636                || buffer.read(cx).is_empty())
 6637        {
 6638            self.discard_inline_completion(false, cx);
 6639            return None;
 6640        }
 6641
 6642        self.update_visible_inline_completion(window, cx);
 6643        provider.refresh(
 6644            self.project.clone(),
 6645            buffer,
 6646            cursor_buffer_position,
 6647            debounce,
 6648            cx,
 6649        );
 6650        Some(())
 6651    }
 6652
 6653    fn show_edit_predictions_in_menu(&self) -> bool {
 6654        match self.edit_prediction_settings {
 6655            EditPredictionSettings::Disabled => false,
 6656            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6657        }
 6658    }
 6659
 6660    pub fn edit_predictions_enabled(&self) -> bool {
 6661        match self.edit_prediction_settings {
 6662            EditPredictionSettings::Disabled => false,
 6663            EditPredictionSettings::Enabled { .. } => true,
 6664        }
 6665    }
 6666
 6667    fn edit_prediction_requires_modifier(&self) -> bool {
 6668        match self.edit_prediction_settings {
 6669            EditPredictionSettings::Disabled => false,
 6670            EditPredictionSettings::Enabled {
 6671                preview_requires_modifier,
 6672                ..
 6673            } => preview_requires_modifier,
 6674        }
 6675    }
 6676
 6677    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6678        if self.edit_prediction_provider.is_none() {
 6679            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6680        } else {
 6681            let selection = self.selections.newest_anchor();
 6682            let cursor = selection.head();
 6683
 6684            if let Some((buffer, cursor_buffer_position)) =
 6685                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6686            {
 6687                self.edit_prediction_settings =
 6688                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6689            }
 6690        }
 6691    }
 6692
 6693    fn edit_prediction_settings_at_position(
 6694        &self,
 6695        buffer: &Entity<Buffer>,
 6696        buffer_position: language::Anchor,
 6697        cx: &App,
 6698    ) -> EditPredictionSettings {
 6699        if !self.mode.is_full()
 6700            || !self.show_inline_completions_override.unwrap_or(true)
 6701            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6702        {
 6703            return EditPredictionSettings::Disabled;
 6704        }
 6705
 6706        let buffer = buffer.read(cx);
 6707
 6708        let file = buffer.file();
 6709
 6710        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6711            return EditPredictionSettings::Disabled;
 6712        };
 6713
 6714        let by_provider = matches!(
 6715            self.menu_inline_completions_policy,
 6716            MenuInlineCompletionsPolicy::ByProvider
 6717        );
 6718
 6719        let show_in_menu = by_provider
 6720            && self
 6721                .edit_prediction_provider
 6722                .as_ref()
 6723                .map_or(false, |provider| {
 6724                    provider.provider.show_completions_in_menu()
 6725                });
 6726
 6727        let preview_requires_modifier =
 6728            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6729
 6730        EditPredictionSettings::Enabled {
 6731            show_in_menu,
 6732            preview_requires_modifier,
 6733        }
 6734    }
 6735
 6736    fn should_show_edit_predictions(&self) -> bool {
 6737        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6738    }
 6739
 6740    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6741        matches!(
 6742            self.edit_prediction_preview,
 6743            EditPredictionPreview::Active { .. }
 6744        )
 6745    }
 6746
 6747    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6748        let cursor = self.selections.newest_anchor().head();
 6749        if let Some((buffer, cursor_position)) =
 6750            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6751        {
 6752            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6753        } else {
 6754            false
 6755        }
 6756    }
 6757
 6758    pub fn supports_minimap(&self, cx: &App) -> bool {
 6759        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6760    }
 6761
 6762    fn edit_predictions_enabled_in_buffer(
 6763        &self,
 6764        buffer: &Entity<Buffer>,
 6765        buffer_position: language::Anchor,
 6766        cx: &App,
 6767    ) -> bool {
 6768        maybe!({
 6769            if self.read_only(cx) {
 6770                return Some(false);
 6771            }
 6772            let provider = self.edit_prediction_provider()?;
 6773            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6774                return Some(false);
 6775            }
 6776            let buffer = buffer.read(cx);
 6777            let Some(file) = buffer.file() else {
 6778                return Some(true);
 6779            };
 6780            let settings = all_language_settings(Some(file), cx);
 6781            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6782        })
 6783        .unwrap_or(false)
 6784    }
 6785
 6786    fn cycle_inline_completion(
 6787        &mut self,
 6788        direction: Direction,
 6789        window: &mut Window,
 6790        cx: &mut Context<Self>,
 6791    ) -> Option<()> {
 6792        let provider = self.edit_prediction_provider()?;
 6793        let cursor = self.selections.newest_anchor().head();
 6794        let (buffer, cursor_buffer_position) =
 6795            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6796        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6797            return None;
 6798        }
 6799
 6800        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6801        self.update_visible_inline_completion(window, cx);
 6802
 6803        Some(())
 6804    }
 6805
 6806    pub fn show_inline_completion(
 6807        &mut self,
 6808        _: &ShowEditPrediction,
 6809        window: &mut Window,
 6810        cx: &mut Context<Self>,
 6811    ) {
 6812        if !self.has_active_inline_completion() {
 6813            self.refresh_inline_completion(false, true, window, cx);
 6814            return;
 6815        }
 6816
 6817        self.update_visible_inline_completion(window, cx);
 6818    }
 6819
 6820    pub fn display_cursor_names(
 6821        &mut self,
 6822        _: &DisplayCursorNames,
 6823        window: &mut Window,
 6824        cx: &mut Context<Self>,
 6825    ) {
 6826        self.show_cursor_names(window, cx);
 6827    }
 6828
 6829    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6830        self.show_cursor_names = true;
 6831        cx.notify();
 6832        cx.spawn_in(window, async move |this, cx| {
 6833            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6834            this.update(cx, |this, cx| {
 6835                this.show_cursor_names = false;
 6836                cx.notify()
 6837            })
 6838            .ok()
 6839        })
 6840        .detach();
 6841    }
 6842
 6843    pub fn next_edit_prediction(
 6844        &mut self,
 6845        _: &NextEditPrediction,
 6846        window: &mut Window,
 6847        cx: &mut Context<Self>,
 6848    ) {
 6849        if self.has_active_inline_completion() {
 6850            self.cycle_inline_completion(Direction::Next, window, cx);
 6851        } else {
 6852            let is_copilot_disabled = self
 6853                .refresh_inline_completion(false, true, window, cx)
 6854                .is_none();
 6855            if is_copilot_disabled {
 6856                cx.propagate();
 6857            }
 6858        }
 6859    }
 6860
 6861    pub fn previous_edit_prediction(
 6862        &mut self,
 6863        _: &PreviousEditPrediction,
 6864        window: &mut Window,
 6865        cx: &mut Context<Self>,
 6866    ) {
 6867        if self.has_active_inline_completion() {
 6868            self.cycle_inline_completion(Direction::Prev, window, cx);
 6869        } else {
 6870            let is_copilot_disabled = self
 6871                .refresh_inline_completion(false, true, window, cx)
 6872                .is_none();
 6873            if is_copilot_disabled {
 6874                cx.propagate();
 6875            }
 6876        }
 6877    }
 6878
 6879    pub fn accept_edit_prediction(
 6880        &mut self,
 6881        _: &AcceptEditPrediction,
 6882        window: &mut Window,
 6883        cx: &mut Context<Self>,
 6884    ) {
 6885        if self.show_edit_predictions_in_menu() {
 6886            self.hide_context_menu(window, cx);
 6887        }
 6888
 6889        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6890            return;
 6891        };
 6892
 6893        self.report_inline_completion_event(
 6894            active_inline_completion.completion_id.clone(),
 6895            true,
 6896            cx,
 6897        );
 6898
 6899        match &active_inline_completion.completion {
 6900            InlineCompletion::Move { target, .. } => {
 6901                let target = *target;
 6902
 6903                if let Some(position_map) = &self.last_position_map {
 6904                    if position_map
 6905                        .visible_row_range
 6906                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6907                        || !self.edit_prediction_requires_modifier()
 6908                    {
 6909                        self.unfold_ranges(&[target..target], true, false, cx);
 6910                        // Note that this is also done in vim's handler of the Tab action.
 6911                        self.change_selections(
 6912                            Some(Autoscroll::newest()),
 6913                            window,
 6914                            cx,
 6915                            |selections| {
 6916                                selections.select_anchor_ranges([target..target]);
 6917                            },
 6918                        );
 6919                        self.clear_row_highlights::<EditPredictionPreview>();
 6920
 6921                        self.edit_prediction_preview
 6922                            .set_previous_scroll_position(None);
 6923                    } else {
 6924                        self.edit_prediction_preview
 6925                            .set_previous_scroll_position(Some(
 6926                                position_map.snapshot.scroll_anchor,
 6927                            ));
 6928
 6929                        self.highlight_rows::<EditPredictionPreview>(
 6930                            target..target,
 6931                            cx.theme().colors().editor_highlighted_line_background,
 6932                            RowHighlightOptions {
 6933                                autoscroll: true,
 6934                                ..Default::default()
 6935                            },
 6936                            cx,
 6937                        );
 6938                        self.request_autoscroll(Autoscroll::fit(), cx);
 6939                    }
 6940                }
 6941            }
 6942            InlineCompletion::Edit { edits, .. } => {
 6943                if let Some(provider) = self.edit_prediction_provider() {
 6944                    provider.accept(cx);
 6945                }
 6946
 6947                // Store the transaction ID and selections before applying the edit
 6948                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6949
 6950                let snapshot = self.buffer.read(cx).snapshot(cx);
 6951                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6952
 6953                self.buffer.update(cx, |buffer, cx| {
 6954                    buffer.edit(edits.iter().cloned(), None, cx)
 6955                });
 6956
 6957                self.change_selections(None, window, cx, |s| {
 6958                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6959                });
 6960
 6961                let selections = self.selections.disjoint_anchors();
 6962                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6963                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6964                    if has_new_transaction {
 6965                        self.selection_history
 6966                            .insert_transaction(transaction_id_now, selections);
 6967                    }
 6968                }
 6969
 6970                self.update_visible_inline_completion(window, cx);
 6971                if self.active_inline_completion.is_none() {
 6972                    self.refresh_inline_completion(true, true, window, cx);
 6973                }
 6974
 6975                cx.notify();
 6976            }
 6977        }
 6978
 6979        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6980    }
 6981
 6982    pub fn accept_partial_inline_completion(
 6983        &mut self,
 6984        _: &AcceptPartialEditPrediction,
 6985        window: &mut Window,
 6986        cx: &mut Context<Self>,
 6987    ) {
 6988        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6989            return;
 6990        };
 6991        if self.selections.count() != 1 {
 6992            return;
 6993        }
 6994
 6995        self.report_inline_completion_event(
 6996            active_inline_completion.completion_id.clone(),
 6997            true,
 6998            cx,
 6999        );
 7000
 7001        match &active_inline_completion.completion {
 7002            InlineCompletion::Move { target, .. } => {
 7003                let target = *target;
 7004                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7005                    selections.select_anchor_ranges([target..target]);
 7006                });
 7007            }
 7008            InlineCompletion::Edit { edits, .. } => {
 7009                // Find an insertion that starts at the cursor position.
 7010                let snapshot = self.buffer.read(cx).snapshot(cx);
 7011                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7012                let insertion = edits.iter().find_map(|(range, text)| {
 7013                    let range = range.to_offset(&snapshot);
 7014                    if range.is_empty() && range.start == cursor_offset {
 7015                        Some(text)
 7016                    } else {
 7017                        None
 7018                    }
 7019                });
 7020
 7021                if let Some(text) = insertion {
 7022                    let mut partial_completion = text
 7023                        .chars()
 7024                        .by_ref()
 7025                        .take_while(|c| c.is_alphabetic())
 7026                        .collect::<String>();
 7027                    if partial_completion.is_empty() {
 7028                        partial_completion = text
 7029                            .chars()
 7030                            .by_ref()
 7031                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7032                            .collect::<String>();
 7033                    }
 7034
 7035                    cx.emit(EditorEvent::InputHandled {
 7036                        utf16_range_to_replace: None,
 7037                        text: partial_completion.clone().into(),
 7038                    });
 7039
 7040                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7041
 7042                    self.refresh_inline_completion(true, true, window, cx);
 7043                    cx.notify();
 7044                } else {
 7045                    self.accept_edit_prediction(&Default::default(), window, cx);
 7046                }
 7047            }
 7048        }
 7049    }
 7050
 7051    fn discard_inline_completion(
 7052        &mut self,
 7053        should_report_inline_completion_event: bool,
 7054        cx: &mut Context<Self>,
 7055    ) -> bool {
 7056        if should_report_inline_completion_event {
 7057            let completion_id = self
 7058                .active_inline_completion
 7059                .as_ref()
 7060                .and_then(|active_completion| active_completion.completion_id.clone());
 7061
 7062            self.report_inline_completion_event(completion_id, false, cx);
 7063        }
 7064
 7065        if let Some(provider) = self.edit_prediction_provider() {
 7066            provider.discard(cx);
 7067        }
 7068
 7069        self.take_active_inline_completion(cx)
 7070    }
 7071
 7072    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7073        let Some(provider) = self.edit_prediction_provider() else {
 7074            return;
 7075        };
 7076
 7077        let Some((_, buffer, _)) = self
 7078            .buffer
 7079            .read(cx)
 7080            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7081        else {
 7082            return;
 7083        };
 7084
 7085        let extension = buffer
 7086            .read(cx)
 7087            .file()
 7088            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7089
 7090        let event_type = match accepted {
 7091            true => "Edit Prediction Accepted",
 7092            false => "Edit Prediction Discarded",
 7093        };
 7094        telemetry::event!(
 7095            event_type,
 7096            provider = provider.name(),
 7097            prediction_id = id,
 7098            suggestion_accepted = accepted,
 7099            file_extension = extension,
 7100        );
 7101    }
 7102
 7103    pub fn has_active_inline_completion(&self) -> bool {
 7104        self.active_inline_completion.is_some()
 7105    }
 7106
 7107    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7108        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7109            return false;
 7110        };
 7111
 7112        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7113        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7114        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7115        true
 7116    }
 7117
 7118    /// Returns true when we're displaying the edit prediction popover below the cursor
 7119    /// like we are not previewing and the LSP autocomplete menu is visible
 7120    /// or we are in `when_holding_modifier` mode.
 7121    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7122        if self.edit_prediction_preview_is_active()
 7123            || !self.show_edit_predictions_in_menu()
 7124            || !self.edit_predictions_enabled()
 7125        {
 7126            return false;
 7127        }
 7128
 7129        if self.has_visible_completions_menu() {
 7130            return true;
 7131        }
 7132
 7133        has_completion && self.edit_prediction_requires_modifier()
 7134    }
 7135
 7136    fn handle_modifiers_changed(
 7137        &mut self,
 7138        modifiers: Modifiers,
 7139        position_map: &PositionMap,
 7140        window: &mut Window,
 7141        cx: &mut Context<Self>,
 7142    ) {
 7143        if self.show_edit_predictions_in_menu() {
 7144            self.update_edit_prediction_preview(&modifiers, window, cx);
 7145        }
 7146
 7147        self.update_selection_mode(&modifiers, position_map, window, cx);
 7148
 7149        let mouse_position = window.mouse_position();
 7150        if !position_map.text_hitbox.is_hovered(window) {
 7151            return;
 7152        }
 7153
 7154        self.update_hovered_link(
 7155            position_map.point_for_position(mouse_position),
 7156            &position_map.snapshot,
 7157            modifiers,
 7158            window,
 7159            cx,
 7160        )
 7161    }
 7162
 7163    fn multi_cursor_modifier(
 7164        cursor_event: bool,
 7165        modifiers: &Modifiers,
 7166        cx: &mut Context<Self>,
 7167    ) -> bool {
 7168        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7169        if cursor_event {
 7170            match multi_cursor_setting {
 7171                MultiCursorModifier::Alt => modifiers.alt,
 7172                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7173            }
 7174        } else {
 7175            match multi_cursor_setting {
 7176                MultiCursorModifier::Alt => modifiers.secondary(),
 7177                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7178            }
 7179        }
 7180    }
 7181
 7182    fn columnar_selection_modifiers(multi_cursor_modifier: bool, modifiers: &Modifiers) -> bool {
 7183        modifiers.shift && multi_cursor_modifier && modifiers.number_of_modifiers() == 2
 7184    }
 7185
 7186    fn update_selection_mode(
 7187        &mut self,
 7188        modifiers: &Modifiers,
 7189        position_map: &PositionMap,
 7190        window: &mut Window,
 7191        cx: &mut Context<Self>,
 7192    ) {
 7193        let multi_cursor_modifier = Self::multi_cursor_modifier(true, modifiers, cx);
 7194        if !Self::columnar_selection_modifiers(multi_cursor_modifier, modifiers)
 7195            || self.selections.pending.is_none()
 7196        {
 7197            return;
 7198        }
 7199
 7200        let mouse_position = window.mouse_position();
 7201        let point_for_position = position_map.point_for_position(mouse_position);
 7202        let position = point_for_position.previous_valid;
 7203
 7204        self.select(
 7205            SelectPhase::BeginColumnar {
 7206                position,
 7207                reset: false,
 7208                goal_column: point_for_position.exact_unclipped.column(),
 7209            },
 7210            window,
 7211            cx,
 7212        );
 7213    }
 7214
 7215    fn update_edit_prediction_preview(
 7216        &mut self,
 7217        modifiers: &Modifiers,
 7218        window: &mut Window,
 7219        cx: &mut Context<Self>,
 7220    ) {
 7221        let mut modifiers_held = false;
 7222        if let Some(accept_keystroke) = self
 7223            .accept_edit_prediction_keybind(false, window, cx)
 7224            .keystroke()
 7225        {
 7226            modifiers_held = modifiers_held
 7227                || (&accept_keystroke.modifiers == modifiers
 7228                    && accept_keystroke.modifiers.modified());
 7229        };
 7230        if let Some(accept_partial_keystroke) = self
 7231            .accept_edit_prediction_keybind(true, window, cx)
 7232            .keystroke()
 7233        {
 7234            modifiers_held = modifiers_held
 7235                || (&accept_partial_keystroke.modifiers == modifiers
 7236                    && accept_partial_keystroke.modifiers.modified());
 7237        }
 7238
 7239        if modifiers_held {
 7240            if matches!(
 7241                self.edit_prediction_preview,
 7242                EditPredictionPreview::Inactive { .. }
 7243            ) {
 7244                self.edit_prediction_preview = EditPredictionPreview::Active {
 7245                    previous_scroll_position: None,
 7246                    since: Instant::now(),
 7247                };
 7248
 7249                self.update_visible_inline_completion(window, cx);
 7250                cx.notify();
 7251            }
 7252        } else if let EditPredictionPreview::Active {
 7253            previous_scroll_position,
 7254            since,
 7255        } = self.edit_prediction_preview
 7256        {
 7257            if let (Some(previous_scroll_position), Some(position_map)) =
 7258                (previous_scroll_position, self.last_position_map.as_ref())
 7259            {
 7260                self.set_scroll_position(
 7261                    previous_scroll_position
 7262                        .scroll_position(&position_map.snapshot.display_snapshot),
 7263                    window,
 7264                    cx,
 7265                );
 7266            }
 7267
 7268            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7269                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7270            };
 7271            self.clear_row_highlights::<EditPredictionPreview>();
 7272            self.update_visible_inline_completion(window, cx);
 7273            cx.notify();
 7274        }
 7275    }
 7276
 7277    fn update_visible_inline_completion(
 7278        &mut self,
 7279        _window: &mut Window,
 7280        cx: &mut Context<Self>,
 7281    ) -> Option<()> {
 7282        let selection = self.selections.newest_anchor();
 7283        let cursor = selection.head();
 7284        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7285        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7286        let excerpt_id = cursor.excerpt_id;
 7287
 7288        let show_in_menu = self.show_edit_predictions_in_menu();
 7289        let completions_menu_has_precedence = !show_in_menu
 7290            && (self.context_menu.borrow().is_some()
 7291                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7292
 7293        if completions_menu_has_precedence
 7294            || !offset_selection.is_empty()
 7295            || self
 7296                .active_inline_completion
 7297                .as_ref()
 7298                .map_or(false, |completion| {
 7299                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7300                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7301                    !invalidation_range.contains(&offset_selection.head())
 7302                })
 7303        {
 7304            self.discard_inline_completion(false, cx);
 7305            return None;
 7306        }
 7307
 7308        self.take_active_inline_completion(cx);
 7309        let Some(provider) = self.edit_prediction_provider() else {
 7310            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7311            return None;
 7312        };
 7313
 7314        let (buffer, cursor_buffer_position) =
 7315            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7316
 7317        self.edit_prediction_settings =
 7318            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7319
 7320        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7321
 7322        if self.edit_prediction_indent_conflict {
 7323            let cursor_point = cursor.to_point(&multibuffer);
 7324
 7325            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7326
 7327            if let Some((_, indent)) = indents.iter().next() {
 7328                if indent.len == cursor_point.column {
 7329                    self.edit_prediction_indent_conflict = false;
 7330                }
 7331            }
 7332        }
 7333
 7334        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7335        let edits = inline_completion
 7336            .edits
 7337            .into_iter()
 7338            .flat_map(|(range, new_text)| {
 7339                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7340                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7341                Some((start..end, new_text))
 7342            })
 7343            .collect::<Vec<_>>();
 7344        if edits.is_empty() {
 7345            return None;
 7346        }
 7347
 7348        let first_edit_start = edits.first().unwrap().0.start;
 7349        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7350        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7351
 7352        let last_edit_end = edits.last().unwrap().0.end;
 7353        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7354        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7355
 7356        let cursor_row = cursor.to_point(&multibuffer).row;
 7357
 7358        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7359
 7360        let mut inlay_ids = Vec::new();
 7361        let invalidation_row_range;
 7362        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7363            Some(cursor_row..edit_end_row)
 7364        } else if cursor_row > edit_end_row {
 7365            Some(edit_start_row..cursor_row)
 7366        } else {
 7367            None
 7368        };
 7369        let is_move =
 7370            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7371        let completion = if is_move {
 7372            invalidation_row_range =
 7373                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7374            let target = first_edit_start;
 7375            InlineCompletion::Move { target, snapshot }
 7376        } else {
 7377            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7378                && !self.inline_completions_hidden_for_vim_mode;
 7379
 7380            if show_completions_in_buffer {
 7381                if edits
 7382                    .iter()
 7383                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7384                {
 7385                    let mut inlays = Vec::new();
 7386                    for (range, new_text) in &edits {
 7387                        let inlay = Inlay::inline_completion(
 7388                            post_inc(&mut self.next_inlay_id),
 7389                            range.start,
 7390                            new_text.as_str(),
 7391                        );
 7392                        inlay_ids.push(inlay.id);
 7393                        inlays.push(inlay);
 7394                    }
 7395
 7396                    self.splice_inlays(&[], inlays, cx);
 7397                } else {
 7398                    let background_color = cx.theme().status().deleted_background;
 7399                    let style = HighlightStyle {
 7400                        background_color: Some(background_color),
 7401                        ..Default::default()
 7402                    };
 7403                    self.highlight_text::<InlineCompletionHighlight>(
 7404                        edits
 7405                            .iter()
 7406                            .map(|(range, _)| (range.clone(), style))
 7407                            .collect(),
 7408                        cx,
 7409                    );
 7410                }
 7411            }
 7412
 7413            invalidation_row_range = edit_start_row..edit_end_row;
 7414
 7415            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7416                if provider.show_tab_accept_marker() {
 7417                    EditDisplayMode::TabAccept
 7418                } else {
 7419                    EditDisplayMode::Inline
 7420                }
 7421            } else {
 7422                EditDisplayMode::DiffPopover
 7423            };
 7424
 7425            InlineCompletion::Edit {
 7426                edits,
 7427                edit_preview: inline_completion.edit_preview,
 7428                display_mode,
 7429                snapshot,
 7430            }
 7431        };
 7432
 7433        let invalidation_range = multibuffer
 7434            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7435            ..multibuffer.anchor_after(Point::new(
 7436                invalidation_row_range.end,
 7437                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7438            ));
 7439
 7440        self.stale_inline_completion_in_menu = None;
 7441        self.active_inline_completion = Some(InlineCompletionState {
 7442            inlay_ids,
 7443            completion,
 7444            completion_id: inline_completion.id,
 7445            invalidation_range,
 7446        });
 7447
 7448        cx.notify();
 7449
 7450        Some(())
 7451    }
 7452
 7453    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7454        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7455    }
 7456
 7457    fn clear_tasks(&mut self) {
 7458        self.tasks.clear()
 7459    }
 7460
 7461    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7462        if self.tasks.insert(key, value).is_some() {
 7463            // This case should hopefully be rare, but just in case...
 7464            log::error!(
 7465                "multiple different run targets found on a single line, only the last target will be rendered"
 7466            )
 7467        }
 7468    }
 7469
 7470    /// Get all display points of breakpoints that will be rendered within editor
 7471    ///
 7472    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7473    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7474    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7475    fn active_breakpoints(
 7476        &self,
 7477        range: Range<DisplayRow>,
 7478        window: &mut Window,
 7479        cx: &mut Context<Self>,
 7480    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7481        let mut breakpoint_display_points = HashMap::default();
 7482
 7483        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7484            return breakpoint_display_points;
 7485        };
 7486
 7487        let snapshot = self.snapshot(window, cx);
 7488
 7489        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7490        let Some(project) = self.project.as_ref() else {
 7491            return breakpoint_display_points;
 7492        };
 7493
 7494        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7495            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7496
 7497        for (buffer_snapshot, range, excerpt_id) in
 7498            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7499        {
 7500            let Some(buffer) = project
 7501                .read(cx)
 7502                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7503            else {
 7504                continue;
 7505            };
 7506            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7507                &buffer,
 7508                Some(
 7509                    buffer_snapshot.anchor_before(range.start)
 7510                        ..buffer_snapshot.anchor_after(range.end),
 7511                ),
 7512                buffer_snapshot,
 7513                cx,
 7514            );
 7515            for (breakpoint, state) in breakpoints {
 7516                let multi_buffer_anchor =
 7517                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7518                let position = multi_buffer_anchor
 7519                    .to_point(&multi_buffer_snapshot)
 7520                    .to_display_point(&snapshot);
 7521
 7522                breakpoint_display_points.insert(
 7523                    position.row(),
 7524                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7525                );
 7526            }
 7527        }
 7528
 7529        breakpoint_display_points
 7530    }
 7531
 7532    fn breakpoint_context_menu(
 7533        &self,
 7534        anchor: Anchor,
 7535        window: &mut Window,
 7536        cx: &mut Context<Self>,
 7537    ) -> Entity<ui::ContextMenu> {
 7538        let weak_editor = cx.weak_entity();
 7539        let focus_handle = self.focus_handle(cx);
 7540
 7541        let row = self
 7542            .buffer
 7543            .read(cx)
 7544            .snapshot(cx)
 7545            .summary_for_anchor::<Point>(&anchor)
 7546            .row;
 7547
 7548        let breakpoint = self
 7549            .breakpoint_at_row(row, window, cx)
 7550            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7551
 7552        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7553            "Edit Log Breakpoint"
 7554        } else {
 7555            "Set Log Breakpoint"
 7556        };
 7557
 7558        let condition_breakpoint_msg = if breakpoint
 7559            .as_ref()
 7560            .is_some_and(|bp| bp.1.condition.is_some())
 7561        {
 7562            "Edit Condition Breakpoint"
 7563        } else {
 7564            "Set Condition Breakpoint"
 7565        };
 7566
 7567        let hit_condition_breakpoint_msg = if breakpoint
 7568            .as_ref()
 7569            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7570        {
 7571            "Edit Hit Condition Breakpoint"
 7572        } else {
 7573            "Set Hit Condition Breakpoint"
 7574        };
 7575
 7576        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7577            "Unset Breakpoint"
 7578        } else {
 7579            "Set Breakpoint"
 7580        };
 7581
 7582        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7583
 7584        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7585            BreakpointState::Enabled => Some("Disable"),
 7586            BreakpointState::Disabled => Some("Enable"),
 7587        });
 7588
 7589        let (anchor, breakpoint) =
 7590            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7591
 7592        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7593            menu.on_blur_subscription(Subscription::new(|| {}))
 7594                .context(focus_handle)
 7595                .when(run_to_cursor, |this| {
 7596                    let weak_editor = weak_editor.clone();
 7597                    this.entry("Run to cursor", None, move |window, cx| {
 7598                        weak_editor
 7599                            .update(cx, |editor, cx| {
 7600                                editor.change_selections(None, window, cx, |s| {
 7601                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7602                                });
 7603                            })
 7604                            .ok();
 7605
 7606                        window.dispatch_action(Box::new(RunToCursor), cx);
 7607                    })
 7608                    .separator()
 7609                })
 7610                .when_some(toggle_state_msg, |this, msg| {
 7611                    this.entry(msg, None, {
 7612                        let weak_editor = weak_editor.clone();
 7613                        let breakpoint = breakpoint.clone();
 7614                        move |_window, cx| {
 7615                            weak_editor
 7616                                .update(cx, |this, cx| {
 7617                                    this.edit_breakpoint_at_anchor(
 7618                                        anchor,
 7619                                        breakpoint.as_ref().clone(),
 7620                                        BreakpointEditAction::InvertState,
 7621                                        cx,
 7622                                    );
 7623                                })
 7624                                .log_err();
 7625                        }
 7626                    })
 7627                })
 7628                .entry(set_breakpoint_msg, None, {
 7629                    let weak_editor = weak_editor.clone();
 7630                    let breakpoint = breakpoint.clone();
 7631                    move |_window, cx| {
 7632                        weak_editor
 7633                            .update(cx, |this, cx| {
 7634                                this.edit_breakpoint_at_anchor(
 7635                                    anchor,
 7636                                    breakpoint.as_ref().clone(),
 7637                                    BreakpointEditAction::Toggle,
 7638                                    cx,
 7639                                );
 7640                            })
 7641                            .log_err();
 7642                    }
 7643                })
 7644                .entry(log_breakpoint_msg, None, {
 7645                    let breakpoint = breakpoint.clone();
 7646                    let weak_editor = weak_editor.clone();
 7647                    move |window, cx| {
 7648                        weak_editor
 7649                            .update(cx, |this, cx| {
 7650                                this.add_edit_breakpoint_block(
 7651                                    anchor,
 7652                                    breakpoint.as_ref(),
 7653                                    BreakpointPromptEditAction::Log,
 7654                                    window,
 7655                                    cx,
 7656                                );
 7657                            })
 7658                            .log_err();
 7659                    }
 7660                })
 7661                .entry(condition_breakpoint_msg, None, {
 7662                    let breakpoint = breakpoint.clone();
 7663                    let weak_editor = weak_editor.clone();
 7664                    move |window, cx| {
 7665                        weak_editor
 7666                            .update(cx, |this, cx| {
 7667                                this.add_edit_breakpoint_block(
 7668                                    anchor,
 7669                                    breakpoint.as_ref(),
 7670                                    BreakpointPromptEditAction::Condition,
 7671                                    window,
 7672                                    cx,
 7673                                );
 7674                            })
 7675                            .log_err();
 7676                    }
 7677                })
 7678                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7679                    weak_editor
 7680                        .update(cx, |this, cx| {
 7681                            this.add_edit_breakpoint_block(
 7682                                anchor,
 7683                                breakpoint.as_ref(),
 7684                                BreakpointPromptEditAction::HitCondition,
 7685                                window,
 7686                                cx,
 7687                            );
 7688                        })
 7689                        .log_err();
 7690                })
 7691        })
 7692    }
 7693
 7694    fn render_breakpoint(
 7695        &self,
 7696        position: Anchor,
 7697        row: DisplayRow,
 7698        breakpoint: &Breakpoint,
 7699        state: Option<BreakpointSessionState>,
 7700        cx: &mut Context<Self>,
 7701    ) -> IconButton {
 7702        let is_rejected = state.is_some_and(|s| !s.verified);
 7703        // Is it a breakpoint that shows up when hovering over gutter?
 7704        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7705            (false, false),
 7706            |PhantomBreakpointIndicator {
 7707                 is_active,
 7708                 display_row,
 7709                 collides_with_existing_breakpoint,
 7710             }| {
 7711                (
 7712                    is_active && display_row == row,
 7713                    collides_with_existing_breakpoint,
 7714                )
 7715            },
 7716        );
 7717
 7718        let (color, icon) = {
 7719            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7720                (false, false) => ui::IconName::DebugBreakpoint,
 7721                (true, false) => ui::IconName::DebugLogBreakpoint,
 7722                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7723                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7724            };
 7725
 7726            let color = if is_phantom {
 7727                Color::Hint
 7728            } else if is_rejected {
 7729                Color::Disabled
 7730            } else {
 7731                Color::Debugger
 7732            };
 7733
 7734            (color, icon)
 7735        };
 7736
 7737        let breakpoint = Arc::from(breakpoint.clone());
 7738
 7739        let alt_as_text = gpui::Keystroke {
 7740            modifiers: Modifiers::secondary_key(),
 7741            ..Default::default()
 7742        };
 7743        let primary_action_text = if breakpoint.is_disabled() {
 7744            "Enable breakpoint"
 7745        } else if is_phantom && !collides_with_existing {
 7746            "Set breakpoint"
 7747        } else {
 7748            "Unset breakpoint"
 7749        };
 7750        let focus_handle = self.focus_handle.clone();
 7751
 7752        let meta = if is_rejected {
 7753            SharedString::from("No executable code is associated with this line.")
 7754        } else if collides_with_existing && !breakpoint.is_disabled() {
 7755            SharedString::from(format!(
 7756                "{alt_as_text}-click to disable,\nright-click for more options."
 7757            ))
 7758        } else {
 7759            SharedString::from("Right-click for more options.")
 7760        };
 7761        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7762            .icon_size(IconSize::XSmall)
 7763            .size(ui::ButtonSize::None)
 7764            .when(is_rejected, |this| {
 7765                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7766            })
 7767            .icon_color(color)
 7768            .style(ButtonStyle::Transparent)
 7769            .on_click(cx.listener({
 7770                let breakpoint = breakpoint.clone();
 7771
 7772                move |editor, event: &ClickEvent, window, cx| {
 7773                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7774                        BreakpointEditAction::InvertState
 7775                    } else {
 7776                        BreakpointEditAction::Toggle
 7777                    };
 7778
 7779                    window.focus(&editor.focus_handle(cx));
 7780                    editor.edit_breakpoint_at_anchor(
 7781                        position,
 7782                        breakpoint.as_ref().clone(),
 7783                        edit_action,
 7784                        cx,
 7785                    );
 7786                }
 7787            }))
 7788            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7789                editor.set_breakpoint_context_menu(
 7790                    row,
 7791                    Some(position),
 7792                    event.down.position,
 7793                    window,
 7794                    cx,
 7795                );
 7796            }))
 7797            .tooltip(move |window, cx| {
 7798                Tooltip::with_meta_in(
 7799                    primary_action_text,
 7800                    Some(&ToggleBreakpoint),
 7801                    meta.clone(),
 7802                    &focus_handle,
 7803                    window,
 7804                    cx,
 7805                )
 7806            })
 7807    }
 7808
 7809    fn build_tasks_context(
 7810        project: &Entity<Project>,
 7811        buffer: &Entity<Buffer>,
 7812        buffer_row: u32,
 7813        tasks: &Arc<RunnableTasks>,
 7814        cx: &mut Context<Self>,
 7815    ) -> Task<Option<task::TaskContext>> {
 7816        let position = Point::new(buffer_row, tasks.column);
 7817        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7818        let location = Location {
 7819            buffer: buffer.clone(),
 7820            range: range_start..range_start,
 7821        };
 7822        // Fill in the environmental variables from the tree-sitter captures
 7823        let mut captured_task_variables = TaskVariables::default();
 7824        for (capture_name, value) in tasks.extra_variables.clone() {
 7825            captured_task_variables.insert(
 7826                task::VariableName::Custom(capture_name.into()),
 7827                value.clone(),
 7828            );
 7829        }
 7830        project.update(cx, |project, cx| {
 7831            project.task_store().update(cx, |task_store, cx| {
 7832                task_store.task_context_for_location(captured_task_variables, location, cx)
 7833            })
 7834        })
 7835    }
 7836
 7837    pub fn spawn_nearest_task(
 7838        &mut self,
 7839        action: &SpawnNearestTask,
 7840        window: &mut Window,
 7841        cx: &mut Context<Self>,
 7842    ) {
 7843        let Some((workspace, _)) = self.workspace.clone() else {
 7844            return;
 7845        };
 7846        let Some(project) = self.project.clone() else {
 7847            return;
 7848        };
 7849
 7850        // Try to find a closest, enclosing node using tree-sitter that has a
 7851        // task
 7852        let Some((buffer, buffer_row, tasks)) = self
 7853            .find_enclosing_node_task(cx)
 7854            // Or find the task that's closest in row-distance.
 7855            .or_else(|| self.find_closest_task(cx))
 7856        else {
 7857            return;
 7858        };
 7859
 7860        let reveal_strategy = action.reveal;
 7861        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7862        cx.spawn_in(window, async move |_, cx| {
 7863            let context = task_context.await?;
 7864            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7865
 7866            let resolved = &mut resolved_task.resolved;
 7867            resolved.reveal = reveal_strategy;
 7868
 7869            workspace
 7870                .update_in(cx, |workspace, window, cx| {
 7871                    workspace.schedule_resolved_task(
 7872                        task_source_kind,
 7873                        resolved_task,
 7874                        false,
 7875                        window,
 7876                        cx,
 7877                    );
 7878                })
 7879                .ok()
 7880        })
 7881        .detach();
 7882    }
 7883
 7884    fn find_closest_task(
 7885        &mut self,
 7886        cx: &mut Context<Self>,
 7887    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7888        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7889
 7890        let ((buffer_id, row), tasks) = self
 7891            .tasks
 7892            .iter()
 7893            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7894
 7895        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7896        let tasks = Arc::new(tasks.to_owned());
 7897        Some((buffer, *row, tasks))
 7898    }
 7899
 7900    fn find_enclosing_node_task(
 7901        &mut self,
 7902        cx: &mut Context<Self>,
 7903    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7904        let snapshot = self.buffer.read(cx).snapshot(cx);
 7905        let offset = self.selections.newest::<usize>(cx).head();
 7906        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7907        let buffer_id = excerpt.buffer().remote_id();
 7908
 7909        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7910        let mut cursor = layer.node().walk();
 7911
 7912        while cursor.goto_first_child_for_byte(offset).is_some() {
 7913            if cursor.node().end_byte() == offset {
 7914                cursor.goto_next_sibling();
 7915            }
 7916        }
 7917
 7918        // Ascend to the smallest ancestor that contains the range and has a task.
 7919        loop {
 7920            let node = cursor.node();
 7921            let node_range = node.byte_range();
 7922            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7923
 7924            // Check if this node contains our offset
 7925            if node_range.start <= offset && node_range.end >= offset {
 7926                // If it contains offset, check for task
 7927                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7928                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7929                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7930                }
 7931            }
 7932
 7933            if !cursor.goto_parent() {
 7934                break;
 7935            }
 7936        }
 7937        None
 7938    }
 7939
 7940    fn render_run_indicator(
 7941        &self,
 7942        _style: &EditorStyle,
 7943        is_active: bool,
 7944        row: DisplayRow,
 7945        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7946        cx: &mut Context<Self>,
 7947    ) -> IconButton {
 7948        let color = Color::Muted;
 7949        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7950
 7951        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7952            .shape(ui::IconButtonShape::Square)
 7953            .icon_size(IconSize::XSmall)
 7954            .icon_color(color)
 7955            .toggle_state(is_active)
 7956            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7957                let quick_launch = e.down.button == MouseButton::Left;
 7958                window.focus(&editor.focus_handle(cx));
 7959                editor.toggle_code_actions(
 7960                    &ToggleCodeActions {
 7961                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 7962                        quick_launch,
 7963                    },
 7964                    window,
 7965                    cx,
 7966                );
 7967            }))
 7968            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7969                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7970            }))
 7971    }
 7972
 7973    pub fn context_menu_visible(&self) -> bool {
 7974        !self.edit_prediction_preview_is_active()
 7975            && self
 7976                .context_menu
 7977                .borrow()
 7978                .as_ref()
 7979                .map_or(false, |menu| menu.visible())
 7980    }
 7981
 7982    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7983        self.context_menu
 7984            .borrow()
 7985            .as_ref()
 7986            .map(|menu| menu.origin())
 7987    }
 7988
 7989    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7990        self.context_menu_options = Some(options);
 7991    }
 7992
 7993    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7994    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7995
 7996    fn render_edit_prediction_popover(
 7997        &mut self,
 7998        text_bounds: &Bounds<Pixels>,
 7999        content_origin: gpui::Point<Pixels>,
 8000        right_margin: Pixels,
 8001        editor_snapshot: &EditorSnapshot,
 8002        visible_row_range: Range<DisplayRow>,
 8003        scroll_top: f32,
 8004        scroll_bottom: f32,
 8005        line_layouts: &[LineWithInvisibles],
 8006        line_height: Pixels,
 8007        scroll_pixel_position: gpui::Point<Pixels>,
 8008        newest_selection_head: Option<DisplayPoint>,
 8009        editor_width: Pixels,
 8010        style: &EditorStyle,
 8011        window: &mut Window,
 8012        cx: &mut App,
 8013    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8014        if self.mode().is_minimap() {
 8015            return None;
 8016        }
 8017        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8018
 8019        if self.edit_prediction_visible_in_cursor_popover(true) {
 8020            return None;
 8021        }
 8022
 8023        match &active_inline_completion.completion {
 8024            InlineCompletion::Move { target, .. } => {
 8025                let target_display_point = target.to_display_point(editor_snapshot);
 8026
 8027                if self.edit_prediction_requires_modifier() {
 8028                    if !self.edit_prediction_preview_is_active() {
 8029                        return None;
 8030                    }
 8031
 8032                    self.render_edit_prediction_modifier_jump_popover(
 8033                        text_bounds,
 8034                        content_origin,
 8035                        visible_row_range,
 8036                        line_layouts,
 8037                        line_height,
 8038                        scroll_pixel_position,
 8039                        newest_selection_head,
 8040                        target_display_point,
 8041                        window,
 8042                        cx,
 8043                    )
 8044                } else {
 8045                    self.render_edit_prediction_eager_jump_popover(
 8046                        text_bounds,
 8047                        content_origin,
 8048                        editor_snapshot,
 8049                        visible_row_range,
 8050                        scroll_top,
 8051                        scroll_bottom,
 8052                        line_height,
 8053                        scroll_pixel_position,
 8054                        target_display_point,
 8055                        editor_width,
 8056                        window,
 8057                        cx,
 8058                    )
 8059                }
 8060            }
 8061            InlineCompletion::Edit {
 8062                display_mode: EditDisplayMode::Inline,
 8063                ..
 8064            } => None,
 8065            InlineCompletion::Edit {
 8066                display_mode: EditDisplayMode::TabAccept,
 8067                edits,
 8068                ..
 8069            } => {
 8070                let range = &edits.first()?.0;
 8071                let target_display_point = range.end.to_display_point(editor_snapshot);
 8072
 8073                self.render_edit_prediction_end_of_line_popover(
 8074                    "Accept",
 8075                    editor_snapshot,
 8076                    visible_row_range,
 8077                    target_display_point,
 8078                    line_height,
 8079                    scroll_pixel_position,
 8080                    content_origin,
 8081                    editor_width,
 8082                    window,
 8083                    cx,
 8084                )
 8085            }
 8086            InlineCompletion::Edit {
 8087                edits,
 8088                edit_preview,
 8089                display_mode: EditDisplayMode::DiffPopover,
 8090                snapshot,
 8091            } => self.render_edit_prediction_diff_popover(
 8092                text_bounds,
 8093                content_origin,
 8094                right_margin,
 8095                editor_snapshot,
 8096                visible_row_range,
 8097                line_layouts,
 8098                line_height,
 8099                scroll_pixel_position,
 8100                newest_selection_head,
 8101                editor_width,
 8102                style,
 8103                edits,
 8104                edit_preview,
 8105                snapshot,
 8106                window,
 8107                cx,
 8108            ),
 8109        }
 8110    }
 8111
 8112    fn render_edit_prediction_modifier_jump_popover(
 8113        &mut self,
 8114        text_bounds: &Bounds<Pixels>,
 8115        content_origin: gpui::Point<Pixels>,
 8116        visible_row_range: Range<DisplayRow>,
 8117        line_layouts: &[LineWithInvisibles],
 8118        line_height: Pixels,
 8119        scroll_pixel_position: gpui::Point<Pixels>,
 8120        newest_selection_head: Option<DisplayPoint>,
 8121        target_display_point: DisplayPoint,
 8122        window: &mut Window,
 8123        cx: &mut App,
 8124    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8125        let scrolled_content_origin =
 8126            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8127
 8128        const SCROLL_PADDING_Y: Pixels = px(12.);
 8129
 8130        if target_display_point.row() < visible_row_range.start {
 8131            return self.render_edit_prediction_scroll_popover(
 8132                |_| SCROLL_PADDING_Y,
 8133                IconName::ArrowUp,
 8134                visible_row_range,
 8135                line_layouts,
 8136                newest_selection_head,
 8137                scrolled_content_origin,
 8138                window,
 8139                cx,
 8140            );
 8141        } else if target_display_point.row() >= visible_row_range.end {
 8142            return self.render_edit_prediction_scroll_popover(
 8143                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8144                IconName::ArrowDown,
 8145                visible_row_range,
 8146                line_layouts,
 8147                newest_selection_head,
 8148                scrolled_content_origin,
 8149                window,
 8150                cx,
 8151            );
 8152        }
 8153
 8154        const POLE_WIDTH: Pixels = px(2.);
 8155
 8156        let line_layout =
 8157            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8158        let target_column = target_display_point.column() as usize;
 8159
 8160        let target_x = line_layout.x_for_index(target_column);
 8161        let target_y =
 8162            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8163
 8164        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8165
 8166        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8167        border_color.l += 0.001;
 8168
 8169        let mut element = v_flex()
 8170            .items_end()
 8171            .when(flag_on_right, |el| el.items_start())
 8172            .child(if flag_on_right {
 8173                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8174                    .rounded_bl(px(0.))
 8175                    .rounded_tl(px(0.))
 8176                    .border_l_2()
 8177                    .border_color(border_color)
 8178            } else {
 8179                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8180                    .rounded_br(px(0.))
 8181                    .rounded_tr(px(0.))
 8182                    .border_r_2()
 8183                    .border_color(border_color)
 8184            })
 8185            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8186            .into_any();
 8187
 8188        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8189
 8190        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8191            - point(
 8192                if flag_on_right {
 8193                    POLE_WIDTH
 8194                } else {
 8195                    size.width - POLE_WIDTH
 8196                },
 8197                size.height - line_height,
 8198            );
 8199
 8200        origin.x = origin.x.max(content_origin.x);
 8201
 8202        element.prepaint_at(origin, window, cx);
 8203
 8204        Some((element, origin))
 8205    }
 8206
 8207    fn render_edit_prediction_scroll_popover(
 8208        &mut self,
 8209        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8210        scroll_icon: IconName,
 8211        visible_row_range: Range<DisplayRow>,
 8212        line_layouts: &[LineWithInvisibles],
 8213        newest_selection_head: Option<DisplayPoint>,
 8214        scrolled_content_origin: gpui::Point<Pixels>,
 8215        window: &mut Window,
 8216        cx: &mut App,
 8217    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8218        let mut element = self
 8219            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8220            .into_any();
 8221
 8222        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8223
 8224        let cursor = newest_selection_head?;
 8225        let cursor_row_layout =
 8226            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8227        let cursor_column = cursor.column() as usize;
 8228
 8229        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8230
 8231        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8232
 8233        element.prepaint_at(origin, window, cx);
 8234        Some((element, origin))
 8235    }
 8236
 8237    fn render_edit_prediction_eager_jump_popover(
 8238        &mut self,
 8239        text_bounds: &Bounds<Pixels>,
 8240        content_origin: gpui::Point<Pixels>,
 8241        editor_snapshot: &EditorSnapshot,
 8242        visible_row_range: Range<DisplayRow>,
 8243        scroll_top: f32,
 8244        scroll_bottom: f32,
 8245        line_height: Pixels,
 8246        scroll_pixel_position: gpui::Point<Pixels>,
 8247        target_display_point: DisplayPoint,
 8248        editor_width: Pixels,
 8249        window: &mut Window,
 8250        cx: &mut App,
 8251    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8252        if target_display_point.row().as_f32() < scroll_top {
 8253            let mut element = self
 8254                .render_edit_prediction_line_popover(
 8255                    "Jump to Edit",
 8256                    Some(IconName::ArrowUp),
 8257                    window,
 8258                    cx,
 8259                )?
 8260                .into_any();
 8261
 8262            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8263            let offset = point(
 8264                (text_bounds.size.width - size.width) / 2.,
 8265                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8266            );
 8267
 8268            let origin = text_bounds.origin + offset;
 8269            element.prepaint_at(origin, window, cx);
 8270            Some((element, origin))
 8271        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8272            let mut element = self
 8273                .render_edit_prediction_line_popover(
 8274                    "Jump to Edit",
 8275                    Some(IconName::ArrowDown),
 8276                    window,
 8277                    cx,
 8278                )?
 8279                .into_any();
 8280
 8281            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8282            let offset = point(
 8283                (text_bounds.size.width - size.width) / 2.,
 8284                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8285            );
 8286
 8287            let origin = text_bounds.origin + offset;
 8288            element.prepaint_at(origin, window, cx);
 8289            Some((element, origin))
 8290        } else {
 8291            self.render_edit_prediction_end_of_line_popover(
 8292                "Jump to Edit",
 8293                editor_snapshot,
 8294                visible_row_range,
 8295                target_display_point,
 8296                line_height,
 8297                scroll_pixel_position,
 8298                content_origin,
 8299                editor_width,
 8300                window,
 8301                cx,
 8302            )
 8303        }
 8304    }
 8305
 8306    fn render_edit_prediction_end_of_line_popover(
 8307        self: &mut Editor,
 8308        label: &'static str,
 8309        editor_snapshot: &EditorSnapshot,
 8310        visible_row_range: Range<DisplayRow>,
 8311        target_display_point: DisplayPoint,
 8312        line_height: Pixels,
 8313        scroll_pixel_position: gpui::Point<Pixels>,
 8314        content_origin: gpui::Point<Pixels>,
 8315        editor_width: Pixels,
 8316        window: &mut Window,
 8317        cx: &mut App,
 8318    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8319        let target_line_end = DisplayPoint::new(
 8320            target_display_point.row(),
 8321            editor_snapshot.line_len(target_display_point.row()),
 8322        );
 8323
 8324        let mut element = self
 8325            .render_edit_prediction_line_popover(label, None, window, cx)?
 8326            .into_any();
 8327
 8328        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8329
 8330        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8331
 8332        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8333        let mut origin = start_point
 8334            + line_origin
 8335            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8336        origin.x = origin.x.max(content_origin.x);
 8337
 8338        let max_x = content_origin.x + editor_width - size.width;
 8339
 8340        if origin.x > max_x {
 8341            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8342
 8343            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8344                origin.y += offset;
 8345                IconName::ArrowUp
 8346            } else {
 8347                origin.y -= offset;
 8348                IconName::ArrowDown
 8349            };
 8350
 8351            element = self
 8352                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8353                .into_any();
 8354
 8355            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8356
 8357            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8358        }
 8359
 8360        element.prepaint_at(origin, window, cx);
 8361        Some((element, origin))
 8362    }
 8363
 8364    fn render_edit_prediction_diff_popover(
 8365        self: &Editor,
 8366        text_bounds: &Bounds<Pixels>,
 8367        content_origin: gpui::Point<Pixels>,
 8368        right_margin: Pixels,
 8369        editor_snapshot: &EditorSnapshot,
 8370        visible_row_range: Range<DisplayRow>,
 8371        line_layouts: &[LineWithInvisibles],
 8372        line_height: Pixels,
 8373        scroll_pixel_position: gpui::Point<Pixels>,
 8374        newest_selection_head: Option<DisplayPoint>,
 8375        editor_width: Pixels,
 8376        style: &EditorStyle,
 8377        edits: &Vec<(Range<Anchor>, String)>,
 8378        edit_preview: &Option<language::EditPreview>,
 8379        snapshot: &language::BufferSnapshot,
 8380        window: &mut Window,
 8381        cx: &mut App,
 8382    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8383        let edit_start = edits
 8384            .first()
 8385            .unwrap()
 8386            .0
 8387            .start
 8388            .to_display_point(editor_snapshot);
 8389        let edit_end = edits
 8390            .last()
 8391            .unwrap()
 8392            .0
 8393            .end
 8394            .to_display_point(editor_snapshot);
 8395
 8396        let is_visible = visible_row_range.contains(&edit_start.row())
 8397            || visible_row_range.contains(&edit_end.row());
 8398        if !is_visible {
 8399            return None;
 8400        }
 8401
 8402        let highlighted_edits =
 8403            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8404
 8405        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8406        let line_count = highlighted_edits.text.lines().count();
 8407
 8408        const BORDER_WIDTH: Pixels = px(1.);
 8409
 8410        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8411        let has_keybind = keybind.is_some();
 8412
 8413        let mut element = h_flex()
 8414            .items_start()
 8415            .child(
 8416                h_flex()
 8417                    .bg(cx.theme().colors().editor_background)
 8418                    .border(BORDER_WIDTH)
 8419                    .shadow_sm()
 8420                    .border_color(cx.theme().colors().border)
 8421                    .rounded_l_lg()
 8422                    .when(line_count > 1, |el| el.rounded_br_lg())
 8423                    .pr_1()
 8424                    .child(styled_text),
 8425            )
 8426            .child(
 8427                h_flex()
 8428                    .h(line_height + BORDER_WIDTH * 2.)
 8429                    .px_1p5()
 8430                    .gap_1()
 8431                    // Workaround: For some reason, there's a gap if we don't do this
 8432                    .ml(-BORDER_WIDTH)
 8433                    .shadow(vec![gpui::BoxShadow {
 8434                        color: gpui::black().opacity(0.05),
 8435                        offset: point(px(1.), px(1.)),
 8436                        blur_radius: px(2.),
 8437                        spread_radius: px(0.),
 8438                    }])
 8439                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8440                    .border(BORDER_WIDTH)
 8441                    .border_color(cx.theme().colors().border)
 8442                    .rounded_r_lg()
 8443                    .id("edit_prediction_diff_popover_keybind")
 8444                    .when(!has_keybind, |el| {
 8445                        let status_colors = cx.theme().status();
 8446
 8447                        el.bg(status_colors.error_background)
 8448                            .border_color(status_colors.error.opacity(0.6))
 8449                            .child(Icon::new(IconName::Info).color(Color::Error))
 8450                            .cursor_default()
 8451                            .hoverable_tooltip(move |_window, cx| {
 8452                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8453                            })
 8454                    })
 8455                    .children(keybind),
 8456            )
 8457            .into_any();
 8458
 8459        let longest_row =
 8460            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8461        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8462            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8463        } else {
 8464            layout_line(
 8465                longest_row,
 8466                editor_snapshot,
 8467                style,
 8468                editor_width,
 8469                |_| false,
 8470                window,
 8471                cx,
 8472            )
 8473            .width
 8474        };
 8475
 8476        let viewport_bounds =
 8477            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8478                right: -right_margin,
 8479                ..Default::default()
 8480            });
 8481
 8482        let x_after_longest =
 8483            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8484                - scroll_pixel_position.x;
 8485
 8486        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8487
 8488        // Fully visible if it can be displayed within the window (allow overlapping other
 8489        // panes). However, this is only allowed if the popover starts within text_bounds.
 8490        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8491            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8492
 8493        let mut origin = if can_position_to_the_right {
 8494            point(
 8495                x_after_longest,
 8496                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8497                    - scroll_pixel_position.y,
 8498            )
 8499        } else {
 8500            let cursor_row = newest_selection_head.map(|head| head.row());
 8501            let above_edit = edit_start
 8502                .row()
 8503                .0
 8504                .checked_sub(line_count as u32)
 8505                .map(DisplayRow);
 8506            let below_edit = Some(edit_end.row() + 1);
 8507            let above_cursor =
 8508                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8509            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8510
 8511            // Place the edit popover adjacent to the edit if there is a location
 8512            // available that is onscreen and does not obscure the cursor. Otherwise,
 8513            // place it adjacent to the cursor.
 8514            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8515                .into_iter()
 8516                .flatten()
 8517                .find(|&start_row| {
 8518                    let end_row = start_row + line_count as u32;
 8519                    visible_row_range.contains(&start_row)
 8520                        && visible_row_range.contains(&end_row)
 8521                        && cursor_row.map_or(true, |cursor_row| {
 8522                            !((start_row..end_row).contains(&cursor_row))
 8523                        })
 8524                })?;
 8525
 8526            content_origin
 8527                + point(
 8528                    -scroll_pixel_position.x,
 8529                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8530                )
 8531        };
 8532
 8533        origin.x -= BORDER_WIDTH;
 8534
 8535        window.defer_draw(element, origin, 1);
 8536
 8537        // Do not return an element, since it will already be drawn due to defer_draw.
 8538        None
 8539    }
 8540
 8541    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8542        px(30.)
 8543    }
 8544
 8545    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8546        if self.read_only(cx) {
 8547            cx.theme().players().read_only()
 8548        } else {
 8549            self.style.as_ref().unwrap().local_player
 8550        }
 8551    }
 8552
 8553    fn render_edit_prediction_accept_keybind(
 8554        &self,
 8555        window: &mut Window,
 8556        cx: &App,
 8557    ) -> Option<AnyElement> {
 8558        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8559        let accept_keystroke = accept_binding.keystroke()?;
 8560
 8561        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8562
 8563        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8564            Color::Accent
 8565        } else {
 8566            Color::Muted
 8567        };
 8568
 8569        h_flex()
 8570            .px_0p5()
 8571            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8572            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8573            .text_size(TextSize::XSmall.rems(cx))
 8574            .child(h_flex().children(ui::render_modifiers(
 8575                &accept_keystroke.modifiers,
 8576                PlatformStyle::platform(),
 8577                Some(modifiers_color),
 8578                Some(IconSize::XSmall.rems().into()),
 8579                true,
 8580            )))
 8581            .when(is_platform_style_mac, |parent| {
 8582                parent.child(accept_keystroke.key.clone())
 8583            })
 8584            .when(!is_platform_style_mac, |parent| {
 8585                parent.child(
 8586                    Key::new(
 8587                        util::capitalize(&accept_keystroke.key),
 8588                        Some(Color::Default),
 8589                    )
 8590                    .size(Some(IconSize::XSmall.rems().into())),
 8591                )
 8592            })
 8593            .into_any()
 8594            .into()
 8595    }
 8596
 8597    fn render_edit_prediction_line_popover(
 8598        &self,
 8599        label: impl Into<SharedString>,
 8600        icon: Option<IconName>,
 8601        window: &mut Window,
 8602        cx: &App,
 8603    ) -> Option<Stateful<Div>> {
 8604        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8605
 8606        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8607        let has_keybind = keybind.is_some();
 8608
 8609        let result = h_flex()
 8610            .id("ep-line-popover")
 8611            .py_0p5()
 8612            .pl_1()
 8613            .pr(padding_right)
 8614            .gap_1()
 8615            .rounded_md()
 8616            .border_1()
 8617            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8618            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8619            .shadow_sm()
 8620            .when(!has_keybind, |el| {
 8621                let status_colors = cx.theme().status();
 8622
 8623                el.bg(status_colors.error_background)
 8624                    .border_color(status_colors.error.opacity(0.6))
 8625                    .pl_2()
 8626                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8627                    .cursor_default()
 8628                    .hoverable_tooltip(move |_window, cx| {
 8629                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8630                    })
 8631            })
 8632            .children(keybind)
 8633            .child(
 8634                Label::new(label)
 8635                    .size(LabelSize::Small)
 8636                    .when(!has_keybind, |el| {
 8637                        el.color(cx.theme().status().error.into()).strikethrough()
 8638                    }),
 8639            )
 8640            .when(!has_keybind, |el| {
 8641                el.child(
 8642                    h_flex().ml_1().child(
 8643                        Icon::new(IconName::Info)
 8644                            .size(IconSize::Small)
 8645                            .color(cx.theme().status().error.into()),
 8646                    ),
 8647                )
 8648            })
 8649            .when_some(icon, |element, icon| {
 8650                element.child(
 8651                    div()
 8652                        .mt(px(1.5))
 8653                        .child(Icon::new(icon).size(IconSize::Small)),
 8654                )
 8655            });
 8656
 8657        Some(result)
 8658    }
 8659
 8660    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8661        let accent_color = cx.theme().colors().text_accent;
 8662        let editor_bg_color = cx.theme().colors().editor_background;
 8663        editor_bg_color.blend(accent_color.opacity(0.1))
 8664    }
 8665
 8666    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8667        let accent_color = cx.theme().colors().text_accent;
 8668        let editor_bg_color = cx.theme().colors().editor_background;
 8669        editor_bg_color.blend(accent_color.opacity(0.6))
 8670    }
 8671
 8672    fn render_edit_prediction_cursor_popover(
 8673        &self,
 8674        min_width: Pixels,
 8675        max_width: Pixels,
 8676        cursor_point: Point,
 8677        style: &EditorStyle,
 8678        accept_keystroke: Option<&gpui::Keystroke>,
 8679        _window: &Window,
 8680        cx: &mut Context<Editor>,
 8681    ) -> Option<AnyElement> {
 8682        let provider = self.edit_prediction_provider.as_ref()?;
 8683
 8684        if provider.provider.needs_terms_acceptance(cx) {
 8685            return Some(
 8686                h_flex()
 8687                    .min_w(min_width)
 8688                    .flex_1()
 8689                    .px_2()
 8690                    .py_1()
 8691                    .gap_3()
 8692                    .elevation_2(cx)
 8693                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8694                    .id("accept-terms")
 8695                    .cursor_pointer()
 8696                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8697                    .on_click(cx.listener(|this, _event, window, cx| {
 8698                        cx.stop_propagation();
 8699                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8700                        window.dispatch_action(
 8701                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8702                            cx,
 8703                        );
 8704                    }))
 8705                    .child(
 8706                        h_flex()
 8707                            .flex_1()
 8708                            .gap_2()
 8709                            .child(Icon::new(IconName::ZedPredict))
 8710                            .child(Label::new("Accept Terms of Service"))
 8711                            .child(div().w_full())
 8712                            .child(
 8713                                Icon::new(IconName::ArrowUpRight)
 8714                                    .color(Color::Muted)
 8715                                    .size(IconSize::Small),
 8716                            )
 8717                            .into_any_element(),
 8718                    )
 8719                    .into_any(),
 8720            );
 8721        }
 8722
 8723        let is_refreshing = provider.provider.is_refreshing(cx);
 8724
 8725        fn pending_completion_container() -> Div {
 8726            h_flex()
 8727                .h_full()
 8728                .flex_1()
 8729                .gap_2()
 8730                .child(Icon::new(IconName::ZedPredict))
 8731        }
 8732
 8733        let completion = match &self.active_inline_completion {
 8734            Some(prediction) => {
 8735                if !self.has_visible_completions_menu() {
 8736                    const RADIUS: Pixels = px(6.);
 8737                    const BORDER_WIDTH: Pixels = px(1.);
 8738
 8739                    return Some(
 8740                        h_flex()
 8741                            .elevation_2(cx)
 8742                            .border(BORDER_WIDTH)
 8743                            .border_color(cx.theme().colors().border)
 8744                            .when(accept_keystroke.is_none(), |el| {
 8745                                el.border_color(cx.theme().status().error)
 8746                            })
 8747                            .rounded(RADIUS)
 8748                            .rounded_tl(px(0.))
 8749                            .overflow_hidden()
 8750                            .child(div().px_1p5().child(match &prediction.completion {
 8751                                InlineCompletion::Move { target, snapshot } => {
 8752                                    use text::ToPoint as _;
 8753                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8754                                    {
 8755                                        Icon::new(IconName::ZedPredictDown)
 8756                                    } else {
 8757                                        Icon::new(IconName::ZedPredictUp)
 8758                                    }
 8759                                }
 8760                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8761                            }))
 8762                            .child(
 8763                                h_flex()
 8764                                    .gap_1()
 8765                                    .py_1()
 8766                                    .px_2()
 8767                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8768                                    .border_l_1()
 8769                                    .border_color(cx.theme().colors().border)
 8770                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8771                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8772                                        el.child(
 8773                                            Label::new("Hold")
 8774                                                .size(LabelSize::Small)
 8775                                                .when(accept_keystroke.is_none(), |el| {
 8776                                                    el.strikethrough()
 8777                                                })
 8778                                                .line_height_style(LineHeightStyle::UiLabel),
 8779                                        )
 8780                                    })
 8781                                    .id("edit_prediction_cursor_popover_keybind")
 8782                                    .when(accept_keystroke.is_none(), |el| {
 8783                                        let status_colors = cx.theme().status();
 8784
 8785                                        el.bg(status_colors.error_background)
 8786                                            .border_color(status_colors.error.opacity(0.6))
 8787                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8788                                            .cursor_default()
 8789                                            .hoverable_tooltip(move |_window, cx| {
 8790                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8791                                                    .into()
 8792                                            })
 8793                                    })
 8794                                    .when_some(
 8795                                        accept_keystroke.as_ref(),
 8796                                        |el, accept_keystroke| {
 8797                                            el.child(h_flex().children(ui::render_modifiers(
 8798                                                &accept_keystroke.modifiers,
 8799                                                PlatformStyle::platform(),
 8800                                                Some(Color::Default),
 8801                                                Some(IconSize::XSmall.rems().into()),
 8802                                                false,
 8803                                            )))
 8804                                        },
 8805                                    ),
 8806                            )
 8807                            .into_any(),
 8808                    );
 8809                }
 8810
 8811                self.render_edit_prediction_cursor_popover_preview(
 8812                    prediction,
 8813                    cursor_point,
 8814                    style,
 8815                    cx,
 8816                )?
 8817            }
 8818
 8819            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8820                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8821                    stale_completion,
 8822                    cursor_point,
 8823                    style,
 8824                    cx,
 8825                )?,
 8826
 8827                None => {
 8828                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8829                }
 8830            },
 8831
 8832            None => pending_completion_container().child(Label::new("No Prediction")),
 8833        };
 8834
 8835        let completion = if is_refreshing {
 8836            completion
 8837                .with_animation(
 8838                    "loading-completion",
 8839                    Animation::new(Duration::from_secs(2))
 8840                        .repeat()
 8841                        .with_easing(pulsating_between(0.4, 0.8)),
 8842                    |label, delta| label.opacity(delta),
 8843                )
 8844                .into_any_element()
 8845        } else {
 8846            completion.into_any_element()
 8847        };
 8848
 8849        let has_completion = self.active_inline_completion.is_some();
 8850
 8851        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8852        Some(
 8853            h_flex()
 8854                .min_w(min_width)
 8855                .max_w(max_width)
 8856                .flex_1()
 8857                .elevation_2(cx)
 8858                .border_color(cx.theme().colors().border)
 8859                .child(
 8860                    div()
 8861                        .flex_1()
 8862                        .py_1()
 8863                        .px_2()
 8864                        .overflow_hidden()
 8865                        .child(completion),
 8866                )
 8867                .when_some(accept_keystroke, |el, accept_keystroke| {
 8868                    if !accept_keystroke.modifiers.modified() {
 8869                        return el;
 8870                    }
 8871
 8872                    el.child(
 8873                        h_flex()
 8874                            .h_full()
 8875                            .border_l_1()
 8876                            .rounded_r_lg()
 8877                            .border_color(cx.theme().colors().border)
 8878                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8879                            .gap_1()
 8880                            .py_1()
 8881                            .px_2()
 8882                            .child(
 8883                                h_flex()
 8884                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8885                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8886                                    .child(h_flex().children(ui::render_modifiers(
 8887                                        &accept_keystroke.modifiers,
 8888                                        PlatformStyle::platform(),
 8889                                        Some(if !has_completion {
 8890                                            Color::Muted
 8891                                        } else {
 8892                                            Color::Default
 8893                                        }),
 8894                                        None,
 8895                                        false,
 8896                                    ))),
 8897                            )
 8898                            .child(Label::new("Preview").into_any_element())
 8899                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8900                    )
 8901                })
 8902                .into_any(),
 8903        )
 8904    }
 8905
 8906    fn render_edit_prediction_cursor_popover_preview(
 8907        &self,
 8908        completion: &InlineCompletionState,
 8909        cursor_point: Point,
 8910        style: &EditorStyle,
 8911        cx: &mut Context<Editor>,
 8912    ) -> Option<Div> {
 8913        use text::ToPoint as _;
 8914
 8915        fn render_relative_row_jump(
 8916            prefix: impl Into<String>,
 8917            current_row: u32,
 8918            target_row: u32,
 8919        ) -> Div {
 8920            let (row_diff, arrow) = if target_row < current_row {
 8921                (current_row - target_row, IconName::ArrowUp)
 8922            } else {
 8923                (target_row - current_row, IconName::ArrowDown)
 8924            };
 8925
 8926            h_flex()
 8927                .child(
 8928                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8929                        .color(Color::Muted)
 8930                        .size(LabelSize::Small),
 8931                )
 8932                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8933        }
 8934
 8935        match &completion.completion {
 8936            InlineCompletion::Move {
 8937                target, snapshot, ..
 8938            } => Some(
 8939                h_flex()
 8940                    .px_2()
 8941                    .gap_2()
 8942                    .flex_1()
 8943                    .child(
 8944                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8945                            Icon::new(IconName::ZedPredictDown)
 8946                        } else {
 8947                            Icon::new(IconName::ZedPredictUp)
 8948                        },
 8949                    )
 8950                    .child(Label::new("Jump to Edit")),
 8951            ),
 8952
 8953            InlineCompletion::Edit {
 8954                edits,
 8955                edit_preview,
 8956                snapshot,
 8957                display_mode: _,
 8958            } => {
 8959                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8960
 8961                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8962                    &snapshot,
 8963                    &edits,
 8964                    edit_preview.as_ref()?,
 8965                    true,
 8966                    cx,
 8967                )
 8968                .first_line_preview();
 8969
 8970                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8971                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8972
 8973                let preview = h_flex()
 8974                    .gap_1()
 8975                    .min_w_16()
 8976                    .child(styled_text)
 8977                    .when(has_more_lines, |parent| parent.child(""));
 8978
 8979                let left = if first_edit_row != cursor_point.row {
 8980                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8981                        .into_any_element()
 8982                } else {
 8983                    Icon::new(IconName::ZedPredict).into_any_element()
 8984                };
 8985
 8986                Some(
 8987                    h_flex()
 8988                        .h_full()
 8989                        .flex_1()
 8990                        .gap_2()
 8991                        .pr_1()
 8992                        .overflow_x_hidden()
 8993                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8994                        .child(left)
 8995                        .child(preview),
 8996                )
 8997            }
 8998        }
 8999    }
 9000
 9001    pub fn render_context_menu(
 9002        &self,
 9003        style: &EditorStyle,
 9004        max_height_in_lines: u32,
 9005        window: &mut Window,
 9006        cx: &mut Context<Editor>,
 9007    ) -> Option<AnyElement> {
 9008        let menu = self.context_menu.borrow();
 9009        let menu = menu.as_ref()?;
 9010        if !menu.visible() {
 9011            return None;
 9012        };
 9013        Some(menu.render(style, max_height_in_lines, window, cx))
 9014    }
 9015
 9016    fn render_context_menu_aside(
 9017        &mut self,
 9018        max_size: Size<Pixels>,
 9019        window: &mut Window,
 9020        cx: &mut Context<Editor>,
 9021    ) -> Option<AnyElement> {
 9022        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9023            if menu.visible() {
 9024                menu.render_aside(max_size, window, cx)
 9025            } else {
 9026                None
 9027            }
 9028        })
 9029    }
 9030
 9031    fn hide_context_menu(
 9032        &mut self,
 9033        window: &mut Window,
 9034        cx: &mut Context<Self>,
 9035    ) -> Option<CodeContextMenu> {
 9036        cx.notify();
 9037        self.completion_tasks.clear();
 9038        let context_menu = self.context_menu.borrow_mut().take();
 9039        self.stale_inline_completion_in_menu.take();
 9040        self.update_visible_inline_completion(window, cx);
 9041        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9042            if let Some(completion_provider) = &self.completion_provider {
 9043                completion_provider.selection_changed(None, window, cx);
 9044            }
 9045        }
 9046        context_menu
 9047    }
 9048
 9049    fn show_snippet_choices(
 9050        &mut self,
 9051        choices: &Vec<String>,
 9052        selection: Range<Anchor>,
 9053        cx: &mut Context<Self>,
 9054    ) {
 9055        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9056            (Some(a), Some(b)) if a == b => a,
 9057            _ => {
 9058                log::error!("expected anchor range to have matching buffer IDs");
 9059                return;
 9060            }
 9061        };
 9062        let multi_buffer = self.buffer().read(cx);
 9063        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9064            return;
 9065        };
 9066
 9067        let id = post_inc(&mut self.next_completion_id);
 9068        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9069        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9070            CompletionsMenu::new_snippet_choices(
 9071                id,
 9072                true,
 9073                choices,
 9074                selection,
 9075                buffer,
 9076                snippet_sort_order,
 9077            ),
 9078        ));
 9079    }
 9080
 9081    pub fn insert_snippet(
 9082        &mut self,
 9083        insertion_ranges: &[Range<usize>],
 9084        snippet: Snippet,
 9085        window: &mut Window,
 9086        cx: &mut Context<Self>,
 9087    ) -> Result<()> {
 9088        struct Tabstop<T> {
 9089            is_end_tabstop: bool,
 9090            ranges: Vec<Range<T>>,
 9091            choices: Option<Vec<String>>,
 9092        }
 9093
 9094        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9095            let snippet_text: Arc<str> = snippet.text.clone().into();
 9096            let edits = insertion_ranges
 9097                .iter()
 9098                .cloned()
 9099                .map(|range| (range, snippet_text.clone()));
 9100            let autoindent_mode = AutoindentMode::Block {
 9101                original_indent_columns: Vec::new(),
 9102            };
 9103            buffer.edit(edits, Some(autoindent_mode), cx);
 9104
 9105            let snapshot = &*buffer.read(cx);
 9106            let snippet = &snippet;
 9107            snippet
 9108                .tabstops
 9109                .iter()
 9110                .map(|tabstop| {
 9111                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9112                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9113                    });
 9114                    let mut tabstop_ranges = tabstop
 9115                        .ranges
 9116                        .iter()
 9117                        .flat_map(|tabstop_range| {
 9118                            let mut delta = 0_isize;
 9119                            insertion_ranges.iter().map(move |insertion_range| {
 9120                                let insertion_start = insertion_range.start as isize + delta;
 9121                                delta +=
 9122                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9123
 9124                                let start = ((insertion_start + tabstop_range.start) as usize)
 9125                                    .min(snapshot.len());
 9126                                let end = ((insertion_start + tabstop_range.end) as usize)
 9127                                    .min(snapshot.len());
 9128                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9129                            })
 9130                        })
 9131                        .collect::<Vec<_>>();
 9132                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9133
 9134                    Tabstop {
 9135                        is_end_tabstop,
 9136                        ranges: tabstop_ranges,
 9137                        choices: tabstop.choices.clone(),
 9138                    }
 9139                })
 9140                .collect::<Vec<_>>()
 9141        });
 9142        if let Some(tabstop) = tabstops.first() {
 9143            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9144                // Reverse order so that the first range is the newest created selection.
 9145                // Completions will use it and autoscroll will prioritize it.
 9146                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9147            });
 9148
 9149            if let Some(choices) = &tabstop.choices {
 9150                if let Some(selection) = tabstop.ranges.first() {
 9151                    self.show_snippet_choices(choices, selection.clone(), cx)
 9152                }
 9153            }
 9154
 9155            // If we're already at the last tabstop and it's at the end of the snippet,
 9156            // we're done, we don't need to keep the state around.
 9157            if !tabstop.is_end_tabstop {
 9158                let choices = tabstops
 9159                    .iter()
 9160                    .map(|tabstop| tabstop.choices.clone())
 9161                    .collect();
 9162
 9163                let ranges = tabstops
 9164                    .into_iter()
 9165                    .map(|tabstop| tabstop.ranges)
 9166                    .collect::<Vec<_>>();
 9167
 9168                self.snippet_stack.push(SnippetState {
 9169                    active_index: 0,
 9170                    ranges,
 9171                    choices,
 9172                });
 9173            }
 9174
 9175            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9176            if self.autoclose_regions.is_empty() {
 9177                let snapshot = self.buffer.read(cx).snapshot(cx);
 9178                for selection in &mut self.selections.all::<Point>(cx) {
 9179                    let selection_head = selection.head();
 9180                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9181                        continue;
 9182                    };
 9183
 9184                    let mut bracket_pair = None;
 9185                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9186                    let prev_chars = snapshot
 9187                        .reversed_chars_at(selection_head)
 9188                        .collect::<String>();
 9189                    for (pair, enabled) in scope.brackets() {
 9190                        if enabled
 9191                            && pair.close
 9192                            && prev_chars.starts_with(pair.start.as_str())
 9193                            && next_chars.starts_with(pair.end.as_str())
 9194                        {
 9195                            bracket_pair = Some(pair.clone());
 9196                            break;
 9197                        }
 9198                    }
 9199                    if let Some(pair) = bracket_pair {
 9200                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9201                        let autoclose_enabled =
 9202                            self.use_autoclose && snapshot_settings.use_autoclose;
 9203                        if autoclose_enabled {
 9204                            let start = snapshot.anchor_after(selection_head);
 9205                            let end = snapshot.anchor_after(selection_head);
 9206                            self.autoclose_regions.push(AutocloseRegion {
 9207                                selection_id: selection.id,
 9208                                range: start..end,
 9209                                pair,
 9210                            });
 9211                        }
 9212                    }
 9213                }
 9214            }
 9215        }
 9216        Ok(())
 9217    }
 9218
 9219    pub fn move_to_next_snippet_tabstop(
 9220        &mut self,
 9221        window: &mut Window,
 9222        cx: &mut Context<Self>,
 9223    ) -> bool {
 9224        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9225    }
 9226
 9227    pub fn move_to_prev_snippet_tabstop(
 9228        &mut self,
 9229        window: &mut Window,
 9230        cx: &mut Context<Self>,
 9231    ) -> bool {
 9232        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9233    }
 9234
 9235    pub fn move_to_snippet_tabstop(
 9236        &mut self,
 9237        bias: Bias,
 9238        window: &mut Window,
 9239        cx: &mut Context<Self>,
 9240    ) -> bool {
 9241        if let Some(mut snippet) = self.snippet_stack.pop() {
 9242            match bias {
 9243                Bias::Left => {
 9244                    if snippet.active_index > 0 {
 9245                        snippet.active_index -= 1;
 9246                    } else {
 9247                        self.snippet_stack.push(snippet);
 9248                        return false;
 9249                    }
 9250                }
 9251                Bias::Right => {
 9252                    if snippet.active_index + 1 < snippet.ranges.len() {
 9253                        snippet.active_index += 1;
 9254                    } else {
 9255                        self.snippet_stack.push(snippet);
 9256                        return false;
 9257                    }
 9258                }
 9259            }
 9260            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9261                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9262                    // Reverse order so that the first range is the newest created selection.
 9263                    // Completions will use it and autoscroll will prioritize it.
 9264                    s.select_ranges(current_ranges.iter().rev().cloned())
 9265                });
 9266
 9267                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9268                    if let Some(selection) = current_ranges.first() {
 9269                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9270                    }
 9271                }
 9272
 9273                // If snippet state is not at the last tabstop, push it back on the stack
 9274                if snippet.active_index + 1 < snippet.ranges.len() {
 9275                    self.snippet_stack.push(snippet);
 9276                }
 9277                return true;
 9278            }
 9279        }
 9280
 9281        false
 9282    }
 9283
 9284    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9285        self.transact(window, cx, |this, window, cx| {
 9286            this.select_all(&SelectAll, window, cx);
 9287            this.insert("", window, cx);
 9288        });
 9289    }
 9290
 9291    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9292        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9293        self.transact(window, cx, |this, window, cx| {
 9294            this.select_autoclose_pair(window, cx);
 9295            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9296            if !this.linked_edit_ranges.is_empty() {
 9297                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9298                let snapshot = this.buffer.read(cx).snapshot(cx);
 9299
 9300                for selection in selections.iter() {
 9301                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9302                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9303                    if selection_start.buffer_id != selection_end.buffer_id {
 9304                        continue;
 9305                    }
 9306                    if let Some(ranges) =
 9307                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9308                    {
 9309                        for (buffer, entries) in ranges {
 9310                            linked_ranges.entry(buffer).or_default().extend(entries);
 9311                        }
 9312                    }
 9313                }
 9314            }
 9315
 9316            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9317            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9318            for selection in &mut selections {
 9319                if selection.is_empty() {
 9320                    let old_head = selection.head();
 9321                    let mut new_head =
 9322                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9323                            .to_point(&display_map);
 9324                    if let Some((buffer, line_buffer_range)) = display_map
 9325                        .buffer_snapshot
 9326                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9327                    {
 9328                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9329                        let indent_len = match indent_size.kind {
 9330                            IndentKind::Space => {
 9331                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9332                            }
 9333                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9334                        };
 9335                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9336                            let indent_len = indent_len.get();
 9337                            new_head = cmp::min(
 9338                                new_head,
 9339                                MultiBufferPoint::new(
 9340                                    old_head.row,
 9341                                    ((old_head.column - 1) / indent_len) * indent_len,
 9342                                ),
 9343                            );
 9344                        }
 9345                    }
 9346
 9347                    selection.set_head(new_head, SelectionGoal::None);
 9348                }
 9349            }
 9350
 9351            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9352                s.select(selections)
 9353            });
 9354            this.insert("", window, cx);
 9355            let empty_str: Arc<str> = Arc::from("");
 9356            for (buffer, edits) in linked_ranges {
 9357                let snapshot = buffer.read(cx).snapshot();
 9358                use text::ToPoint as TP;
 9359
 9360                let edits = edits
 9361                    .into_iter()
 9362                    .map(|range| {
 9363                        let end_point = TP::to_point(&range.end, &snapshot);
 9364                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9365
 9366                        if end_point == start_point {
 9367                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9368                                .saturating_sub(1);
 9369                            start_point =
 9370                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9371                        };
 9372
 9373                        (start_point..end_point, empty_str.clone())
 9374                    })
 9375                    .sorted_by_key(|(range, _)| range.start)
 9376                    .collect::<Vec<_>>();
 9377                buffer.update(cx, |this, cx| {
 9378                    this.edit(edits, None, cx);
 9379                })
 9380            }
 9381            this.refresh_inline_completion(true, false, window, cx);
 9382            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9383        });
 9384    }
 9385
 9386    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9387        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9388        self.transact(window, cx, |this, window, cx| {
 9389            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9390                s.move_with(|map, selection| {
 9391                    if selection.is_empty() {
 9392                        let cursor = movement::right(map, selection.head());
 9393                        selection.end = cursor;
 9394                        selection.reversed = true;
 9395                        selection.goal = SelectionGoal::None;
 9396                    }
 9397                })
 9398            });
 9399            this.insert("", window, cx);
 9400            this.refresh_inline_completion(true, false, window, cx);
 9401        });
 9402    }
 9403
 9404    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9405        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9406        if self.move_to_prev_snippet_tabstop(window, cx) {
 9407            return;
 9408        }
 9409        self.outdent(&Outdent, window, cx);
 9410    }
 9411
 9412    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9413        if self.move_to_next_snippet_tabstop(window, cx) {
 9414            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9415            return;
 9416        }
 9417        if self.read_only(cx) {
 9418            return;
 9419        }
 9420        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9421        let mut selections = self.selections.all_adjusted(cx);
 9422        let buffer = self.buffer.read(cx);
 9423        let snapshot = buffer.snapshot(cx);
 9424        let rows_iter = selections.iter().map(|s| s.head().row);
 9425        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9426
 9427        let has_some_cursor_in_whitespace = selections
 9428            .iter()
 9429            .filter(|selection| selection.is_empty())
 9430            .any(|selection| {
 9431                let cursor = selection.head();
 9432                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9433                cursor.column < current_indent.len
 9434            });
 9435
 9436        let mut edits = Vec::new();
 9437        let mut prev_edited_row = 0;
 9438        let mut row_delta = 0;
 9439        for selection in &mut selections {
 9440            if selection.start.row != prev_edited_row {
 9441                row_delta = 0;
 9442            }
 9443            prev_edited_row = selection.end.row;
 9444
 9445            // If the selection is non-empty, then increase the indentation of the selected lines.
 9446            if !selection.is_empty() {
 9447                row_delta =
 9448                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9449                continue;
 9450            }
 9451
 9452            let cursor = selection.head();
 9453            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9454            if let Some(suggested_indent) =
 9455                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9456            {
 9457                // Don't do anything if already at suggested indent
 9458                // and there is any other cursor which is not
 9459                if has_some_cursor_in_whitespace
 9460                    && cursor.column == current_indent.len
 9461                    && current_indent.len == suggested_indent.len
 9462                {
 9463                    continue;
 9464                }
 9465
 9466                // Adjust line and move cursor to suggested indent
 9467                // if cursor is not at suggested indent
 9468                if cursor.column < suggested_indent.len
 9469                    && cursor.column <= current_indent.len
 9470                    && current_indent.len <= suggested_indent.len
 9471                {
 9472                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9473                    selection.end = selection.start;
 9474                    if row_delta == 0 {
 9475                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9476                            cursor.row,
 9477                            current_indent,
 9478                            suggested_indent,
 9479                        ));
 9480                        row_delta = suggested_indent.len - current_indent.len;
 9481                    }
 9482                    continue;
 9483                }
 9484
 9485                // If current indent is more than suggested indent
 9486                // only move cursor to current indent and skip indent
 9487                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9488                    selection.start = Point::new(cursor.row, current_indent.len);
 9489                    selection.end = selection.start;
 9490                    continue;
 9491                }
 9492            }
 9493
 9494            // Otherwise, insert a hard or soft tab.
 9495            let settings = buffer.language_settings_at(cursor, cx);
 9496            let tab_size = if settings.hard_tabs {
 9497                IndentSize::tab()
 9498            } else {
 9499                let tab_size = settings.tab_size.get();
 9500                let indent_remainder = snapshot
 9501                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9502                    .flat_map(str::chars)
 9503                    .fold(row_delta % tab_size, |counter: u32, c| {
 9504                        if c == '\t' {
 9505                            0
 9506                        } else {
 9507                            (counter + 1) % tab_size
 9508                        }
 9509                    });
 9510
 9511                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9512                IndentSize::spaces(chars_to_next_tab_stop)
 9513            };
 9514            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9515            selection.end = selection.start;
 9516            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9517            row_delta += tab_size.len;
 9518        }
 9519
 9520        self.transact(window, cx, |this, window, cx| {
 9521            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9522            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9523                s.select(selections)
 9524            });
 9525            this.refresh_inline_completion(true, false, window, cx);
 9526        });
 9527    }
 9528
 9529    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9530        if self.read_only(cx) {
 9531            return;
 9532        }
 9533        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9534        let mut selections = self.selections.all::<Point>(cx);
 9535        let mut prev_edited_row = 0;
 9536        let mut row_delta = 0;
 9537        let mut edits = Vec::new();
 9538        let buffer = self.buffer.read(cx);
 9539        let snapshot = buffer.snapshot(cx);
 9540        for selection in &mut selections {
 9541            if selection.start.row != prev_edited_row {
 9542                row_delta = 0;
 9543            }
 9544            prev_edited_row = selection.end.row;
 9545
 9546            row_delta =
 9547                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9548        }
 9549
 9550        self.transact(window, cx, |this, window, cx| {
 9551            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9552            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9553                s.select(selections)
 9554            });
 9555        });
 9556    }
 9557
 9558    fn indent_selection(
 9559        buffer: &MultiBuffer,
 9560        snapshot: &MultiBufferSnapshot,
 9561        selection: &mut Selection<Point>,
 9562        edits: &mut Vec<(Range<Point>, String)>,
 9563        delta_for_start_row: u32,
 9564        cx: &App,
 9565    ) -> u32 {
 9566        let settings = buffer.language_settings_at(selection.start, cx);
 9567        let tab_size = settings.tab_size.get();
 9568        let indent_kind = if settings.hard_tabs {
 9569            IndentKind::Tab
 9570        } else {
 9571            IndentKind::Space
 9572        };
 9573        let mut start_row = selection.start.row;
 9574        let mut end_row = selection.end.row + 1;
 9575
 9576        // If a selection ends at the beginning of a line, don't indent
 9577        // that last line.
 9578        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9579            end_row -= 1;
 9580        }
 9581
 9582        // Avoid re-indenting a row that has already been indented by a
 9583        // previous selection, but still update this selection's column
 9584        // to reflect that indentation.
 9585        if delta_for_start_row > 0 {
 9586            start_row += 1;
 9587            selection.start.column += delta_for_start_row;
 9588            if selection.end.row == selection.start.row {
 9589                selection.end.column += delta_for_start_row;
 9590            }
 9591        }
 9592
 9593        let mut delta_for_end_row = 0;
 9594        let has_multiple_rows = start_row + 1 != end_row;
 9595        for row in start_row..end_row {
 9596            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9597            let indent_delta = match (current_indent.kind, indent_kind) {
 9598                (IndentKind::Space, IndentKind::Space) => {
 9599                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9600                    IndentSize::spaces(columns_to_next_tab_stop)
 9601                }
 9602                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9603                (_, IndentKind::Tab) => IndentSize::tab(),
 9604            };
 9605
 9606            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9607                0
 9608            } else {
 9609                selection.start.column
 9610            };
 9611            let row_start = Point::new(row, start);
 9612            edits.push((
 9613                row_start..row_start,
 9614                indent_delta.chars().collect::<String>(),
 9615            ));
 9616
 9617            // Update this selection's endpoints to reflect the indentation.
 9618            if row == selection.start.row {
 9619                selection.start.column += indent_delta.len;
 9620            }
 9621            if row == selection.end.row {
 9622                selection.end.column += indent_delta.len;
 9623                delta_for_end_row = indent_delta.len;
 9624            }
 9625        }
 9626
 9627        if selection.start.row == selection.end.row {
 9628            delta_for_start_row + delta_for_end_row
 9629        } else {
 9630            delta_for_end_row
 9631        }
 9632    }
 9633
 9634    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9635        if self.read_only(cx) {
 9636            return;
 9637        }
 9638        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9639        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9640        let selections = self.selections.all::<Point>(cx);
 9641        let mut deletion_ranges = Vec::new();
 9642        let mut last_outdent = None;
 9643        {
 9644            let buffer = self.buffer.read(cx);
 9645            let snapshot = buffer.snapshot(cx);
 9646            for selection in &selections {
 9647                let settings = buffer.language_settings_at(selection.start, cx);
 9648                let tab_size = settings.tab_size.get();
 9649                let mut rows = selection.spanned_rows(false, &display_map);
 9650
 9651                // Avoid re-outdenting a row that has already been outdented by a
 9652                // previous selection.
 9653                if let Some(last_row) = last_outdent {
 9654                    if last_row == rows.start {
 9655                        rows.start = rows.start.next_row();
 9656                    }
 9657                }
 9658                let has_multiple_rows = rows.len() > 1;
 9659                for row in rows.iter_rows() {
 9660                    let indent_size = snapshot.indent_size_for_line(row);
 9661                    if indent_size.len > 0 {
 9662                        let deletion_len = match indent_size.kind {
 9663                            IndentKind::Space => {
 9664                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9665                                if columns_to_prev_tab_stop == 0 {
 9666                                    tab_size
 9667                                } else {
 9668                                    columns_to_prev_tab_stop
 9669                                }
 9670                            }
 9671                            IndentKind::Tab => 1,
 9672                        };
 9673                        let start = if has_multiple_rows
 9674                            || deletion_len > selection.start.column
 9675                            || indent_size.len < selection.start.column
 9676                        {
 9677                            0
 9678                        } else {
 9679                            selection.start.column - deletion_len
 9680                        };
 9681                        deletion_ranges.push(
 9682                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9683                        );
 9684                        last_outdent = Some(row);
 9685                    }
 9686                }
 9687            }
 9688        }
 9689
 9690        self.transact(window, cx, |this, window, cx| {
 9691            this.buffer.update(cx, |buffer, cx| {
 9692                let empty_str: Arc<str> = Arc::default();
 9693                buffer.edit(
 9694                    deletion_ranges
 9695                        .into_iter()
 9696                        .map(|range| (range, empty_str.clone())),
 9697                    None,
 9698                    cx,
 9699                );
 9700            });
 9701            let selections = this.selections.all::<usize>(cx);
 9702            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9703                s.select(selections)
 9704            });
 9705        });
 9706    }
 9707
 9708    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9709        if self.read_only(cx) {
 9710            return;
 9711        }
 9712        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9713        let selections = self
 9714            .selections
 9715            .all::<usize>(cx)
 9716            .into_iter()
 9717            .map(|s| s.range());
 9718
 9719        self.transact(window, cx, |this, window, cx| {
 9720            this.buffer.update(cx, |buffer, cx| {
 9721                buffer.autoindent_ranges(selections, cx);
 9722            });
 9723            let selections = this.selections.all::<usize>(cx);
 9724            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9725                s.select(selections)
 9726            });
 9727        });
 9728    }
 9729
 9730    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9731        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9732        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9733        let selections = self.selections.all::<Point>(cx);
 9734
 9735        let mut new_cursors = Vec::new();
 9736        let mut edit_ranges = Vec::new();
 9737        let mut selections = selections.iter().peekable();
 9738        while let Some(selection) = selections.next() {
 9739            let mut rows = selection.spanned_rows(false, &display_map);
 9740            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9741
 9742            // Accumulate contiguous regions of rows that we want to delete.
 9743            while let Some(next_selection) = selections.peek() {
 9744                let next_rows = next_selection.spanned_rows(false, &display_map);
 9745                if next_rows.start <= rows.end {
 9746                    rows.end = next_rows.end;
 9747                    selections.next().unwrap();
 9748                } else {
 9749                    break;
 9750                }
 9751            }
 9752
 9753            let buffer = &display_map.buffer_snapshot;
 9754            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9755            let edit_end;
 9756            let cursor_buffer_row;
 9757            if buffer.max_point().row >= rows.end.0 {
 9758                // If there's a line after the range, delete the \n from the end of the row range
 9759                // and position the cursor on the next line.
 9760                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9761                cursor_buffer_row = rows.end;
 9762            } else {
 9763                // If there isn't a line after the range, delete the \n from the line before the
 9764                // start of the row range and position the cursor there.
 9765                edit_start = edit_start.saturating_sub(1);
 9766                edit_end = buffer.len();
 9767                cursor_buffer_row = rows.start.previous_row();
 9768            }
 9769
 9770            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9771            *cursor.column_mut() =
 9772                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9773
 9774            new_cursors.push((
 9775                selection.id,
 9776                buffer.anchor_after(cursor.to_point(&display_map)),
 9777            ));
 9778            edit_ranges.push(edit_start..edit_end);
 9779        }
 9780
 9781        self.transact(window, cx, |this, window, cx| {
 9782            let buffer = this.buffer.update(cx, |buffer, cx| {
 9783                let empty_str: Arc<str> = Arc::default();
 9784                buffer.edit(
 9785                    edit_ranges
 9786                        .into_iter()
 9787                        .map(|range| (range, empty_str.clone())),
 9788                    None,
 9789                    cx,
 9790                );
 9791                buffer.snapshot(cx)
 9792            });
 9793            let new_selections = new_cursors
 9794                .into_iter()
 9795                .map(|(id, cursor)| {
 9796                    let cursor = cursor.to_point(&buffer);
 9797                    Selection {
 9798                        id,
 9799                        start: cursor,
 9800                        end: cursor,
 9801                        reversed: false,
 9802                        goal: SelectionGoal::None,
 9803                    }
 9804                })
 9805                .collect();
 9806
 9807            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9808                s.select(new_selections);
 9809            });
 9810        });
 9811    }
 9812
 9813    pub fn join_lines_impl(
 9814        &mut self,
 9815        insert_whitespace: bool,
 9816        window: &mut Window,
 9817        cx: &mut Context<Self>,
 9818    ) {
 9819        if self.read_only(cx) {
 9820            return;
 9821        }
 9822        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9823        for selection in self.selections.all::<Point>(cx) {
 9824            let start = MultiBufferRow(selection.start.row);
 9825            // Treat single line selections as if they include the next line. Otherwise this action
 9826            // would do nothing for single line selections individual cursors.
 9827            let end = if selection.start.row == selection.end.row {
 9828                MultiBufferRow(selection.start.row + 1)
 9829            } else {
 9830                MultiBufferRow(selection.end.row)
 9831            };
 9832
 9833            if let Some(last_row_range) = row_ranges.last_mut() {
 9834                if start <= last_row_range.end {
 9835                    last_row_range.end = end;
 9836                    continue;
 9837                }
 9838            }
 9839            row_ranges.push(start..end);
 9840        }
 9841
 9842        let snapshot = self.buffer.read(cx).snapshot(cx);
 9843        let mut cursor_positions = Vec::new();
 9844        for row_range in &row_ranges {
 9845            let anchor = snapshot.anchor_before(Point::new(
 9846                row_range.end.previous_row().0,
 9847                snapshot.line_len(row_range.end.previous_row()),
 9848            ));
 9849            cursor_positions.push(anchor..anchor);
 9850        }
 9851
 9852        self.transact(window, cx, |this, window, cx| {
 9853            for row_range in row_ranges.into_iter().rev() {
 9854                for row in row_range.iter_rows().rev() {
 9855                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9856                    let next_line_row = row.next_row();
 9857                    let indent = snapshot.indent_size_for_line(next_line_row);
 9858                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9859
 9860                    let replace =
 9861                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9862                            " "
 9863                        } else {
 9864                            ""
 9865                        };
 9866
 9867                    this.buffer.update(cx, |buffer, cx| {
 9868                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9869                    });
 9870                }
 9871            }
 9872
 9873            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9874                s.select_anchor_ranges(cursor_positions)
 9875            });
 9876        });
 9877    }
 9878
 9879    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9880        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9881        self.join_lines_impl(true, window, cx);
 9882    }
 9883
 9884    pub fn sort_lines_case_sensitive(
 9885        &mut self,
 9886        _: &SortLinesCaseSensitive,
 9887        window: &mut Window,
 9888        cx: &mut Context<Self>,
 9889    ) {
 9890        self.manipulate_lines(window, cx, |lines| lines.sort())
 9891    }
 9892
 9893    pub fn sort_lines_case_insensitive(
 9894        &mut self,
 9895        _: &SortLinesCaseInsensitive,
 9896        window: &mut Window,
 9897        cx: &mut Context<Self>,
 9898    ) {
 9899        self.manipulate_lines(window, cx, |lines| {
 9900            lines.sort_by_key(|line| line.to_lowercase())
 9901        })
 9902    }
 9903
 9904    pub fn unique_lines_case_insensitive(
 9905        &mut self,
 9906        _: &UniqueLinesCaseInsensitive,
 9907        window: &mut Window,
 9908        cx: &mut Context<Self>,
 9909    ) {
 9910        self.manipulate_lines(window, cx, |lines| {
 9911            let mut seen = HashSet::default();
 9912            lines.retain(|line| seen.insert(line.to_lowercase()));
 9913        })
 9914    }
 9915
 9916    pub fn unique_lines_case_sensitive(
 9917        &mut self,
 9918        _: &UniqueLinesCaseSensitive,
 9919        window: &mut Window,
 9920        cx: &mut Context<Self>,
 9921    ) {
 9922        self.manipulate_lines(window, cx, |lines| {
 9923            let mut seen = HashSet::default();
 9924            lines.retain(|line| seen.insert(*line));
 9925        })
 9926    }
 9927
 9928    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9929        let Some(project) = self.project.clone() else {
 9930            return;
 9931        };
 9932        self.reload(project, window, cx)
 9933            .detach_and_notify_err(window, cx);
 9934    }
 9935
 9936    pub fn restore_file(
 9937        &mut self,
 9938        _: &::git::RestoreFile,
 9939        window: &mut Window,
 9940        cx: &mut Context<Self>,
 9941    ) {
 9942        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9943        let mut buffer_ids = HashSet::default();
 9944        let snapshot = self.buffer().read(cx).snapshot(cx);
 9945        for selection in self.selections.all::<usize>(cx) {
 9946            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9947        }
 9948
 9949        let buffer = self.buffer().read(cx);
 9950        let ranges = buffer_ids
 9951            .into_iter()
 9952            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9953            .collect::<Vec<_>>();
 9954
 9955        self.restore_hunks_in_ranges(ranges, window, cx);
 9956    }
 9957
 9958    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9959        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9960        let selections = self
 9961            .selections
 9962            .all(cx)
 9963            .into_iter()
 9964            .map(|s| s.range())
 9965            .collect();
 9966        self.restore_hunks_in_ranges(selections, window, cx);
 9967    }
 9968
 9969    pub fn restore_hunks_in_ranges(
 9970        &mut self,
 9971        ranges: Vec<Range<Point>>,
 9972        window: &mut Window,
 9973        cx: &mut Context<Editor>,
 9974    ) {
 9975        let mut revert_changes = HashMap::default();
 9976        let chunk_by = self
 9977            .snapshot(window, cx)
 9978            .hunks_for_ranges(ranges)
 9979            .into_iter()
 9980            .chunk_by(|hunk| hunk.buffer_id);
 9981        for (buffer_id, hunks) in &chunk_by {
 9982            let hunks = hunks.collect::<Vec<_>>();
 9983            for hunk in &hunks {
 9984                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9985            }
 9986            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9987        }
 9988        drop(chunk_by);
 9989        if !revert_changes.is_empty() {
 9990            self.transact(window, cx, |editor, window, cx| {
 9991                editor.restore(revert_changes, window, cx);
 9992            });
 9993        }
 9994    }
 9995
 9996    pub fn open_active_item_in_terminal(
 9997        &mut self,
 9998        _: &OpenInTerminal,
 9999        window: &mut Window,
10000        cx: &mut Context<Self>,
10001    ) {
10002        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10003            let project_path = buffer.read(cx).project_path(cx)?;
10004            let project = self.project.as_ref()?.read(cx);
10005            let entry = project.entry_for_path(&project_path, cx)?;
10006            let parent = match &entry.canonical_path {
10007                Some(canonical_path) => canonical_path.to_path_buf(),
10008                None => project.absolute_path(&project_path, cx)?,
10009            }
10010            .parent()?
10011            .to_path_buf();
10012            Some(parent)
10013        }) {
10014            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10015        }
10016    }
10017
10018    fn set_breakpoint_context_menu(
10019        &mut self,
10020        display_row: DisplayRow,
10021        position: Option<Anchor>,
10022        clicked_point: gpui::Point<Pixels>,
10023        window: &mut Window,
10024        cx: &mut Context<Self>,
10025    ) {
10026        if !cx.has_flag::<DebuggerFeatureFlag>() {
10027            return;
10028        }
10029        let source = self
10030            .buffer
10031            .read(cx)
10032            .snapshot(cx)
10033            .anchor_before(Point::new(display_row.0, 0u32));
10034
10035        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10036
10037        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10038            self,
10039            source,
10040            clicked_point,
10041            context_menu,
10042            window,
10043            cx,
10044        );
10045    }
10046
10047    fn add_edit_breakpoint_block(
10048        &mut self,
10049        anchor: Anchor,
10050        breakpoint: &Breakpoint,
10051        edit_action: BreakpointPromptEditAction,
10052        window: &mut Window,
10053        cx: &mut Context<Self>,
10054    ) {
10055        let weak_editor = cx.weak_entity();
10056        let bp_prompt = cx.new(|cx| {
10057            BreakpointPromptEditor::new(
10058                weak_editor,
10059                anchor,
10060                breakpoint.clone(),
10061                edit_action,
10062                window,
10063                cx,
10064            )
10065        });
10066
10067        let height = bp_prompt.update(cx, |this, cx| {
10068            this.prompt
10069                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10070        });
10071        let cloned_prompt = bp_prompt.clone();
10072        let blocks = vec![BlockProperties {
10073            style: BlockStyle::Sticky,
10074            placement: BlockPlacement::Above(anchor),
10075            height: Some(height),
10076            render: Arc::new(move |cx| {
10077                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10078                cloned_prompt.clone().into_any_element()
10079            }),
10080            priority: 0,
10081            render_in_minimap: true,
10082        }];
10083
10084        let focus_handle = bp_prompt.focus_handle(cx);
10085        window.focus(&focus_handle);
10086
10087        let block_ids = self.insert_blocks(blocks, None, cx);
10088        bp_prompt.update(cx, |prompt, _| {
10089            prompt.add_block_ids(block_ids);
10090        });
10091    }
10092
10093    pub(crate) fn breakpoint_at_row(
10094        &self,
10095        row: u32,
10096        window: &mut Window,
10097        cx: &mut Context<Self>,
10098    ) -> Option<(Anchor, Breakpoint)> {
10099        let snapshot = self.snapshot(window, cx);
10100        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10101
10102        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10103    }
10104
10105    pub(crate) fn breakpoint_at_anchor(
10106        &self,
10107        breakpoint_position: Anchor,
10108        snapshot: &EditorSnapshot,
10109        cx: &mut Context<Self>,
10110    ) -> Option<(Anchor, Breakpoint)> {
10111        let project = self.project.clone()?;
10112
10113        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10114            snapshot
10115                .buffer_snapshot
10116                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10117        })?;
10118
10119        let enclosing_excerpt = breakpoint_position.excerpt_id;
10120        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10121        let buffer_snapshot = buffer.read(cx).snapshot();
10122
10123        let row = buffer_snapshot
10124            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10125            .row;
10126
10127        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10128        let anchor_end = snapshot
10129            .buffer_snapshot
10130            .anchor_after(Point::new(row, line_len));
10131
10132        let bp = self
10133            .breakpoint_store
10134            .as_ref()?
10135            .read_with(cx, |breakpoint_store, cx| {
10136                breakpoint_store
10137                    .breakpoints(
10138                        &buffer,
10139                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10140                        &buffer_snapshot,
10141                        cx,
10142                    )
10143                    .next()
10144                    .and_then(|(bp, _)| {
10145                        let breakpoint_row = buffer_snapshot
10146                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10147                            .row;
10148
10149                        if breakpoint_row == row {
10150                            snapshot
10151                                .buffer_snapshot
10152                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10153                                .map(|position| (position, bp.bp.clone()))
10154                        } else {
10155                            None
10156                        }
10157                    })
10158            });
10159        bp
10160    }
10161
10162    pub fn edit_log_breakpoint(
10163        &mut self,
10164        _: &EditLogBreakpoint,
10165        window: &mut Window,
10166        cx: &mut Context<Self>,
10167    ) {
10168        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10169            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10170                message: None,
10171                state: BreakpointState::Enabled,
10172                condition: None,
10173                hit_condition: None,
10174            });
10175
10176            self.add_edit_breakpoint_block(
10177                anchor,
10178                &breakpoint,
10179                BreakpointPromptEditAction::Log,
10180                window,
10181                cx,
10182            );
10183        }
10184    }
10185
10186    fn breakpoints_at_cursors(
10187        &self,
10188        window: &mut Window,
10189        cx: &mut Context<Self>,
10190    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10191        let snapshot = self.snapshot(window, cx);
10192        let cursors = self
10193            .selections
10194            .disjoint_anchors()
10195            .into_iter()
10196            .map(|selection| {
10197                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10198
10199                let breakpoint_position = self
10200                    .breakpoint_at_row(cursor_position.row, window, cx)
10201                    .map(|bp| bp.0)
10202                    .unwrap_or_else(|| {
10203                        snapshot
10204                            .display_snapshot
10205                            .buffer_snapshot
10206                            .anchor_after(Point::new(cursor_position.row, 0))
10207                    });
10208
10209                let breakpoint = self
10210                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10211                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10212
10213                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10214            })
10215            // 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.
10216            .collect::<HashMap<Anchor, _>>();
10217
10218        cursors.into_iter().collect()
10219    }
10220
10221    pub fn enable_breakpoint(
10222        &mut self,
10223        _: &crate::actions::EnableBreakpoint,
10224        window: &mut Window,
10225        cx: &mut Context<Self>,
10226    ) {
10227        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10228            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10229                continue;
10230            };
10231            self.edit_breakpoint_at_anchor(
10232                anchor,
10233                breakpoint,
10234                BreakpointEditAction::InvertState,
10235                cx,
10236            );
10237        }
10238    }
10239
10240    pub fn disable_breakpoint(
10241        &mut self,
10242        _: &crate::actions::DisableBreakpoint,
10243        window: &mut Window,
10244        cx: &mut Context<Self>,
10245    ) {
10246        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10247            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10248                continue;
10249            };
10250            self.edit_breakpoint_at_anchor(
10251                anchor,
10252                breakpoint,
10253                BreakpointEditAction::InvertState,
10254                cx,
10255            );
10256        }
10257    }
10258
10259    pub fn toggle_breakpoint(
10260        &mut self,
10261        _: &crate::actions::ToggleBreakpoint,
10262        window: &mut Window,
10263        cx: &mut Context<Self>,
10264    ) {
10265        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10266            if let Some(breakpoint) = breakpoint {
10267                self.edit_breakpoint_at_anchor(
10268                    anchor,
10269                    breakpoint,
10270                    BreakpointEditAction::Toggle,
10271                    cx,
10272                );
10273            } else {
10274                self.edit_breakpoint_at_anchor(
10275                    anchor,
10276                    Breakpoint::new_standard(),
10277                    BreakpointEditAction::Toggle,
10278                    cx,
10279                );
10280            }
10281        }
10282    }
10283
10284    pub fn edit_breakpoint_at_anchor(
10285        &mut self,
10286        breakpoint_position: Anchor,
10287        breakpoint: Breakpoint,
10288        edit_action: BreakpointEditAction,
10289        cx: &mut Context<Self>,
10290    ) {
10291        let Some(breakpoint_store) = &self.breakpoint_store else {
10292            return;
10293        };
10294
10295        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10296            if breakpoint_position == Anchor::min() {
10297                self.buffer()
10298                    .read(cx)
10299                    .excerpt_buffer_ids()
10300                    .into_iter()
10301                    .next()
10302            } else {
10303                None
10304            }
10305        }) else {
10306            return;
10307        };
10308
10309        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10310            return;
10311        };
10312
10313        breakpoint_store.update(cx, |breakpoint_store, cx| {
10314            breakpoint_store.toggle_breakpoint(
10315                buffer,
10316                BreakpointWithPosition {
10317                    position: breakpoint_position.text_anchor,
10318                    bp: breakpoint,
10319                },
10320                edit_action,
10321                cx,
10322            );
10323        });
10324
10325        cx.notify();
10326    }
10327
10328    #[cfg(any(test, feature = "test-support"))]
10329    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10330        self.breakpoint_store.clone()
10331    }
10332
10333    pub fn prepare_restore_change(
10334        &self,
10335        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10336        hunk: &MultiBufferDiffHunk,
10337        cx: &mut App,
10338    ) -> Option<()> {
10339        if hunk.is_created_file() {
10340            return None;
10341        }
10342        let buffer = self.buffer.read(cx);
10343        let diff = buffer.diff_for(hunk.buffer_id)?;
10344        let buffer = buffer.buffer(hunk.buffer_id)?;
10345        let buffer = buffer.read(cx);
10346        let original_text = diff
10347            .read(cx)
10348            .base_text()
10349            .as_rope()
10350            .slice(hunk.diff_base_byte_range.clone());
10351        let buffer_snapshot = buffer.snapshot();
10352        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10353        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10354            probe
10355                .0
10356                .start
10357                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10358                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10359        }) {
10360            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10361            Some(())
10362        } else {
10363            None
10364        }
10365    }
10366
10367    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10368        self.manipulate_lines(window, cx, |lines| lines.reverse())
10369    }
10370
10371    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10372        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10373    }
10374
10375    fn manipulate_lines<Fn>(
10376        &mut self,
10377        window: &mut Window,
10378        cx: &mut Context<Self>,
10379        mut callback: Fn,
10380    ) where
10381        Fn: FnMut(&mut Vec<&str>),
10382    {
10383        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10384
10385        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10386        let buffer = self.buffer.read(cx).snapshot(cx);
10387
10388        let mut edits = Vec::new();
10389
10390        let selections = self.selections.all::<Point>(cx);
10391        let mut selections = selections.iter().peekable();
10392        let mut contiguous_row_selections = Vec::new();
10393        let mut new_selections = Vec::new();
10394        let mut added_lines = 0;
10395        let mut removed_lines = 0;
10396
10397        while let Some(selection) = selections.next() {
10398            let (start_row, end_row) = consume_contiguous_rows(
10399                &mut contiguous_row_selections,
10400                selection,
10401                &display_map,
10402                &mut selections,
10403            );
10404
10405            let start_point = Point::new(start_row.0, 0);
10406            let end_point = Point::new(
10407                end_row.previous_row().0,
10408                buffer.line_len(end_row.previous_row()),
10409            );
10410            let text = buffer
10411                .text_for_range(start_point..end_point)
10412                .collect::<String>();
10413
10414            let mut lines = text.split('\n').collect_vec();
10415
10416            let lines_before = lines.len();
10417            callback(&mut lines);
10418            let lines_after = lines.len();
10419
10420            edits.push((start_point..end_point, lines.join("\n")));
10421
10422            // Selections must change based on added and removed line count
10423            let start_row =
10424                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10425            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10426            new_selections.push(Selection {
10427                id: selection.id,
10428                start: start_row,
10429                end: end_row,
10430                goal: SelectionGoal::None,
10431                reversed: selection.reversed,
10432            });
10433
10434            if lines_after > lines_before {
10435                added_lines += lines_after - lines_before;
10436            } else if lines_before > lines_after {
10437                removed_lines += lines_before - lines_after;
10438            }
10439        }
10440
10441        self.transact(window, cx, |this, window, cx| {
10442            let buffer = this.buffer.update(cx, |buffer, cx| {
10443                buffer.edit(edits, None, cx);
10444                buffer.snapshot(cx)
10445            });
10446
10447            // Recalculate offsets on newly edited buffer
10448            let new_selections = new_selections
10449                .iter()
10450                .map(|s| {
10451                    let start_point = Point::new(s.start.0, 0);
10452                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10453                    Selection {
10454                        id: s.id,
10455                        start: buffer.point_to_offset(start_point),
10456                        end: buffer.point_to_offset(end_point),
10457                        goal: s.goal,
10458                        reversed: s.reversed,
10459                    }
10460                })
10461                .collect();
10462
10463            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10464                s.select(new_selections);
10465            });
10466
10467            this.request_autoscroll(Autoscroll::fit(), cx);
10468        });
10469    }
10470
10471    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10472        self.manipulate_text(window, cx, |text| {
10473            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10474            if has_upper_case_characters {
10475                text.to_lowercase()
10476            } else {
10477                text.to_uppercase()
10478            }
10479        })
10480    }
10481
10482    pub fn convert_to_upper_case(
10483        &mut self,
10484        _: &ConvertToUpperCase,
10485        window: &mut Window,
10486        cx: &mut Context<Self>,
10487    ) {
10488        self.manipulate_text(window, cx, |text| text.to_uppercase())
10489    }
10490
10491    pub fn convert_to_lower_case(
10492        &mut self,
10493        _: &ConvertToLowerCase,
10494        window: &mut Window,
10495        cx: &mut Context<Self>,
10496    ) {
10497        self.manipulate_text(window, cx, |text| text.to_lowercase())
10498    }
10499
10500    pub fn convert_to_title_case(
10501        &mut self,
10502        _: &ConvertToTitleCase,
10503        window: &mut Window,
10504        cx: &mut Context<Self>,
10505    ) {
10506        self.manipulate_text(window, cx, |text| {
10507            text.split('\n')
10508                .map(|line| line.to_case(Case::Title))
10509                .join("\n")
10510        })
10511    }
10512
10513    pub fn convert_to_snake_case(
10514        &mut self,
10515        _: &ConvertToSnakeCase,
10516        window: &mut Window,
10517        cx: &mut Context<Self>,
10518    ) {
10519        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10520    }
10521
10522    pub fn convert_to_kebab_case(
10523        &mut self,
10524        _: &ConvertToKebabCase,
10525        window: &mut Window,
10526        cx: &mut Context<Self>,
10527    ) {
10528        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10529    }
10530
10531    pub fn convert_to_upper_camel_case(
10532        &mut self,
10533        _: &ConvertToUpperCamelCase,
10534        window: &mut Window,
10535        cx: &mut Context<Self>,
10536    ) {
10537        self.manipulate_text(window, cx, |text| {
10538            text.split('\n')
10539                .map(|line| line.to_case(Case::UpperCamel))
10540                .join("\n")
10541        })
10542    }
10543
10544    pub fn convert_to_lower_camel_case(
10545        &mut self,
10546        _: &ConvertToLowerCamelCase,
10547        window: &mut Window,
10548        cx: &mut Context<Self>,
10549    ) {
10550        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10551    }
10552
10553    pub fn convert_to_opposite_case(
10554        &mut self,
10555        _: &ConvertToOppositeCase,
10556        window: &mut Window,
10557        cx: &mut Context<Self>,
10558    ) {
10559        self.manipulate_text(window, cx, |text| {
10560            text.chars()
10561                .fold(String::with_capacity(text.len()), |mut t, c| {
10562                    if c.is_uppercase() {
10563                        t.extend(c.to_lowercase());
10564                    } else {
10565                        t.extend(c.to_uppercase());
10566                    }
10567                    t
10568                })
10569        })
10570    }
10571
10572    pub fn convert_to_rot13(
10573        &mut self,
10574        _: &ConvertToRot13,
10575        window: &mut Window,
10576        cx: &mut Context<Self>,
10577    ) {
10578        self.manipulate_text(window, cx, |text| {
10579            text.chars()
10580                .map(|c| match c {
10581                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10582                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10583                    _ => c,
10584                })
10585                .collect()
10586        })
10587    }
10588
10589    pub fn convert_to_rot47(
10590        &mut self,
10591        _: &ConvertToRot47,
10592        window: &mut Window,
10593        cx: &mut Context<Self>,
10594    ) {
10595        self.manipulate_text(window, cx, |text| {
10596            text.chars()
10597                .map(|c| {
10598                    let code_point = c as u32;
10599                    if code_point >= 33 && code_point <= 126 {
10600                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10601                    }
10602                    c
10603                })
10604                .collect()
10605        })
10606    }
10607
10608    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10609    where
10610        Fn: FnMut(&str) -> String,
10611    {
10612        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10613        let buffer = self.buffer.read(cx).snapshot(cx);
10614
10615        let mut new_selections = Vec::new();
10616        let mut edits = Vec::new();
10617        let mut selection_adjustment = 0i32;
10618
10619        for selection in self.selections.all::<usize>(cx) {
10620            let selection_is_empty = selection.is_empty();
10621
10622            let (start, end) = if selection_is_empty {
10623                let word_range = movement::surrounding_word(
10624                    &display_map,
10625                    selection.start.to_display_point(&display_map),
10626                );
10627                let start = word_range.start.to_offset(&display_map, Bias::Left);
10628                let end = word_range.end.to_offset(&display_map, Bias::Left);
10629                (start, end)
10630            } else {
10631                (selection.start, selection.end)
10632            };
10633
10634            let text = buffer.text_for_range(start..end).collect::<String>();
10635            let old_length = text.len() as i32;
10636            let text = callback(&text);
10637
10638            new_selections.push(Selection {
10639                start: (start as i32 - selection_adjustment) as usize,
10640                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10641                goal: SelectionGoal::None,
10642                ..selection
10643            });
10644
10645            selection_adjustment += old_length - text.len() as i32;
10646
10647            edits.push((start..end, text));
10648        }
10649
10650        self.transact(window, cx, |this, window, cx| {
10651            this.buffer.update(cx, |buffer, cx| {
10652                buffer.edit(edits, None, cx);
10653            });
10654
10655            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10656                s.select(new_selections);
10657            });
10658
10659            this.request_autoscroll(Autoscroll::fit(), cx);
10660        });
10661    }
10662
10663    pub fn move_selection_on_drop(
10664        &mut self,
10665        selection: &Selection<Anchor>,
10666        target: DisplayPoint,
10667        is_cut: bool,
10668        window: &mut Window,
10669        cx: &mut Context<Self>,
10670    ) {
10671        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10672        let buffer = &display_map.buffer_snapshot;
10673        let mut edits = Vec::new();
10674        let insert_point = display_map
10675            .clip_point(target, Bias::Left)
10676            .to_point(&display_map);
10677        let text = buffer
10678            .text_for_range(selection.start..selection.end)
10679            .collect::<String>();
10680        if is_cut {
10681            edits.push(((selection.start..selection.end), String::new()));
10682        }
10683        let insert_anchor = buffer.anchor_before(insert_point);
10684        edits.push(((insert_anchor..insert_anchor), text));
10685        let last_edit_start = insert_anchor.bias_left(buffer);
10686        let last_edit_end = insert_anchor.bias_right(buffer);
10687        self.transact(window, cx, |this, window, cx| {
10688            this.buffer.update(cx, |buffer, cx| {
10689                buffer.edit(edits, None, cx);
10690            });
10691            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10692                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10693            });
10694        });
10695    }
10696
10697    pub fn clear_selection_drag_state(&mut self) {
10698        self.selection_drag_state = SelectionDragState::None;
10699    }
10700
10701    pub fn duplicate(
10702        &mut self,
10703        upwards: bool,
10704        whole_lines: bool,
10705        window: &mut Window,
10706        cx: &mut Context<Self>,
10707    ) {
10708        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10709
10710        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10711        let buffer = &display_map.buffer_snapshot;
10712        let selections = self.selections.all::<Point>(cx);
10713
10714        let mut edits = Vec::new();
10715        let mut selections_iter = selections.iter().peekable();
10716        while let Some(selection) = selections_iter.next() {
10717            let mut rows = selection.spanned_rows(false, &display_map);
10718            // duplicate line-wise
10719            if whole_lines || selection.start == selection.end {
10720                // Avoid duplicating the same lines twice.
10721                while let Some(next_selection) = selections_iter.peek() {
10722                    let next_rows = next_selection.spanned_rows(false, &display_map);
10723                    if next_rows.start < rows.end {
10724                        rows.end = next_rows.end;
10725                        selections_iter.next().unwrap();
10726                    } else {
10727                        break;
10728                    }
10729                }
10730
10731                // Copy the text from the selected row region and splice it either at the start
10732                // or end of the region.
10733                let start = Point::new(rows.start.0, 0);
10734                let end = Point::new(
10735                    rows.end.previous_row().0,
10736                    buffer.line_len(rows.end.previous_row()),
10737                );
10738                let text = buffer
10739                    .text_for_range(start..end)
10740                    .chain(Some("\n"))
10741                    .collect::<String>();
10742                let insert_location = if upwards {
10743                    Point::new(rows.end.0, 0)
10744                } else {
10745                    start
10746                };
10747                edits.push((insert_location..insert_location, text));
10748            } else {
10749                // duplicate character-wise
10750                let start = selection.start;
10751                let end = selection.end;
10752                let text = buffer.text_for_range(start..end).collect::<String>();
10753                edits.push((selection.end..selection.end, text));
10754            }
10755        }
10756
10757        self.transact(window, cx, |this, _, cx| {
10758            this.buffer.update(cx, |buffer, cx| {
10759                buffer.edit(edits, None, cx);
10760            });
10761
10762            this.request_autoscroll(Autoscroll::fit(), cx);
10763        });
10764    }
10765
10766    pub fn duplicate_line_up(
10767        &mut self,
10768        _: &DuplicateLineUp,
10769        window: &mut Window,
10770        cx: &mut Context<Self>,
10771    ) {
10772        self.duplicate(true, true, window, cx);
10773    }
10774
10775    pub fn duplicate_line_down(
10776        &mut self,
10777        _: &DuplicateLineDown,
10778        window: &mut Window,
10779        cx: &mut Context<Self>,
10780    ) {
10781        self.duplicate(false, true, window, cx);
10782    }
10783
10784    pub fn duplicate_selection(
10785        &mut self,
10786        _: &DuplicateSelection,
10787        window: &mut Window,
10788        cx: &mut Context<Self>,
10789    ) {
10790        self.duplicate(false, false, window, cx);
10791    }
10792
10793    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10794        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10795
10796        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10797        let buffer = self.buffer.read(cx).snapshot(cx);
10798
10799        let mut edits = Vec::new();
10800        let mut unfold_ranges = Vec::new();
10801        let mut refold_creases = Vec::new();
10802
10803        let selections = self.selections.all::<Point>(cx);
10804        let mut selections = selections.iter().peekable();
10805        let mut contiguous_row_selections = Vec::new();
10806        let mut new_selections = Vec::new();
10807
10808        while let Some(selection) = selections.next() {
10809            // Find all the selections that span a contiguous row range
10810            let (start_row, end_row) = consume_contiguous_rows(
10811                &mut contiguous_row_selections,
10812                selection,
10813                &display_map,
10814                &mut selections,
10815            );
10816
10817            // Move the text spanned by the row range to be before the line preceding the row range
10818            if start_row.0 > 0 {
10819                let range_to_move = Point::new(
10820                    start_row.previous_row().0,
10821                    buffer.line_len(start_row.previous_row()),
10822                )
10823                    ..Point::new(
10824                        end_row.previous_row().0,
10825                        buffer.line_len(end_row.previous_row()),
10826                    );
10827                let insertion_point = display_map
10828                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10829                    .0;
10830
10831                // Don't move lines across excerpts
10832                if buffer
10833                    .excerpt_containing(insertion_point..range_to_move.end)
10834                    .is_some()
10835                {
10836                    let text = buffer
10837                        .text_for_range(range_to_move.clone())
10838                        .flat_map(|s| s.chars())
10839                        .skip(1)
10840                        .chain(['\n'])
10841                        .collect::<String>();
10842
10843                    edits.push((
10844                        buffer.anchor_after(range_to_move.start)
10845                            ..buffer.anchor_before(range_to_move.end),
10846                        String::new(),
10847                    ));
10848                    let insertion_anchor = buffer.anchor_after(insertion_point);
10849                    edits.push((insertion_anchor..insertion_anchor, text));
10850
10851                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10852
10853                    // Move selections up
10854                    new_selections.extend(contiguous_row_selections.drain(..).map(
10855                        |mut selection| {
10856                            selection.start.row -= row_delta;
10857                            selection.end.row -= row_delta;
10858                            selection
10859                        },
10860                    ));
10861
10862                    // Move folds up
10863                    unfold_ranges.push(range_to_move.clone());
10864                    for fold in display_map.folds_in_range(
10865                        buffer.anchor_before(range_to_move.start)
10866                            ..buffer.anchor_after(range_to_move.end),
10867                    ) {
10868                        let mut start = fold.range.start.to_point(&buffer);
10869                        let mut end = fold.range.end.to_point(&buffer);
10870                        start.row -= row_delta;
10871                        end.row -= row_delta;
10872                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10873                    }
10874                }
10875            }
10876
10877            // If we didn't move line(s), preserve the existing selections
10878            new_selections.append(&mut contiguous_row_selections);
10879        }
10880
10881        self.transact(window, cx, |this, window, cx| {
10882            this.unfold_ranges(&unfold_ranges, true, true, cx);
10883            this.buffer.update(cx, |buffer, cx| {
10884                for (range, text) in edits {
10885                    buffer.edit([(range, text)], None, cx);
10886                }
10887            });
10888            this.fold_creases(refold_creases, true, window, cx);
10889            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10890                s.select(new_selections);
10891            })
10892        });
10893    }
10894
10895    pub fn move_line_down(
10896        &mut self,
10897        _: &MoveLineDown,
10898        window: &mut Window,
10899        cx: &mut Context<Self>,
10900    ) {
10901        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10902
10903        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10904        let buffer = self.buffer.read(cx).snapshot(cx);
10905
10906        let mut edits = Vec::new();
10907        let mut unfold_ranges = Vec::new();
10908        let mut refold_creases = Vec::new();
10909
10910        let selections = self.selections.all::<Point>(cx);
10911        let mut selections = selections.iter().peekable();
10912        let mut contiguous_row_selections = Vec::new();
10913        let mut new_selections = Vec::new();
10914
10915        while let Some(selection) = selections.next() {
10916            // Find all the selections that span a contiguous row range
10917            let (start_row, end_row) = consume_contiguous_rows(
10918                &mut contiguous_row_selections,
10919                selection,
10920                &display_map,
10921                &mut selections,
10922            );
10923
10924            // Move the text spanned by the row range to be after the last line of the row range
10925            if end_row.0 <= buffer.max_point().row {
10926                let range_to_move =
10927                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10928                let insertion_point = display_map
10929                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10930                    .0;
10931
10932                // Don't move lines across excerpt boundaries
10933                if buffer
10934                    .excerpt_containing(range_to_move.start..insertion_point)
10935                    .is_some()
10936                {
10937                    let mut text = String::from("\n");
10938                    text.extend(buffer.text_for_range(range_to_move.clone()));
10939                    text.pop(); // Drop trailing newline
10940                    edits.push((
10941                        buffer.anchor_after(range_to_move.start)
10942                            ..buffer.anchor_before(range_to_move.end),
10943                        String::new(),
10944                    ));
10945                    let insertion_anchor = buffer.anchor_after(insertion_point);
10946                    edits.push((insertion_anchor..insertion_anchor, text));
10947
10948                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10949
10950                    // Move selections down
10951                    new_selections.extend(contiguous_row_selections.drain(..).map(
10952                        |mut selection| {
10953                            selection.start.row += row_delta;
10954                            selection.end.row += row_delta;
10955                            selection
10956                        },
10957                    ));
10958
10959                    // Move folds down
10960                    unfold_ranges.push(range_to_move.clone());
10961                    for fold in display_map.folds_in_range(
10962                        buffer.anchor_before(range_to_move.start)
10963                            ..buffer.anchor_after(range_to_move.end),
10964                    ) {
10965                        let mut start = fold.range.start.to_point(&buffer);
10966                        let mut end = fold.range.end.to_point(&buffer);
10967                        start.row += row_delta;
10968                        end.row += row_delta;
10969                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10970                    }
10971                }
10972            }
10973
10974            // If we didn't move line(s), preserve the existing selections
10975            new_selections.append(&mut contiguous_row_selections);
10976        }
10977
10978        self.transact(window, cx, |this, window, cx| {
10979            this.unfold_ranges(&unfold_ranges, true, true, cx);
10980            this.buffer.update(cx, |buffer, cx| {
10981                for (range, text) in edits {
10982                    buffer.edit([(range, text)], None, cx);
10983                }
10984            });
10985            this.fold_creases(refold_creases, true, window, cx);
10986            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10987                s.select(new_selections)
10988            });
10989        });
10990    }
10991
10992    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10993        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10994        let text_layout_details = &self.text_layout_details(window);
10995        self.transact(window, cx, |this, window, cx| {
10996            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10997                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10998                s.move_with(|display_map, selection| {
10999                    if !selection.is_empty() {
11000                        return;
11001                    }
11002
11003                    let mut head = selection.head();
11004                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11005                    if head.column() == display_map.line_len(head.row()) {
11006                        transpose_offset = display_map
11007                            .buffer_snapshot
11008                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11009                    }
11010
11011                    if transpose_offset == 0 {
11012                        return;
11013                    }
11014
11015                    *head.column_mut() += 1;
11016                    head = display_map.clip_point(head, Bias::Right);
11017                    let goal = SelectionGoal::HorizontalPosition(
11018                        display_map
11019                            .x_for_display_point(head, text_layout_details)
11020                            .into(),
11021                    );
11022                    selection.collapse_to(head, goal);
11023
11024                    let transpose_start = display_map
11025                        .buffer_snapshot
11026                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11027                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11028                        let transpose_end = display_map
11029                            .buffer_snapshot
11030                            .clip_offset(transpose_offset + 1, Bias::Right);
11031                        if let Some(ch) =
11032                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11033                        {
11034                            edits.push((transpose_start..transpose_offset, String::new()));
11035                            edits.push((transpose_end..transpose_end, ch.to_string()));
11036                        }
11037                    }
11038                });
11039                edits
11040            });
11041            this.buffer
11042                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11043            let selections = this.selections.all::<usize>(cx);
11044            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11045                s.select(selections);
11046            });
11047        });
11048    }
11049
11050    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11051        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11052        self.rewrap_impl(RewrapOptions::default(), cx)
11053    }
11054
11055    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11056        let buffer = self.buffer.read(cx).snapshot(cx);
11057        let selections = self.selections.all::<Point>(cx);
11058
11059        // Shrink and split selections to respect paragraph boundaries.
11060        let ranges = selections.into_iter().flat_map(|selection| {
11061            let language_settings = buffer.language_settings_at(selection.head(), cx);
11062            let language_scope = buffer.language_scope_at(selection.head());
11063
11064            let Some(start_row) = (selection.start.row..=selection.end.row)
11065                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11066            else {
11067                return vec![];
11068            };
11069            let Some(end_row) = (selection.start.row..=selection.end.row)
11070                .rev()
11071                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11072            else {
11073                return vec![];
11074            };
11075
11076            let mut row = start_row;
11077            let mut ranges = Vec::new();
11078            while let Some(blank_row) =
11079                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11080            {
11081                let next_paragraph_start = (blank_row + 1..=end_row)
11082                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11083                    .unwrap();
11084                ranges.push((
11085                    language_settings.clone(),
11086                    language_scope.clone(),
11087                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11088                ));
11089                row = next_paragraph_start;
11090            }
11091            ranges.push((
11092                language_settings.clone(),
11093                language_scope.clone(),
11094                Point::new(row, 0)..Point::new(end_row, 0),
11095            ));
11096
11097            ranges
11098        });
11099
11100        let mut edits = Vec::new();
11101        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11102
11103        for (language_settings, language_scope, range) in ranges {
11104            let mut start_row = range.start.row;
11105            let mut end_row = range.end.row;
11106
11107            // Skip selections that overlap with a range that has already been rewrapped.
11108            let selection_range = start_row..end_row;
11109            if rewrapped_row_ranges
11110                .iter()
11111                .any(|range| range.overlaps(&selection_range))
11112            {
11113                continue;
11114            }
11115
11116            let tab_size = language_settings.tab_size;
11117
11118            // Since not all lines in the selection may be at the same indent
11119            // level, choose the indent size that is the most common between all
11120            // of the lines.
11121            //
11122            // If there is a tie, we use the deepest indent.
11123            let (indent_size, indent_end) = {
11124                let mut indent_size_occurrences = HashMap::default();
11125                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11126
11127                for row in start_row..=end_row {
11128                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11129                    rows_by_indent_size.entry(indent).or_default().push(row);
11130                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11131                }
11132
11133                let indent_size = indent_size_occurrences
11134                    .into_iter()
11135                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11136                    .map(|(indent, _)| indent)
11137                    .unwrap_or_default();
11138                let row = rows_by_indent_size[&indent_size][0];
11139                let indent_end = Point::new(row, indent_size.len);
11140
11141                (indent_size, indent_end)
11142            };
11143
11144            let mut line_prefix = indent_size.chars().collect::<String>();
11145
11146            let mut inside_comment = false;
11147            if let Some(comment_prefix) = language_scope.and_then(|language| {
11148                language
11149                    .line_comment_prefixes()
11150                    .iter()
11151                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11152                    .cloned()
11153            }) {
11154                line_prefix.push_str(&comment_prefix);
11155                inside_comment = true;
11156            }
11157
11158            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11159                RewrapBehavior::InComments => inside_comment,
11160                RewrapBehavior::InSelections => !range.is_empty(),
11161                RewrapBehavior::Anywhere => true,
11162            };
11163
11164            let should_rewrap = options.override_language_settings
11165                || allow_rewrap_based_on_language
11166                || self.hard_wrap.is_some();
11167            if !should_rewrap {
11168                continue;
11169            }
11170
11171            if range.is_empty() {
11172                'expand_upwards: while start_row > 0 {
11173                    let prev_row = start_row - 1;
11174                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11175                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11176                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11177                    {
11178                        start_row = prev_row;
11179                    } else {
11180                        break 'expand_upwards;
11181                    }
11182                }
11183
11184                'expand_downwards: while end_row < buffer.max_point().row {
11185                    let next_row = end_row + 1;
11186                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11187                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11188                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11189                    {
11190                        end_row = next_row;
11191                    } else {
11192                        break 'expand_downwards;
11193                    }
11194                }
11195            }
11196
11197            let start = Point::new(start_row, 0);
11198            let start_offset = start.to_offset(&buffer);
11199            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11200            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11201            let Some(lines_without_prefixes) = selection_text
11202                .lines()
11203                .map(|line| {
11204                    line.strip_prefix(&line_prefix)
11205                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11206                        .with_context(|| {
11207                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11208                        })
11209                })
11210                .collect::<Result<Vec<_>, _>>()
11211                .log_err()
11212            else {
11213                continue;
11214            };
11215
11216            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11217                buffer
11218                    .language_settings_at(Point::new(start_row, 0), cx)
11219                    .preferred_line_length as usize
11220            });
11221            let wrapped_text = wrap_with_prefix(
11222                line_prefix,
11223                lines_without_prefixes.join("\n"),
11224                wrap_column,
11225                tab_size,
11226                options.preserve_existing_whitespace,
11227            );
11228
11229            // TODO: should always use char-based diff while still supporting cursor behavior that
11230            // matches vim.
11231            let mut diff_options = DiffOptions::default();
11232            if options.override_language_settings {
11233                diff_options.max_word_diff_len = 0;
11234                diff_options.max_word_diff_line_count = 0;
11235            } else {
11236                diff_options.max_word_diff_len = usize::MAX;
11237                diff_options.max_word_diff_line_count = usize::MAX;
11238            }
11239
11240            for (old_range, new_text) in
11241                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11242            {
11243                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11244                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11245                edits.push((edit_start..edit_end, new_text));
11246            }
11247
11248            rewrapped_row_ranges.push(start_row..=end_row);
11249        }
11250
11251        self.buffer
11252            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11253    }
11254
11255    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11256        let mut text = String::new();
11257        let buffer = self.buffer.read(cx).snapshot(cx);
11258        let mut selections = self.selections.all::<Point>(cx);
11259        let mut clipboard_selections = Vec::with_capacity(selections.len());
11260        {
11261            let max_point = buffer.max_point();
11262            let mut is_first = true;
11263            for selection in &mut selections {
11264                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11265                if is_entire_line {
11266                    selection.start = Point::new(selection.start.row, 0);
11267                    if !selection.is_empty() && selection.end.column == 0 {
11268                        selection.end = cmp::min(max_point, selection.end);
11269                    } else {
11270                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11271                    }
11272                    selection.goal = SelectionGoal::None;
11273                }
11274                if is_first {
11275                    is_first = false;
11276                } else {
11277                    text += "\n";
11278                }
11279                let mut len = 0;
11280                for chunk in buffer.text_for_range(selection.start..selection.end) {
11281                    text.push_str(chunk);
11282                    len += chunk.len();
11283                }
11284                clipboard_selections.push(ClipboardSelection {
11285                    len,
11286                    is_entire_line,
11287                    first_line_indent: buffer
11288                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11289                        .len,
11290                });
11291            }
11292        }
11293
11294        self.transact(window, cx, |this, window, cx| {
11295            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11296                s.select(selections);
11297            });
11298            this.insert("", window, cx);
11299        });
11300        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11301    }
11302
11303    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11304        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11305        let item = self.cut_common(window, cx);
11306        cx.write_to_clipboard(item);
11307    }
11308
11309    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11310        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11311        self.change_selections(None, window, cx, |s| {
11312            s.move_with(|snapshot, sel| {
11313                if sel.is_empty() {
11314                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11315                }
11316            });
11317        });
11318        let item = self.cut_common(window, cx);
11319        cx.set_global(KillRing(item))
11320    }
11321
11322    pub fn kill_ring_yank(
11323        &mut self,
11324        _: &KillRingYank,
11325        window: &mut Window,
11326        cx: &mut Context<Self>,
11327    ) {
11328        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11329        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11330            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11331                (kill_ring.text().to_string(), kill_ring.metadata_json())
11332            } else {
11333                return;
11334            }
11335        } else {
11336            return;
11337        };
11338        self.do_paste(&text, metadata, false, window, cx);
11339    }
11340
11341    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11342        self.do_copy(true, cx);
11343    }
11344
11345    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11346        self.do_copy(false, cx);
11347    }
11348
11349    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11350        let selections = self.selections.all::<Point>(cx);
11351        let buffer = self.buffer.read(cx).read(cx);
11352        let mut text = String::new();
11353
11354        let mut clipboard_selections = Vec::with_capacity(selections.len());
11355        {
11356            let max_point = buffer.max_point();
11357            let mut is_first = true;
11358            for selection in &selections {
11359                let mut start = selection.start;
11360                let mut end = selection.end;
11361                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11362                if is_entire_line {
11363                    start = Point::new(start.row, 0);
11364                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11365                }
11366
11367                let mut trimmed_selections = Vec::new();
11368                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11369                    let row = MultiBufferRow(start.row);
11370                    let first_indent = buffer.indent_size_for_line(row);
11371                    if first_indent.len == 0 || start.column > first_indent.len {
11372                        trimmed_selections.push(start..end);
11373                    } else {
11374                        trimmed_selections.push(
11375                            Point::new(row.0, first_indent.len)
11376                                ..Point::new(row.0, buffer.line_len(row)),
11377                        );
11378                        for row in start.row + 1..=end.row {
11379                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11380                            if row == end.row {
11381                                line_len = end.column;
11382                            }
11383                            if line_len == 0 {
11384                                trimmed_selections
11385                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11386                                continue;
11387                            }
11388                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11389                            if row_indent_size.len >= first_indent.len {
11390                                trimmed_selections.push(
11391                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11392                                );
11393                            } else {
11394                                trimmed_selections.clear();
11395                                trimmed_selections.push(start..end);
11396                                break;
11397                            }
11398                        }
11399                    }
11400                } else {
11401                    trimmed_selections.push(start..end);
11402                }
11403
11404                for trimmed_range in trimmed_selections {
11405                    if is_first {
11406                        is_first = false;
11407                    } else {
11408                        text += "\n";
11409                    }
11410                    let mut len = 0;
11411                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11412                        text.push_str(chunk);
11413                        len += chunk.len();
11414                    }
11415                    clipboard_selections.push(ClipboardSelection {
11416                        len,
11417                        is_entire_line,
11418                        first_line_indent: buffer
11419                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11420                            .len,
11421                    });
11422                }
11423            }
11424        }
11425
11426        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11427            text,
11428            clipboard_selections,
11429        ));
11430    }
11431
11432    pub fn do_paste(
11433        &mut self,
11434        text: &String,
11435        clipboard_selections: Option<Vec<ClipboardSelection>>,
11436        handle_entire_lines: bool,
11437        window: &mut Window,
11438        cx: &mut Context<Self>,
11439    ) {
11440        if self.read_only(cx) {
11441            return;
11442        }
11443
11444        let clipboard_text = Cow::Borrowed(text);
11445
11446        self.transact(window, cx, |this, window, cx| {
11447            if let Some(mut clipboard_selections) = clipboard_selections {
11448                let old_selections = this.selections.all::<usize>(cx);
11449                let all_selections_were_entire_line =
11450                    clipboard_selections.iter().all(|s| s.is_entire_line);
11451                let first_selection_indent_column =
11452                    clipboard_selections.first().map(|s| s.first_line_indent);
11453                if clipboard_selections.len() != old_selections.len() {
11454                    clipboard_selections.drain(..);
11455                }
11456                let cursor_offset = this.selections.last::<usize>(cx).head();
11457                let mut auto_indent_on_paste = true;
11458
11459                this.buffer.update(cx, |buffer, cx| {
11460                    let snapshot = buffer.read(cx);
11461                    auto_indent_on_paste = snapshot
11462                        .language_settings_at(cursor_offset, cx)
11463                        .auto_indent_on_paste;
11464
11465                    let mut start_offset = 0;
11466                    let mut edits = Vec::new();
11467                    let mut original_indent_columns = Vec::new();
11468                    for (ix, selection) in old_selections.iter().enumerate() {
11469                        let to_insert;
11470                        let entire_line;
11471                        let original_indent_column;
11472                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11473                            let end_offset = start_offset + clipboard_selection.len;
11474                            to_insert = &clipboard_text[start_offset..end_offset];
11475                            entire_line = clipboard_selection.is_entire_line;
11476                            start_offset = end_offset + 1;
11477                            original_indent_column = Some(clipboard_selection.first_line_indent);
11478                        } else {
11479                            to_insert = clipboard_text.as_str();
11480                            entire_line = all_selections_were_entire_line;
11481                            original_indent_column = first_selection_indent_column
11482                        }
11483
11484                        // If the corresponding selection was empty when this slice of the
11485                        // clipboard text was written, then the entire line containing the
11486                        // selection was copied. If this selection is also currently empty,
11487                        // then paste the line before the current line of the buffer.
11488                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11489                            let column = selection.start.to_point(&snapshot).column as usize;
11490                            let line_start = selection.start - column;
11491                            line_start..line_start
11492                        } else {
11493                            selection.range()
11494                        };
11495
11496                        edits.push((range, to_insert));
11497                        original_indent_columns.push(original_indent_column);
11498                    }
11499                    drop(snapshot);
11500
11501                    buffer.edit(
11502                        edits,
11503                        if auto_indent_on_paste {
11504                            Some(AutoindentMode::Block {
11505                                original_indent_columns,
11506                            })
11507                        } else {
11508                            None
11509                        },
11510                        cx,
11511                    );
11512                });
11513
11514                let selections = this.selections.all::<usize>(cx);
11515                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11516                    s.select(selections)
11517                });
11518            } else {
11519                this.insert(&clipboard_text, window, cx);
11520            }
11521        });
11522    }
11523
11524    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11525        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11526        if let Some(item) = cx.read_from_clipboard() {
11527            let entries = item.entries();
11528
11529            match entries.first() {
11530                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11531                // of all the pasted entries.
11532                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11533                    .do_paste(
11534                        clipboard_string.text(),
11535                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11536                        true,
11537                        window,
11538                        cx,
11539                    ),
11540                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11541            }
11542        }
11543    }
11544
11545    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11546        if self.read_only(cx) {
11547            return;
11548        }
11549
11550        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11551
11552        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11553            if let Some((selections, _)) =
11554                self.selection_history.transaction(transaction_id).cloned()
11555            {
11556                self.change_selections(None, window, cx, |s| {
11557                    s.select_anchors(selections.to_vec());
11558                });
11559            } else {
11560                log::error!(
11561                    "No entry in selection_history found for undo. \
11562                     This may correspond to a bug where undo does not update the selection. \
11563                     If this is occurring, please add details to \
11564                     https://github.com/zed-industries/zed/issues/22692"
11565                );
11566            }
11567            self.request_autoscroll(Autoscroll::fit(), cx);
11568            self.unmark_text(window, cx);
11569            self.refresh_inline_completion(true, false, window, cx);
11570            cx.emit(EditorEvent::Edited { transaction_id });
11571            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11572        }
11573    }
11574
11575    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11576        if self.read_only(cx) {
11577            return;
11578        }
11579
11580        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11581
11582        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11583            if let Some((_, Some(selections))) =
11584                self.selection_history.transaction(transaction_id).cloned()
11585            {
11586                self.change_selections(None, window, cx, |s| {
11587                    s.select_anchors(selections.to_vec());
11588                });
11589            } else {
11590                log::error!(
11591                    "No entry in selection_history found for redo. \
11592                     This may correspond to a bug where undo does not update the selection. \
11593                     If this is occurring, please add details to \
11594                     https://github.com/zed-industries/zed/issues/22692"
11595                );
11596            }
11597            self.request_autoscroll(Autoscroll::fit(), cx);
11598            self.unmark_text(window, cx);
11599            self.refresh_inline_completion(true, false, window, cx);
11600            cx.emit(EditorEvent::Edited { transaction_id });
11601        }
11602    }
11603
11604    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11605        self.buffer
11606            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11607    }
11608
11609    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11610        self.buffer
11611            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11612    }
11613
11614    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11615        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11616        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11617            s.move_with(|map, selection| {
11618                let cursor = if selection.is_empty() {
11619                    movement::left(map, selection.start)
11620                } else {
11621                    selection.start
11622                };
11623                selection.collapse_to(cursor, SelectionGoal::None);
11624            });
11625        })
11626    }
11627
11628    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11629        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11630        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11631            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11632        })
11633    }
11634
11635    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11636        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11637        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11638            s.move_with(|map, selection| {
11639                let cursor = if selection.is_empty() {
11640                    movement::right(map, selection.end)
11641                } else {
11642                    selection.end
11643                };
11644                selection.collapse_to(cursor, SelectionGoal::None)
11645            });
11646        })
11647    }
11648
11649    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11650        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11651        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11652            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11653        })
11654    }
11655
11656    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11657        if self.take_rename(true, window, cx).is_some() {
11658            return;
11659        }
11660
11661        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11662            cx.propagate();
11663            return;
11664        }
11665
11666        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11667
11668        let text_layout_details = &self.text_layout_details(window);
11669        let selection_count = self.selections.count();
11670        let first_selection = self.selections.first_anchor();
11671
11672        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11673            s.move_with(|map, selection| {
11674                if !selection.is_empty() {
11675                    selection.goal = SelectionGoal::None;
11676                }
11677                let (cursor, goal) = movement::up(
11678                    map,
11679                    selection.start,
11680                    selection.goal,
11681                    false,
11682                    text_layout_details,
11683                );
11684                selection.collapse_to(cursor, goal);
11685            });
11686        });
11687
11688        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11689        {
11690            cx.propagate();
11691        }
11692    }
11693
11694    pub fn move_up_by_lines(
11695        &mut self,
11696        action: &MoveUpByLines,
11697        window: &mut Window,
11698        cx: &mut Context<Self>,
11699    ) {
11700        if self.take_rename(true, window, cx).is_some() {
11701            return;
11702        }
11703
11704        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11705            cx.propagate();
11706            return;
11707        }
11708
11709        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11710
11711        let text_layout_details = &self.text_layout_details(window);
11712
11713        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11714            s.move_with(|map, selection| {
11715                if !selection.is_empty() {
11716                    selection.goal = SelectionGoal::None;
11717                }
11718                let (cursor, goal) = movement::up_by_rows(
11719                    map,
11720                    selection.start,
11721                    action.lines,
11722                    selection.goal,
11723                    false,
11724                    text_layout_details,
11725                );
11726                selection.collapse_to(cursor, goal);
11727            });
11728        })
11729    }
11730
11731    pub fn move_down_by_lines(
11732        &mut self,
11733        action: &MoveDownByLines,
11734        window: &mut Window,
11735        cx: &mut Context<Self>,
11736    ) {
11737        if self.take_rename(true, window, cx).is_some() {
11738            return;
11739        }
11740
11741        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11742            cx.propagate();
11743            return;
11744        }
11745
11746        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11747
11748        let text_layout_details = &self.text_layout_details(window);
11749
11750        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11751            s.move_with(|map, selection| {
11752                if !selection.is_empty() {
11753                    selection.goal = SelectionGoal::None;
11754                }
11755                let (cursor, goal) = movement::down_by_rows(
11756                    map,
11757                    selection.start,
11758                    action.lines,
11759                    selection.goal,
11760                    false,
11761                    text_layout_details,
11762                );
11763                selection.collapse_to(cursor, goal);
11764            });
11765        })
11766    }
11767
11768    pub fn select_down_by_lines(
11769        &mut self,
11770        action: &SelectDownByLines,
11771        window: &mut Window,
11772        cx: &mut Context<Self>,
11773    ) {
11774        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11775        let text_layout_details = &self.text_layout_details(window);
11776        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11777            s.move_heads_with(|map, head, goal| {
11778                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11779            })
11780        })
11781    }
11782
11783    pub fn select_up_by_lines(
11784        &mut self,
11785        action: &SelectUpByLines,
11786        window: &mut Window,
11787        cx: &mut Context<Self>,
11788    ) {
11789        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11790        let text_layout_details = &self.text_layout_details(window);
11791        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11792            s.move_heads_with(|map, head, goal| {
11793                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11794            })
11795        })
11796    }
11797
11798    pub fn select_page_up(
11799        &mut self,
11800        _: &SelectPageUp,
11801        window: &mut Window,
11802        cx: &mut Context<Self>,
11803    ) {
11804        let Some(row_count) = self.visible_row_count() else {
11805            return;
11806        };
11807
11808        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11809
11810        let text_layout_details = &self.text_layout_details(window);
11811
11812        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11813            s.move_heads_with(|map, head, goal| {
11814                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11815            })
11816        })
11817    }
11818
11819    pub fn move_page_up(
11820        &mut self,
11821        action: &MovePageUp,
11822        window: &mut Window,
11823        cx: &mut Context<Self>,
11824    ) {
11825        if self.take_rename(true, window, cx).is_some() {
11826            return;
11827        }
11828
11829        if self
11830            .context_menu
11831            .borrow_mut()
11832            .as_mut()
11833            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11834            .unwrap_or(false)
11835        {
11836            return;
11837        }
11838
11839        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11840            cx.propagate();
11841            return;
11842        }
11843
11844        let Some(row_count) = self.visible_row_count() else {
11845            return;
11846        };
11847
11848        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11849
11850        let autoscroll = if action.center_cursor {
11851            Autoscroll::center()
11852        } else {
11853            Autoscroll::fit()
11854        };
11855
11856        let text_layout_details = &self.text_layout_details(window);
11857
11858        self.change_selections(Some(autoscroll), window, cx, |s| {
11859            s.move_with(|map, selection| {
11860                if !selection.is_empty() {
11861                    selection.goal = SelectionGoal::None;
11862                }
11863                let (cursor, goal) = movement::up_by_rows(
11864                    map,
11865                    selection.end,
11866                    row_count,
11867                    selection.goal,
11868                    false,
11869                    text_layout_details,
11870                );
11871                selection.collapse_to(cursor, goal);
11872            });
11873        });
11874    }
11875
11876    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11877        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11878        let text_layout_details = &self.text_layout_details(window);
11879        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11880            s.move_heads_with(|map, head, goal| {
11881                movement::up(map, head, goal, false, text_layout_details)
11882            })
11883        })
11884    }
11885
11886    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11887        self.take_rename(true, window, cx);
11888
11889        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11890            cx.propagate();
11891            return;
11892        }
11893
11894        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11895
11896        let text_layout_details = &self.text_layout_details(window);
11897        let selection_count = self.selections.count();
11898        let first_selection = self.selections.first_anchor();
11899
11900        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11901            s.move_with(|map, selection| {
11902                if !selection.is_empty() {
11903                    selection.goal = SelectionGoal::None;
11904                }
11905                let (cursor, goal) = movement::down(
11906                    map,
11907                    selection.end,
11908                    selection.goal,
11909                    false,
11910                    text_layout_details,
11911                );
11912                selection.collapse_to(cursor, goal);
11913            });
11914        });
11915
11916        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11917        {
11918            cx.propagate();
11919        }
11920    }
11921
11922    pub fn select_page_down(
11923        &mut self,
11924        _: &SelectPageDown,
11925        window: &mut Window,
11926        cx: &mut Context<Self>,
11927    ) {
11928        let Some(row_count) = self.visible_row_count() else {
11929            return;
11930        };
11931
11932        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11933
11934        let text_layout_details = &self.text_layout_details(window);
11935
11936        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11937            s.move_heads_with(|map, head, goal| {
11938                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11939            })
11940        })
11941    }
11942
11943    pub fn move_page_down(
11944        &mut self,
11945        action: &MovePageDown,
11946        window: &mut Window,
11947        cx: &mut Context<Self>,
11948    ) {
11949        if self.take_rename(true, window, cx).is_some() {
11950            return;
11951        }
11952
11953        if self
11954            .context_menu
11955            .borrow_mut()
11956            .as_mut()
11957            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11958            .unwrap_or(false)
11959        {
11960            return;
11961        }
11962
11963        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11964            cx.propagate();
11965            return;
11966        }
11967
11968        let Some(row_count) = self.visible_row_count() else {
11969            return;
11970        };
11971
11972        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11973
11974        let autoscroll = if action.center_cursor {
11975            Autoscroll::center()
11976        } else {
11977            Autoscroll::fit()
11978        };
11979
11980        let text_layout_details = &self.text_layout_details(window);
11981        self.change_selections(Some(autoscroll), window, cx, |s| {
11982            s.move_with(|map, selection| {
11983                if !selection.is_empty() {
11984                    selection.goal = SelectionGoal::None;
11985                }
11986                let (cursor, goal) = movement::down_by_rows(
11987                    map,
11988                    selection.end,
11989                    row_count,
11990                    selection.goal,
11991                    false,
11992                    text_layout_details,
11993                );
11994                selection.collapse_to(cursor, goal);
11995            });
11996        });
11997    }
11998
11999    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12000        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12001        let text_layout_details = &self.text_layout_details(window);
12002        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12003            s.move_heads_with(|map, head, goal| {
12004                movement::down(map, head, goal, false, text_layout_details)
12005            })
12006        });
12007    }
12008
12009    pub fn context_menu_first(
12010        &mut self,
12011        _: &ContextMenuFirst,
12012        window: &mut Window,
12013        cx: &mut Context<Self>,
12014    ) {
12015        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12016            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12017        }
12018    }
12019
12020    pub fn context_menu_prev(
12021        &mut self,
12022        _: &ContextMenuPrevious,
12023        window: &mut Window,
12024        cx: &mut Context<Self>,
12025    ) {
12026        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12027            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12028        }
12029    }
12030
12031    pub fn context_menu_next(
12032        &mut self,
12033        _: &ContextMenuNext,
12034        window: &mut Window,
12035        cx: &mut Context<Self>,
12036    ) {
12037        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12038            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12039        }
12040    }
12041
12042    pub fn context_menu_last(
12043        &mut self,
12044        _: &ContextMenuLast,
12045        window: &mut Window,
12046        cx: &mut Context<Self>,
12047    ) {
12048        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12049            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12050        }
12051    }
12052
12053    pub fn move_to_previous_word_start(
12054        &mut self,
12055        _: &MoveToPreviousWordStart,
12056        window: &mut Window,
12057        cx: &mut Context<Self>,
12058    ) {
12059        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12060        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12061            s.move_cursors_with(|map, head, _| {
12062                (
12063                    movement::previous_word_start(map, head),
12064                    SelectionGoal::None,
12065                )
12066            });
12067        })
12068    }
12069
12070    pub fn move_to_previous_subword_start(
12071        &mut self,
12072        _: &MoveToPreviousSubwordStart,
12073        window: &mut Window,
12074        cx: &mut Context<Self>,
12075    ) {
12076        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12077        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12078            s.move_cursors_with(|map, head, _| {
12079                (
12080                    movement::previous_subword_start(map, head),
12081                    SelectionGoal::None,
12082                )
12083            });
12084        })
12085    }
12086
12087    pub fn select_to_previous_word_start(
12088        &mut self,
12089        _: &SelectToPreviousWordStart,
12090        window: &mut Window,
12091        cx: &mut Context<Self>,
12092    ) {
12093        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12094        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12095            s.move_heads_with(|map, head, _| {
12096                (
12097                    movement::previous_word_start(map, head),
12098                    SelectionGoal::None,
12099                )
12100            });
12101        })
12102    }
12103
12104    pub fn select_to_previous_subword_start(
12105        &mut self,
12106        _: &SelectToPreviousSubwordStart,
12107        window: &mut Window,
12108        cx: &mut Context<Self>,
12109    ) {
12110        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12111        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12112            s.move_heads_with(|map, head, _| {
12113                (
12114                    movement::previous_subword_start(map, head),
12115                    SelectionGoal::None,
12116                )
12117            });
12118        })
12119    }
12120
12121    pub fn delete_to_previous_word_start(
12122        &mut self,
12123        action: &DeleteToPreviousWordStart,
12124        window: &mut Window,
12125        cx: &mut Context<Self>,
12126    ) {
12127        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12128        self.transact(window, cx, |this, window, cx| {
12129            this.select_autoclose_pair(window, cx);
12130            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12131                s.move_with(|map, selection| {
12132                    if selection.is_empty() {
12133                        let cursor = if action.ignore_newlines {
12134                            movement::previous_word_start(map, selection.head())
12135                        } else {
12136                            movement::previous_word_start_or_newline(map, selection.head())
12137                        };
12138                        selection.set_head(cursor, SelectionGoal::None);
12139                    }
12140                });
12141            });
12142            this.insert("", window, cx);
12143        });
12144    }
12145
12146    pub fn delete_to_previous_subword_start(
12147        &mut self,
12148        _: &DeleteToPreviousSubwordStart,
12149        window: &mut Window,
12150        cx: &mut Context<Self>,
12151    ) {
12152        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12153        self.transact(window, cx, |this, window, cx| {
12154            this.select_autoclose_pair(window, cx);
12155            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12156                s.move_with(|map, selection| {
12157                    if selection.is_empty() {
12158                        let cursor = movement::previous_subword_start(map, selection.head());
12159                        selection.set_head(cursor, SelectionGoal::None);
12160                    }
12161                });
12162            });
12163            this.insert("", window, cx);
12164        });
12165    }
12166
12167    pub fn move_to_next_word_end(
12168        &mut self,
12169        _: &MoveToNextWordEnd,
12170        window: &mut Window,
12171        cx: &mut Context<Self>,
12172    ) {
12173        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12174        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12175            s.move_cursors_with(|map, head, _| {
12176                (movement::next_word_end(map, head), SelectionGoal::None)
12177            });
12178        })
12179    }
12180
12181    pub fn move_to_next_subword_end(
12182        &mut self,
12183        _: &MoveToNextSubwordEnd,
12184        window: &mut Window,
12185        cx: &mut Context<Self>,
12186    ) {
12187        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12188        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12189            s.move_cursors_with(|map, head, _| {
12190                (movement::next_subword_end(map, head), SelectionGoal::None)
12191            });
12192        })
12193    }
12194
12195    pub fn select_to_next_word_end(
12196        &mut self,
12197        _: &SelectToNextWordEnd,
12198        window: &mut Window,
12199        cx: &mut Context<Self>,
12200    ) {
12201        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12202        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12203            s.move_heads_with(|map, head, _| {
12204                (movement::next_word_end(map, head), SelectionGoal::None)
12205            });
12206        })
12207    }
12208
12209    pub fn select_to_next_subword_end(
12210        &mut self,
12211        _: &SelectToNextSubwordEnd,
12212        window: &mut Window,
12213        cx: &mut Context<Self>,
12214    ) {
12215        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12216        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12217            s.move_heads_with(|map, head, _| {
12218                (movement::next_subword_end(map, head), SelectionGoal::None)
12219            });
12220        })
12221    }
12222
12223    pub fn delete_to_next_word_end(
12224        &mut self,
12225        action: &DeleteToNextWordEnd,
12226        window: &mut Window,
12227        cx: &mut Context<Self>,
12228    ) {
12229        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12230        self.transact(window, cx, |this, window, cx| {
12231            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12232                s.move_with(|map, selection| {
12233                    if selection.is_empty() {
12234                        let cursor = if action.ignore_newlines {
12235                            movement::next_word_end(map, selection.head())
12236                        } else {
12237                            movement::next_word_end_or_newline(map, selection.head())
12238                        };
12239                        selection.set_head(cursor, SelectionGoal::None);
12240                    }
12241                });
12242            });
12243            this.insert("", window, cx);
12244        });
12245    }
12246
12247    pub fn delete_to_next_subword_end(
12248        &mut self,
12249        _: &DeleteToNextSubwordEnd,
12250        window: &mut Window,
12251        cx: &mut Context<Self>,
12252    ) {
12253        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12254        self.transact(window, cx, |this, window, cx| {
12255            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12256                s.move_with(|map, selection| {
12257                    if selection.is_empty() {
12258                        let cursor = movement::next_subword_end(map, selection.head());
12259                        selection.set_head(cursor, SelectionGoal::None);
12260                    }
12261                });
12262            });
12263            this.insert("", window, cx);
12264        });
12265    }
12266
12267    pub fn move_to_beginning_of_line(
12268        &mut self,
12269        action: &MoveToBeginningOfLine,
12270        window: &mut Window,
12271        cx: &mut Context<Self>,
12272    ) {
12273        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12274        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12275            s.move_cursors_with(|map, head, _| {
12276                (
12277                    movement::indented_line_beginning(
12278                        map,
12279                        head,
12280                        action.stop_at_soft_wraps,
12281                        action.stop_at_indent,
12282                    ),
12283                    SelectionGoal::None,
12284                )
12285            });
12286        })
12287    }
12288
12289    pub fn select_to_beginning_of_line(
12290        &mut self,
12291        action: &SelectToBeginningOfLine,
12292        window: &mut Window,
12293        cx: &mut Context<Self>,
12294    ) {
12295        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12296        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12297            s.move_heads_with(|map, head, _| {
12298                (
12299                    movement::indented_line_beginning(
12300                        map,
12301                        head,
12302                        action.stop_at_soft_wraps,
12303                        action.stop_at_indent,
12304                    ),
12305                    SelectionGoal::None,
12306                )
12307            });
12308        });
12309    }
12310
12311    pub fn delete_to_beginning_of_line(
12312        &mut self,
12313        action: &DeleteToBeginningOfLine,
12314        window: &mut Window,
12315        cx: &mut Context<Self>,
12316    ) {
12317        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12318        self.transact(window, cx, |this, window, cx| {
12319            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12320                s.move_with(|_, selection| {
12321                    selection.reversed = true;
12322                });
12323            });
12324
12325            this.select_to_beginning_of_line(
12326                &SelectToBeginningOfLine {
12327                    stop_at_soft_wraps: false,
12328                    stop_at_indent: action.stop_at_indent,
12329                },
12330                window,
12331                cx,
12332            );
12333            this.backspace(&Backspace, window, cx);
12334        });
12335    }
12336
12337    pub fn move_to_end_of_line(
12338        &mut self,
12339        action: &MoveToEndOfLine,
12340        window: &mut Window,
12341        cx: &mut Context<Self>,
12342    ) {
12343        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12344        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12345            s.move_cursors_with(|map, head, _| {
12346                (
12347                    movement::line_end(map, head, action.stop_at_soft_wraps),
12348                    SelectionGoal::None,
12349                )
12350            });
12351        })
12352    }
12353
12354    pub fn select_to_end_of_line(
12355        &mut self,
12356        action: &SelectToEndOfLine,
12357        window: &mut Window,
12358        cx: &mut Context<Self>,
12359    ) {
12360        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12361        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12362            s.move_heads_with(|map, head, _| {
12363                (
12364                    movement::line_end(map, head, action.stop_at_soft_wraps),
12365                    SelectionGoal::None,
12366                )
12367            });
12368        })
12369    }
12370
12371    pub fn delete_to_end_of_line(
12372        &mut self,
12373        _: &DeleteToEndOfLine,
12374        window: &mut Window,
12375        cx: &mut Context<Self>,
12376    ) {
12377        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12378        self.transact(window, cx, |this, window, cx| {
12379            this.select_to_end_of_line(
12380                &SelectToEndOfLine {
12381                    stop_at_soft_wraps: false,
12382                },
12383                window,
12384                cx,
12385            );
12386            this.delete(&Delete, window, cx);
12387        });
12388    }
12389
12390    pub fn cut_to_end_of_line(
12391        &mut self,
12392        _: &CutToEndOfLine,
12393        window: &mut Window,
12394        cx: &mut Context<Self>,
12395    ) {
12396        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12397        self.transact(window, cx, |this, window, cx| {
12398            this.select_to_end_of_line(
12399                &SelectToEndOfLine {
12400                    stop_at_soft_wraps: false,
12401                },
12402                window,
12403                cx,
12404            );
12405            this.cut(&Cut, window, cx);
12406        });
12407    }
12408
12409    pub fn move_to_start_of_paragraph(
12410        &mut self,
12411        _: &MoveToStartOfParagraph,
12412        window: &mut Window,
12413        cx: &mut Context<Self>,
12414    ) {
12415        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12416            cx.propagate();
12417            return;
12418        }
12419        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12420        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12421            s.move_with(|map, selection| {
12422                selection.collapse_to(
12423                    movement::start_of_paragraph(map, selection.head(), 1),
12424                    SelectionGoal::None,
12425                )
12426            });
12427        })
12428    }
12429
12430    pub fn move_to_end_of_paragraph(
12431        &mut self,
12432        _: &MoveToEndOfParagraph,
12433        window: &mut Window,
12434        cx: &mut Context<Self>,
12435    ) {
12436        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12437            cx.propagate();
12438            return;
12439        }
12440        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12441        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12442            s.move_with(|map, selection| {
12443                selection.collapse_to(
12444                    movement::end_of_paragraph(map, selection.head(), 1),
12445                    SelectionGoal::None,
12446                )
12447            });
12448        })
12449    }
12450
12451    pub fn select_to_start_of_paragraph(
12452        &mut self,
12453        _: &SelectToStartOfParagraph,
12454        window: &mut Window,
12455        cx: &mut Context<Self>,
12456    ) {
12457        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12458            cx.propagate();
12459            return;
12460        }
12461        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12462        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12463            s.move_heads_with(|map, head, _| {
12464                (
12465                    movement::start_of_paragraph(map, head, 1),
12466                    SelectionGoal::None,
12467                )
12468            });
12469        })
12470    }
12471
12472    pub fn select_to_end_of_paragraph(
12473        &mut self,
12474        _: &SelectToEndOfParagraph,
12475        window: &mut Window,
12476        cx: &mut Context<Self>,
12477    ) {
12478        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12479            cx.propagate();
12480            return;
12481        }
12482        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12483        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12484            s.move_heads_with(|map, head, _| {
12485                (
12486                    movement::end_of_paragraph(map, head, 1),
12487                    SelectionGoal::None,
12488                )
12489            });
12490        })
12491    }
12492
12493    pub fn move_to_start_of_excerpt(
12494        &mut self,
12495        _: &MoveToStartOfExcerpt,
12496        window: &mut Window,
12497        cx: &mut Context<Self>,
12498    ) {
12499        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12500            cx.propagate();
12501            return;
12502        }
12503        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12504        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12505            s.move_with(|map, selection| {
12506                selection.collapse_to(
12507                    movement::start_of_excerpt(
12508                        map,
12509                        selection.head(),
12510                        workspace::searchable::Direction::Prev,
12511                    ),
12512                    SelectionGoal::None,
12513                )
12514            });
12515        })
12516    }
12517
12518    pub fn move_to_start_of_next_excerpt(
12519        &mut self,
12520        _: &MoveToStartOfNextExcerpt,
12521        window: &mut Window,
12522        cx: &mut Context<Self>,
12523    ) {
12524        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12525            cx.propagate();
12526            return;
12527        }
12528
12529        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12530            s.move_with(|map, selection| {
12531                selection.collapse_to(
12532                    movement::start_of_excerpt(
12533                        map,
12534                        selection.head(),
12535                        workspace::searchable::Direction::Next,
12536                    ),
12537                    SelectionGoal::None,
12538                )
12539            });
12540        })
12541    }
12542
12543    pub fn move_to_end_of_excerpt(
12544        &mut self,
12545        _: &MoveToEndOfExcerpt,
12546        window: &mut Window,
12547        cx: &mut Context<Self>,
12548    ) {
12549        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12550            cx.propagate();
12551            return;
12552        }
12553        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12554        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12555            s.move_with(|map, selection| {
12556                selection.collapse_to(
12557                    movement::end_of_excerpt(
12558                        map,
12559                        selection.head(),
12560                        workspace::searchable::Direction::Next,
12561                    ),
12562                    SelectionGoal::None,
12563                )
12564            });
12565        })
12566    }
12567
12568    pub fn move_to_end_of_previous_excerpt(
12569        &mut self,
12570        _: &MoveToEndOfPreviousExcerpt,
12571        window: &mut Window,
12572        cx: &mut Context<Self>,
12573    ) {
12574        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12575            cx.propagate();
12576            return;
12577        }
12578        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12579        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12580            s.move_with(|map, selection| {
12581                selection.collapse_to(
12582                    movement::end_of_excerpt(
12583                        map,
12584                        selection.head(),
12585                        workspace::searchable::Direction::Prev,
12586                    ),
12587                    SelectionGoal::None,
12588                )
12589            });
12590        })
12591    }
12592
12593    pub fn select_to_start_of_excerpt(
12594        &mut self,
12595        _: &SelectToStartOfExcerpt,
12596        window: &mut Window,
12597        cx: &mut Context<Self>,
12598    ) {
12599        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12600            cx.propagate();
12601            return;
12602        }
12603        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12604        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12605            s.move_heads_with(|map, head, _| {
12606                (
12607                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12608                    SelectionGoal::None,
12609                )
12610            });
12611        })
12612    }
12613
12614    pub fn select_to_start_of_next_excerpt(
12615        &mut self,
12616        _: &SelectToStartOfNextExcerpt,
12617        window: &mut Window,
12618        cx: &mut Context<Self>,
12619    ) {
12620        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12621            cx.propagate();
12622            return;
12623        }
12624        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12625        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12626            s.move_heads_with(|map, head, _| {
12627                (
12628                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12629                    SelectionGoal::None,
12630                )
12631            });
12632        })
12633    }
12634
12635    pub fn select_to_end_of_excerpt(
12636        &mut self,
12637        _: &SelectToEndOfExcerpt,
12638        window: &mut Window,
12639        cx: &mut Context<Self>,
12640    ) {
12641        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12642            cx.propagate();
12643            return;
12644        }
12645        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12646        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12647            s.move_heads_with(|map, head, _| {
12648                (
12649                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12650                    SelectionGoal::None,
12651                )
12652            });
12653        })
12654    }
12655
12656    pub fn select_to_end_of_previous_excerpt(
12657        &mut self,
12658        _: &SelectToEndOfPreviousExcerpt,
12659        window: &mut Window,
12660        cx: &mut Context<Self>,
12661    ) {
12662        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12663            cx.propagate();
12664            return;
12665        }
12666        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12667        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12668            s.move_heads_with(|map, head, _| {
12669                (
12670                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12671                    SelectionGoal::None,
12672                )
12673            });
12674        })
12675    }
12676
12677    pub fn move_to_beginning(
12678        &mut self,
12679        _: &MoveToBeginning,
12680        window: &mut Window,
12681        cx: &mut Context<Self>,
12682    ) {
12683        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12684            cx.propagate();
12685            return;
12686        }
12687        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12688        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12689            s.select_ranges(vec![0..0]);
12690        });
12691    }
12692
12693    pub fn select_to_beginning(
12694        &mut self,
12695        _: &SelectToBeginning,
12696        window: &mut Window,
12697        cx: &mut Context<Self>,
12698    ) {
12699        let mut selection = self.selections.last::<Point>(cx);
12700        selection.set_head(Point::zero(), SelectionGoal::None);
12701        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12702        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12703            s.select(vec![selection]);
12704        });
12705    }
12706
12707    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12708        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12709            cx.propagate();
12710            return;
12711        }
12712        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12713        let cursor = self.buffer.read(cx).read(cx).len();
12714        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12715            s.select_ranges(vec![cursor..cursor])
12716        });
12717    }
12718
12719    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12720        self.nav_history = nav_history;
12721    }
12722
12723    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12724        self.nav_history.as_ref()
12725    }
12726
12727    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12728        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12729    }
12730
12731    fn push_to_nav_history(
12732        &mut self,
12733        cursor_anchor: Anchor,
12734        new_position: Option<Point>,
12735        is_deactivate: bool,
12736        cx: &mut Context<Self>,
12737    ) {
12738        if let Some(nav_history) = self.nav_history.as_mut() {
12739            let buffer = self.buffer.read(cx).read(cx);
12740            let cursor_position = cursor_anchor.to_point(&buffer);
12741            let scroll_state = self.scroll_manager.anchor();
12742            let scroll_top_row = scroll_state.top_row(&buffer);
12743            drop(buffer);
12744
12745            if let Some(new_position) = new_position {
12746                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12747                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12748                    return;
12749                }
12750            }
12751
12752            nav_history.push(
12753                Some(NavigationData {
12754                    cursor_anchor,
12755                    cursor_position,
12756                    scroll_anchor: scroll_state,
12757                    scroll_top_row,
12758                }),
12759                cx,
12760            );
12761            cx.emit(EditorEvent::PushedToNavHistory {
12762                anchor: cursor_anchor,
12763                is_deactivate,
12764            })
12765        }
12766    }
12767
12768    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12769        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12770        let buffer = self.buffer.read(cx).snapshot(cx);
12771        let mut selection = self.selections.first::<usize>(cx);
12772        selection.set_head(buffer.len(), SelectionGoal::None);
12773        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12774            s.select(vec![selection]);
12775        });
12776    }
12777
12778    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12779        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12780        let end = self.buffer.read(cx).read(cx).len();
12781        self.change_selections(None, window, cx, |s| {
12782            s.select_ranges(vec![0..end]);
12783        });
12784    }
12785
12786    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12787        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12788        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12789        let mut selections = self.selections.all::<Point>(cx);
12790        let max_point = display_map.buffer_snapshot.max_point();
12791        for selection in &mut selections {
12792            let rows = selection.spanned_rows(true, &display_map);
12793            selection.start = Point::new(rows.start.0, 0);
12794            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12795            selection.reversed = false;
12796        }
12797        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12798            s.select(selections);
12799        });
12800    }
12801
12802    pub fn split_selection_into_lines(
12803        &mut self,
12804        _: &SplitSelectionIntoLines,
12805        window: &mut Window,
12806        cx: &mut Context<Self>,
12807    ) {
12808        let selections = self
12809            .selections
12810            .all::<Point>(cx)
12811            .into_iter()
12812            .map(|selection| selection.start..selection.end)
12813            .collect::<Vec<_>>();
12814        self.unfold_ranges(&selections, true, true, cx);
12815
12816        let mut new_selection_ranges = Vec::new();
12817        {
12818            let buffer = self.buffer.read(cx).read(cx);
12819            for selection in selections {
12820                for row in selection.start.row..selection.end.row {
12821                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12822                    new_selection_ranges.push(cursor..cursor);
12823                }
12824
12825                let is_multiline_selection = selection.start.row != selection.end.row;
12826                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12827                // so this action feels more ergonomic when paired with other selection operations
12828                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12829                if !should_skip_last {
12830                    new_selection_ranges.push(selection.end..selection.end);
12831                }
12832            }
12833        }
12834        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12835            s.select_ranges(new_selection_ranges);
12836        });
12837    }
12838
12839    pub fn add_selection_above(
12840        &mut self,
12841        _: &AddSelectionAbove,
12842        window: &mut Window,
12843        cx: &mut Context<Self>,
12844    ) {
12845        self.add_selection(true, window, cx);
12846    }
12847
12848    pub fn add_selection_below(
12849        &mut self,
12850        _: &AddSelectionBelow,
12851        window: &mut Window,
12852        cx: &mut Context<Self>,
12853    ) {
12854        self.add_selection(false, window, cx);
12855    }
12856
12857    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12858        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12859
12860        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12861        let all_selections = self.selections.all::<Point>(cx);
12862        let text_layout_details = self.text_layout_details(window);
12863
12864        let (mut columnar_selections, new_selections_to_columnarize) = {
12865            if let Some(state) = self.add_selections_state.as_ref() {
12866                let columnar_selection_ids: HashSet<_> = state
12867                    .groups
12868                    .iter()
12869                    .flat_map(|group| group.stack.iter())
12870                    .copied()
12871                    .collect();
12872
12873                all_selections
12874                    .into_iter()
12875                    .partition(|s| columnar_selection_ids.contains(&s.id))
12876            } else {
12877                (Vec::new(), all_selections)
12878            }
12879        };
12880
12881        let mut state = self
12882            .add_selections_state
12883            .take()
12884            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12885
12886        for selection in new_selections_to_columnarize {
12887            let range = selection.display_range(&display_map).sorted();
12888            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12889            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12890            let positions = start_x.min(end_x)..start_x.max(end_x);
12891            let mut stack = Vec::new();
12892            for row in range.start.row().0..=range.end.row().0 {
12893                if let Some(selection) = self.selections.build_columnar_selection(
12894                    &display_map,
12895                    DisplayRow(row),
12896                    &positions,
12897                    selection.reversed,
12898                    &text_layout_details,
12899                ) {
12900                    stack.push(selection.id);
12901                    columnar_selections.push(selection);
12902                }
12903            }
12904            if !stack.is_empty() {
12905                if above {
12906                    stack.reverse();
12907                }
12908                state.groups.push(AddSelectionsGroup { above, stack });
12909            }
12910        }
12911
12912        let mut final_selections = Vec::new();
12913        let end_row = if above {
12914            DisplayRow(0)
12915        } else {
12916            display_map.max_point().row()
12917        };
12918
12919        let mut last_added_item_per_group = HashMap::default();
12920        for group in state.groups.iter_mut() {
12921            if let Some(last_id) = group.stack.last() {
12922                last_added_item_per_group.insert(*last_id, group);
12923            }
12924        }
12925
12926        for selection in columnar_selections {
12927            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
12928                if above == group.above {
12929                    let range = selection.display_range(&display_map).sorted();
12930                    debug_assert_eq!(range.start.row(), range.end.row());
12931                    let mut row = range.start.row();
12932                    let positions =
12933                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12934                            px(start)..px(end)
12935                        } else {
12936                            let start_x =
12937                                display_map.x_for_display_point(range.start, &text_layout_details);
12938                            let end_x =
12939                                display_map.x_for_display_point(range.end, &text_layout_details);
12940                            start_x.min(end_x)..start_x.max(end_x)
12941                        };
12942
12943                    let mut maybe_new_selection = None;
12944                    while row != end_row {
12945                        if above {
12946                            row.0 -= 1;
12947                        } else {
12948                            row.0 += 1;
12949                        }
12950                        if let Some(new_selection) = self.selections.build_columnar_selection(
12951                            &display_map,
12952                            row,
12953                            &positions,
12954                            selection.reversed,
12955                            &text_layout_details,
12956                        ) {
12957                            maybe_new_selection = Some(new_selection);
12958                            break;
12959                        }
12960                    }
12961
12962                    if let Some(new_selection) = maybe_new_selection {
12963                        group.stack.push(new_selection.id);
12964                        if above {
12965                            final_selections.push(new_selection);
12966                            final_selections.push(selection);
12967                        } else {
12968                            final_selections.push(selection);
12969                            final_selections.push(new_selection);
12970                        }
12971                    } else {
12972                        final_selections.push(selection);
12973                    }
12974                } else {
12975                    group.stack.pop();
12976                }
12977            } else {
12978                final_selections.push(selection);
12979            }
12980        }
12981
12982        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12983            s.select(final_selections);
12984        });
12985
12986        let final_selection_ids: HashSet<_> = self
12987            .selections
12988            .all::<Point>(cx)
12989            .iter()
12990            .map(|s| s.id)
12991            .collect();
12992        state.groups.retain_mut(|group| {
12993            // selections might get merged above so we remove invalid items from stacks
12994            group.stack.retain(|id| final_selection_ids.contains(id));
12995
12996            // single selection in stack can be treated as initial state
12997            group.stack.len() > 1
12998        });
12999
13000        if !state.groups.is_empty() {
13001            self.add_selections_state = Some(state);
13002        }
13003    }
13004
13005    fn select_match_ranges(
13006        &mut self,
13007        range: Range<usize>,
13008        reversed: bool,
13009        replace_newest: bool,
13010        auto_scroll: Option<Autoscroll>,
13011        window: &mut Window,
13012        cx: &mut Context<Editor>,
13013    ) {
13014        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13015        self.change_selections(auto_scroll, window, cx, |s| {
13016            if replace_newest {
13017                s.delete(s.newest_anchor().id);
13018            }
13019            if reversed {
13020                s.insert_range(range.end..range.start);
13021            } else {
13022                s.insert_range(range);
13023            }
13024        });
13025    }
13026
13027    pub fn select_next_match_internal(
13028        &mut self,
13029        display_map: &DisplaySnapshot,
13030        replace_newest: bool,
13031        autoscroll: Option<Autoscroll>,
13032        window: &mut Window,
13033        cx: &mut Context<Self>,
13034    ) -> Result<()> {
13035        let buffer = &display_map.buffer_snapshot;
13036        let mut selections = self.selections.all::<usize>(cx);
13037        if let Some(mut select_next_state) = self.select_next_state.take() {
13038            let query = &select_next_state.query;
13039            if !select_next_state.done {
13040                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13041                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13042                let mut next_selected_range = None;
13043
13044                let bytes_after_last_selection =
13045                    buffer.bytes_in_range(last_selection.end..buffer.len());
13046                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13047                let query_matches = query
13048                    .stream_find_iter(bytes_after_last_selection)
13049                    .map(|result| (last_selection.end, result))
13050                    .chain(
13051                        query
13052                            .stream_find_iter(bytes_before_first_selection)
13053                            .map(|result| (0, result)),
13054                    );
13055
13056                for (start_offset, query_match) in query_matches {
13057                    let query_match = query_match.unwrap(); // can only fail due to I/O
13058                    let offset_range =
13059                        start_offset + query_match.start()..start_offset + query_match.end();
13060                    let display_range = offset_range.start.to_display_point(display_map)
13061                        ..offset_range.end.to_display_point(display_map);
13062
13063                    if !select_next_state.wordwise
13064                        || (!movement::is_inside_word(display_map, display_range.start)
13065                            && !movement::is_inside_word(display_map, display_range.end))
13066                    {
13067                        // TODO: This is n^2, because we might check all the selections
13068                        if !selections
13069                            .iter()
13070                            .any(|selection| selection.range().overlaps(&offset_range))
13071                        {
13072                            next_selected_range = Some(offset_range);
13073                            break;
13074                        }
13075                    }
13076                }
13077
13078                if let Some(next_selected_range) = next_selected_range {
13079                    self.select_match_ranges(
13080                        next_selected_range,
13081                        last_selection.reversed,
13082                        replace_newest,
13083                        autoscroll,
13084                        window,
13085                        cx,
13086                    );
13087                } else {
13088                    select_next_state.done = true;
13089                }
13090            }
13091
13092            self.select_next_state = Some(select_next_state);
13093        } else {
13094            let mut only_carets = true;
13095            let mut same_text_selected = true;
13096            let mut selected_text = None;
13097
13098            let mut selections_iter = selections.iter().peekable();
13099            while let Some(selection) = selections_iter.next() {
13100                if selection.start != selection.end {
13101                    only_carets = false;
13102                }
13103
13104                if same_text_selected {
13105                    if selected_text.is_none() {
13106                        selected_text =
13107                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13108                    }
13109
13110                    if let Some(next_selection) = selections_iter.peek() {
13111                        if next_selection.range().len() == selection.range().len() {
13112                            let next_selected_text = buffer
13113                                .text_for_range(next_selection.range())
13114                                .collect::<String>();
13115                            if Some(next_selected_text) != selected_text {
13116                                same_text_selected = false;
13117                                selected_text = None;
13118                            }
13119                        } else {
13120                            same_text_selected = false;
13121                            selected_text = None;
13122                        }
13123                    }
13124                }
13125            }
13126
13127            if only_carets {
13128                for selection in &mut selections {
13129                    let word_range = movement::surrounding_word(
13130                        display_map,
13131                        selection.start.to_display_point(display_map),
13132                    );
13133                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13134                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13135                    selection.goal = SelectionGoal::None;
13136                    selection.reversed = false;
13137                    self.select_match_ranges(
13138                        selection.start..selection.end,
13139                        selection.reversed,
13140                        replace_newest,
13141                        autoscroll,
13142                        window,
13143                        cx,
13144                    );
13145                }
13146
13147                if selections.len() == 1 {
13148                    let selection = selections
13149                        .last()
13150                        .expect("ensured that there's only one selection");
13151                    let query = buffer
13152                        .text_for_range(selection.start..selection.end)
13153                        .collect::<String>();
13154                    let is_empty = query.is_empty();
13155                    let select_state = SelectNextState {
13156                        query: AhoCorasick::new(&[query])?,
13157                        wordwise: true,
13158                        done: is_empty,
13159                    };
13160                    self.select_next_state = Some(select_state);
13161                } else {
13162                    self.select_next_state = None;
13163                }
13164            } else if let Some(selected_text) = selected_text {
13165                self.select_next_state = Some(SelectNextState {
13166                    query: AhoCorasick::new(&[selected_text])?,
13167                    wordwise: false,
13168                    done: false,
13169                });
13170                self.select_next_match_internal(
13171                    display_map,
13172                    replace_newest,
13173                    autoscroll,
13174                    window,
13175                    cx,
13176                )?;
13177            }
13178        }
13179        Ok(())
13180    }
13181
13182    pub fn select_all_matches(
13183        &mut self,
13184        _action: &SelectAllMatches,
13185        window: &mut Window,
13186        cx: &mut Context<Self>,
13187    ) -> Result<()> {
13188        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13189
13190        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13191
13192        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13193        let Some(select_next_state) = self.select_next_state.as_mut() else {
13194            return Ok(());
13195        };
13196        if select_next_state.done {
13197            return Ok(());
13198        }
13199
13200        let mut new_selections = Vec::new();
13201
13202        let reversed = self.selections.oldest::<usize>(cx).reversed;
13203        let buffer = &display_map.buffer_snapshot;
13204        let query_matches = select_next_state
13205            .query
13206            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13207
13208        for query_match in query_matches.into_iter() {
13209            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13210            let offset_range = if reversed {
13211                query_match.end()..query_match.start()
13212            } else {
13213                query_match.start()..query_match.end()
13214            };
13215            let display_range = offset_range.start.to_display_point(&display_map)
13216                ..offset_range.end.to_display_point(&display_map);
13217
13218            if !select_next_state.wordwise
13219                || (!movement::is_inside_word(&display_map, display_range.start)
13220                    && !movement::is_inside_word(&display_map, display_range.end))
13221            {
13222                new_selections.push(offset_range.start..offset_range.end);
13223            }
13224        }
13225
13226        select_next_state.done = true;
13227        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13228        self.change_selections(None, window, cx, |selections| {
13229            selections.select_ranges(new_selections)
13230        });
13231
13232        Ok(())
13233    }
13234
13235    pub fn select_next(
13236        &mut self,
13237        action: &SelectNext,
13238        window: &mut Window,
13239        cx: &mut Context<Self>,
13240    ) -> Result<()> {
13241        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13242        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13243        self.select_next_match_internal(
13244            &display_map,
13245            action.replace_newest,
13246            Some(Autoscroll::newest()),
13247            window,
13248            cx,
13249        )?;
13250        Ok(())
13251    }
13252
13253    pub fn select_previous(
13254        &mut self,
13255        action: &SelectPrevious,
13256        window: &mut Window,
13257        cx: &mut Context<Self>,
13258    ) -> Result<()> {
13259        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13260        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13261        let buffer = &display_map.buffer_snapshot;
13262        let mut selections = self.selections.all::<usize>(cx);
13263        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13264            let query = &select_prev_state.query;
13265            if !select_prev_state.done {
13266                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13267                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13268                let mut next_selected_range = None;
13269                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13270                let bytes_before_last_selection =
13271                    buffer.reversed_bytes_in_range(0..last_selection.start);
13272                let bytes_after_first_selection =
13273                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13274                let query_matches = query
13275                    .stream_find_iter(bytes_before_last_selection)
13276                    .map(|result| (last_selection.start, result))
13277                    .chain(
13278                        query
13279                            .stream_find_iter(bytes_after_first_selection)
13280                            .map(|result| (buffer.len(), result)),
13281                    );
13282                for (end_offset, query_match) in query_matches {
13283                    let query_match = query_match.unwrap(); // can only fail due to I/O
13284                    let offset_range =
13285                        end_offset - query_match.end()..end_offset - query_match.start();
13286                    let display_range = offset_range.start.to_display_point(&display_map)
13287                        ..offset_range.end.to_display_point(&display_map);
13288
13289                    if !select_prev_state.wordwise
13290                        || (!movement::is_inside_word(&display_map, display_range.start)
13291                            && !movement::is_inside_word(&display_map, display_range.end))
13292                    {
13293                        next_selected_range = Some(offset_range);
13294                        break;
13295                    }
13296                }
13297
13298                if let Some(next_selected_range) = next_selected_range {
13299                    self.select_match_ranges(
13300                        next_selected_range,
13301                        last_selection.reversed,
13302                        action.replace_newest,
13303                        Some(Autoscroll::newest()),
13304                        window,
13305                        cx,
13306                    );
13307                } else {
13308                    select_prev_state.done = true;
13309                }
13310            }
13311
13312            self.select_prev_state = Some(select_prev_state);
13313        } else {
13314            let mut only_carets = true;
13315            let mut same_text_selected = true;
13316            let mut selected_text = None;
13317
13318            let mut selections_iter = selections.iter().peekable();
13319            while let Some(selection) = selections_iter.next() {
13320                if selection.start != selection.end {
13321                    only_carets = false;
13322                }
13323
13324                if same_text_selected {
13325                    if selected_text.is_none() {
13326                        selected_text =
13327                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13328                    }
13329
13330                    if let Some(next_selection) = selections_iter.peek() {
13331                        if next_selection.range().len() == selection.range().len() {
13332                            let next_selected_text = buffer
13333                                .text_for_range(next_selection.range())
13334                                .collect::<String>();
13335                            if Some(next_selected_text) != selected_text {
13336                                same_text_selected = false;
13337                                selected_text = None;
13338                            }
13339                        } else {
13340                            same_text_selected = false;
13341                            selected_text = None;
13342                        }
13343                    }
13344                }
13345            }
13346
13347            if only_carets {
13348                for selection in &mut selections {
13349                    let word_range = movement::surrounding_word(
13350                        &display_map,
13351                        selection.start.to_display_point(&display_map),
13352                    );
13353                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13354                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13355                    selection.goal = SelectionGoal::None;
13356                    selection.reversed = false;
13357                    self.select_match_ranges(
13358                        selection.start..selection.end,
13359                        selection.reversed,
13360                        action.replace_newest,
13361                        Some(Autoscroll::newest()),
13362                        window,
13363                        cx,
13364                    );
13365                }
13366                if selections.len() == 1 {
13367                    let selection = selections
13368                        .last()
13369                        .expect("ensured that there's only one selection");
13370                    let query = buffer
13371                        .text_for_range(selection.start..selection.end)
13372                        .collect::<String>();
13373                    let is_empty = query.is_empty();
13374                    let select_state = SelectNextState {
13375                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13376                        wordwise: true,
13377                        done: is_empty,
13378                    };
13379                    self.select_prev_state = Some(select_state);
13380                } else {
13381                    self.select_prev_state = None;
13382                }
13383            } else if let Some(selected_text) = selected_text {
13384                self.select_prev_state = Some(SelectNextState {
13385                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13386                    wordwise: false,
13387                    done: false,
13388                });
13389                self.select_previous(action, window, cx)?;
13390            }
13391        }
13392        Ok(())
13393    }
13394
13395    pub fn find_next_match(
13396        &mut self,
13397        _: &FindNextMatch,
13398        window: &mut Window,
13399        cx: &mut Context<Self>,
13400    ) -> Result<()> {
13401        let selections = self.selections.disjoint_anchors();
13402        match selections.first() {
13403            Some(first) if selections.len() >= 2 => {
13404                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13405                    s.select_ranges([first.range()]);
13406                });
13407            }
13408            _ => self.select_next(
13409                &SelectNext {
13410                    replace_newest: true,
13411                },
13412                window,
13413                cx,
13414            )?,
13415        }
13416        Ok(())
13417    }
13418
13419    pub fn find_previous_match(
13420        &mut self,
13421        _: &FindPreviousMatch,
13422        window: &mut Window,
13423        cx: &mut Context<Self>,
13424    ) -> Result<()> {
13425        let selections = self.selections.disjoint_anchors();
13426        match selections.last() {
13427            Some(last) if selections.len() >= 2 => {
13428                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13429                    s.select_ranges([last.range()]);
13430                });
13431            }
13432            _ => self.select_previous(
13433                &SelectPrevious {
13434                    replace_newest: true,
13435                },
13436                window,
13437                cx,
13438            )?,
13439        }
13440        Ok(())
13441    }
13442
13443    pub fn toggle_comments(
13444        &mut self,
13445        action: &ToggleComments,
13446        window: &mut Window,
13447        cx: &mut Context<Self>,
13448    ) {
13449        if self.read_only(cx) {
13450            return;
13451        }
13452        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13453        let text_layout_details = &self.text_layout_details(window);
13454        self.transact(window, cx, |this, window, cx| {
13455            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13456            let mut edits = Vec::new();
13457            let mut selection_edit_ranges = Vec::new();
13458            let mut last_toggled_row = None;
13459            let snapshot = this.buffer.read(cx).read(cx);
13460            let empty_str: Arc<str> = Arc::default();
13461            let mut suffixes_inserted = Vec::new();
13462            let ignore_indent = action.ignore_indent;
13463
13464            fn comment_prefix_range(
13465                snapshot: &MultiBufferSnapshot,
13466                row: MultiBufferRow,
13467                comment_prefix: &str,
13468                comment_prefix_whitespace: &str,
13469                ignore_indent: bool,
13470            ) -> Range<Point> {
13471                let indent_size = if ignore_indent {
13472                    0
13473                } else {
13474                    snapshot.indent_size_for_line(row).len
13475                };
13476
13477                let start = Point::new(row.0, indent_size);
13478
13479                let mut line_bytes = snapshot
13480                    .bytes_in_range(start..snapshot.max_point())
13481                    .flatten()
13482                    .copied();
13483
13484                // If this line currently begins with the line comment prefix, then record
13485                // the range containing the prefix.
13486                if line_bytes
13487                    .by_ref()
13488                    .take(comment_prefix.len())
13489                    .eq(comment_prefix.bytes())
13490                {
13491                    // Include any whitespace that matches the comment prefix.
13492                    let matching_whitespace_len = line_bytes
13493                        .zip(comment_prefix_whitespace.bytes())
13494                        .take_while(|(a, b)| a == b)
13495                        .count() as u32;
13496                    let end = Point::new(
13497                        start.row,
13498                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13499                    );
13500                    start..end
13501                } else {
13502                    start..start
13503                }
13504            }
13505
13506            fn comment_suffix_range(
13507                snapshot: &MultiBufferSnapshot,
13508                row: MultiBufferRow,
13509                comment_suffix: &str,
13510                comment_suffix_has_leading_space: bool,
13511            ) -> Range<Point> {
13512                let end = Point::new(row.0, snapshot.line_len(row));
13513                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13514
13515                let mut line_end_bytes = snapshot
13516                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13517                    .flatten()
13518                    .copied();
13519
13520                let leading_space_len = if suffix_start_column > 0
13521                    && line_end_bytes.next() == Some(b' ')
13522                    && comment_suffix_has_leading_space
13523                {
13524                    1
13525                } else {
13526                    0
13527                };
13528
13529                // If this line currently begins with the line comment prefix, then record
13530                // the range containing the prefix.
13531                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13532                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13533                    start..end
13534                } else {
13535                    end..end
13536                }
13537            }
13538
13539            // TODO: Handle selections that cross excerpts
13540            for selection in &mut selections {
13541                let start_column = snapshot
13542                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13543                    .len;
13544                let language = if let Some(language) =
13545                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13546                {
13547                    language
13548                } else {
13549                    continue;
13550                };
13551
13552                selection_edit_ranges.clear();
13553
13554                // If multiple selections contain a given row, avoid processing that
13555                // row more than once.
13556                let mut start_row = MultiBufferRow(selection.start.row);
13557                if last_toggled_row == Some(start_row) {
13558                    start_row = start_row.next_row();
13559                }
13560                let end_row =
13561                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13562                        MultiBufferRow(selection.end.row - 1)
13563                    } else {
13564                        MultiBufferRow(selection.end.row)
13565                    };
13566                last_toggled_row = Some(end_row);
13567
13568                if start_row > end_row {
13569                    continue;
13570                }
13571
13572                // If the language has line comments, toggle those.
13573                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13574
13575                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13576                if ignore_indent {
13577                    full_comment_prefixes = full_comment_prefixes
13578                        .into_iter()
13579                        .map(|s| Arc::from(s.trim_end()))
13580                        .collect();
13581                }
13582
13583                if !full_comment_prefixes.is_empty() {
13584                    let first_prefix = full_comment_prefixes
13585                        .first()
13586                        .expect("prefixes is non-empty");
13587                    let prefix_trimmed_lengths = full_comment_prefixes
13588                        .iter()
13589                        .map(|p| p.trim_end_matches(' ').len())
13590                        .collect::<SmallVec<[usize; 4]>>();
13591
13592                    let mut all_selection_lines_are_comments = true;
13593
13594                    for row in start_row.0..=end_row.0 {
13595                        let row = MultiBufferRow(row);
13596                        if start_row < end_row && snapshot.is_line_blank(row) {
13597                            continue;
13598                        }
13599
13600                        let prefix_range = full_comment_prefixes
13601                            .iter()
13602                            .zip(prefix_trimmed_lengths.iter().copied())
13603                            .map(|(prefix, trimmed_prefix_len)| {
13604                                comment_prefix_range(
13605                                    snapshot.deref(),
13606                                    row,
13607                                    &prefix[..trimmed_prefix_len],
13608                                    &prefix[trimmed_prefix_len..],
13609                                    ignore_indent,
13610                                )
13611                            })
13612                            .max_by_key(|range| range.end.column - range.start.column)
13613                            .expect("prefixes is non-empty");
13614
13615                        if prefix_range.is_empty() {
13616                            all_selection_lines_are_comments = false;
13617                        }
13618
13619                        selection_edit_ranges.push(prefix_range);
13620                    }
13621
13622                    if all_selection_lines_are_comments {
13623                        edits.extend(
13624                            selection_edit_ranges
13625                                .iter()
13626                                .cloned()
13627                                .map(|range| (range, empty_str.clone())),
13628                        );
13629                    } else {
13630                        let min_column = selection_edit_ranges
13631                            .iter()
13632                            .map(|range| range.start.column)
13633                            .min()
13634                            .unwrap_or(0);
13635                        edits.extend(selection_edit_ranges.iter().map(|range| {
13636                            let position = Point::new(range.start.row, min_column);
13637                            (position..position, first_prefix.clone())
13638                        }));
13639                    }
13640                } else if let Some((full_comment_prefix, comment_suffix)) =
13641                    language.block_comment_delimiters()
13642                {
13643                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13644                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13645                    let prefix_range = comment_prefix_range(
13646                        snapshot.deref(),
13647                        start_row,
13648                        comment_prefix,
13649                        comment_prefix_whitespace,
13650                        ignore_indent,
13651                    );
13652                    let suffix_range = comment_suffix_range(
13653                        snapshot.deref(),
13654                        end_row,
13655                        comment_suffix.trim_start_matches(' '),
13656                        comment_suffix.starts_with(' '),
13657                    );
13658
13659                    if prefix_range.is_empty() || suffix_range.is_empty() {
13660                        edits.push((
13661                            prefix_range.start..prefix_range.start,
13662                            full_comment_prefix.clone(),
13663                        ));
13664                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13665                        suffixes_inserted.push((end_row, comment_suffix.len()));
13666                    } else {
13667                        edits.push((prefix_range, empty_str.clone()));
13668                        edits.push((suffix_range, empty_str.clone()));
13669                    }
13670                } else {
13671                    continue;
13672                }
13673            }
13674
13675            drop(snapshot);
13676            this.buffer.update(cx, |buffer, cx| {
13677                buffer.edit(edits, None, cx);
13678            });
13679
13680            // Adjust selections so that they end before any comment suffixes that
13681            // were inserted.
13682            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13683            let mut selections = this.selections.all::<Point>(cx);
13684            let snapshot = this.buffer.read(cx).read(cx);
13685            for selection in &mut selections {
13686                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13687                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13688                        Ordering::Less => {
13689                            suffixes_inserted.next();
13690                            continue;
13691                        }
13692                        Ordering::Greater => break,
13693                        Ordering::Equal => {
13694                            if selection.end.column == snapshot.line_len(row) {
13695                                if selection.is_empty() {
13696                                    selection.start.column -= suffix_len as u32;
13697                                }
13698                                selection.end.column -= suffix_len as u32;
13699                            }
13700                            break;
13701                        }
13702                    }
13703                }
13704            }
13705
13706            drop(snapshot);
13707            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13708                s.select(selections)
13709            });
13710
13711            let selections = this.selections.all::<Point>(cx);
13712            let selections_on_single_row = selections.windows(2).all(|selections| {
13713                selections[0].start.row == selections[1].start.row
13714                    && selections[0].end.row == selections[1].end.row
13715                    && selections[0].start.row == selections[0].end.row
13716            });
13717            let selections_selecting = selections
13718                .iter()
13719                .any(|selection| selection.start != selection.end);
13720            let advance_downwards = action.advance_downwards
13721                && selections_on_single_row
13722                && !selections_selecting
13723                && !matches!(this.mode, EditorMode::SingleLine { .. });
13724
13725            if advance_downwards {
13726                let snapshot = this.buffer.read(cx).snapshot(cx);
13727
13728                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13729                    s.move_cursors_with(|display_snapshot, display_point, _| {
13730                        let mut point = display_point.to_point(display_snapshot);
13731                        point.row += 1;
13732                        point = snapshot.clip_point(point, Bias::Left);
13733                        let display_point = point.to_display_point(display_snapshot);
13734                        let goal = SelectionGoal::HorizontalPosition(
13735                            display_snapshot
13736                                .x_for_display_point(display_point, text_layout_details)
13737                                .into(),
13738                        );
13739                        (display_point, goal)
13740                    })
13741                });
13742            }
13743        });
13744    }
13745
13746    pub fn select_enclosing_symbol(
13747        &mut self,
13748        _: &SelectEnclosingSymbol,
13749        window: &mut Window,
13750        cx: &mut Context<Self>,
13751    ) {
13752        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13753
13754        let buffer = self.buffer.read(cx).snapshot(cx);
13755        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13756
13757        fn update_selection(
13758            selection: &Selection<usize>,
13759            buffer_snap: &MultiBufferSnapshot,
13760        ) -> Option<Selection<usize>> {
13761            let cursor = selection.head();
13762            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13763            for symbol in symbols.iter().rev() {
13764                let start = symbol.range.start.to_offset(buffer_snap);
13765                let end = symbol.range.end.to_offset(buffer_snap);
13766                let new_range = start..end;
13767                if start < selection.start || end > selection.end {
13768                    return Some(Selection {
13769                        id: selection.id,
13770                        start: new_range.start,
13771                        end: new_range.end,
13772                        goal: SelectionGoal::None,
13773                        reversed: selection.reversed,
13774                    });
13775                }
13776            }
13777            None
13778        }
13779
13780        let mut selected_larger_symbol = false;
13781        let new_selections = old_selections
13782            .iter()
13783            .map(|selection| match update_selection(selection, &buffer) {
13784                Some(new_selection) => {
13785                    if new_selection.range() != selection.range() {
13786                        selected_larger_symbol = true;
13787                    }
13788                    new_selection
13789                }
13790                None => selection.clone(),
13791            })
13792            .collect::<Vec<_>>();
13793
13794        if selected_larger_symbol {
13795            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13796                s.select(new_selections);
13797            });
13798        }
13799    }
13800
13801    pub fn select_larger_syntax_node(
13802        &mut self,
13803        _: &SelectLargerSyntaxNode,
13804        window: &mut Window,
13805        cx: &mut Context<Self>,
13806    ) {
13807        let Some(visible_row_count) = self.visible_row_count() else {
13808            return;
13809        };
13810        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13811        if old_selections.is_empty() {
13812            return;
13813        }
13814
13815        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13816
13817        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13818        let buffer = self.buffer.read(cx).snapshot(cx);
13819
13820        let mut selected_larger_node = false;
13821        let mut new_selections = old_selections
13822            .iter()
13823            .map(|selection| {
13824                let old_range = selection.start..selection.end;
13825
13826                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13827                    // manually select word at selection
13828                    if ["string_content", "inline"].contains(&node.kind()) {
13829                        let word_range = {
13830                            let display_point = buffer
13831                                .offset_to_point(old_range.start)
13832                                .to_display_point(&display_map);
13833                            let Range { start, end } =
13834                                movement::surrounding_word(&display_map, display_point);
13835                            start.to_point(&display_map).to_offset(&buffer)
13836                                ..end.to_point(&display_map).to_offset(&buffer)
13837                        };
13838                        // ignore if word is already selected
13839                        if !word_range.is_empty() && old_range != word_range {
13840                            let last_word_range = {
13841                                let display_point = buffer
13842                                    .offset_to_point(old_range.end)
13843                                    .to_display_point(&display_map);
13844                                let Range { start, end } =
13845                                    movement::surrounding_word(&display_map, display_point);
13846                                start.to_point(&display_map).to_offset(&buffer)
13847                                    ..end.to_point(&display_map).to_offset(&buffer)
13848                            };
13849                            // only select word if start and end point belongs to same word
13850                            if word_range == last_word_range {
13851                                selected_larger_node = true;
13852                                return Selection {
13853                                    id: selection.id,
13854                                    start: word_range.start,
13855                                    end: word_range.end,
13856                                    goal: SelectionGoal::None,
13857                                    reversed: selection.reversed,
13858                                };
13859                            }
13860                        }
13861                    }
13862                }
13863
13864                let mut new_range = old_range.clone();
13865                while let Some((_node, containing_range)) =
13866                    buffer.syntax_ancestor(new_range.clone())
13867                {
13868                    new_range = match containing_range {
13869                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13870                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13871                    };
13872                    if !display_map.intersects_fold(new_range.start)
13873                        && !display_map.intersects_fold(new_range.end)
13874                    {
13875                        break;
13876                    }
13877                }
13878
13879                selected_larger_node |= new_range != old_range;
13880                Selection {
13881                    id: selection.id,
13882                    start: new_range.start,
13883                    end: new_range.end,
13884                    goal: SelectionGoal::None,
13885                    reversed: selection.reversed,
13886                }
13887            })
13888            .collect::<Vec<_>>();
13889
13890        if !selected_larger_node {
13891            return; // don't put this call in the history
13892        }
13893
13894        // scroll based on transformation done to the last selection created by the user
13895        let (last_old, last_new) = old_selections
13896            .last()
13897            .zip(new_selections.last().cloned())
13898            .expect("old_selections isn't empty");
13899
13900        // revert selection
13901        let is_selection_reversed = {
13902            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13903            new_selections.last_mut().expect("checked above").reversed =
13904                should_newest_selection_be_reversed;
13905            should_newest_selection_be_reversed
13906        };
13907
13908        if selected_larger_node {
13909            self.select_syntax_node_history.disable_clearing = true;
13910            self.change_selections(None, window, cx, |s| {
13911                s.select(new_selections.clone());
13912            });
13913            self.select_syntax_node_history.disable_clearing = false;
13914        }
13915
13916        let start_row = last_new.start.to_display_point(&display_map).row().0;
13917        let end_row = last_new.end.to_display_point(&display_map).row().0;
13918        let selection_height = end_row - start_row + 1;
13919        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13920
13921        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13922        let scroll_behavior = if fits_on_the_screen {
13923            self.request_autoscroll(Autoscroll::fit(), cx);
13924            SelectSyntaxNodeScrollBehavior::FitSelection
13925        } else if is_selection_reversed {
13926            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13927            SelectSyntaxNodeScrollBehavior::CursorTop
13928        } else {
13929            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13930            SelectSyntaxNodeScrollBehavior::CursorBottom
13931        };
13932
13933        self.select_syntax_node_history.push((
13934            old_selections,
13935            scroll_behavior,
13936            is_selection_reversed,
13937        ));
13938    }
13939
13940    pub fn select_smaller_syntax_node(
13941        &mut self,
13942        _: &SelectSmallerSyntaxNode,
13943        window: &mut Window,
13944        cx: &mut Context<Self>,
13945    ) {
13946        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13947
13948        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13949            self.select_syntax_node_history.pop()
13950        {
13951            if let Some(selection) = selections.last_mut() {
13952                selection.reversed = is_selection_reversed;
13953            }
13954
13955            self.select_syntax_node_history.disable_clearing = true;
13956            self.change_selections(None, window, cx, |s| {
13957                s.select(selections.to_vec());
13958            });
13959            self.select_syntax_node_history.disable_clearing = false;
13960
13961            match scroll_behavior {
13962                SelectSyntaxNodeScrollBehavior::CursorTop => {
13963                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13964                }
13965                SelectSyntaxNodeScrollBehavior::FitSelection => {
13966                    self.request_autoscroll(Autoscroll::fit(), cx);
13967                }
13968                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13969                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13970                }
13971            }
13972        }
13973    }
13974
13975    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13976        if !EditorSettings::get_global(cx).gutter.runnables {
13977            self.clear_tasks();
13978            return Task::ready(());
13979        }
13980        let project = self.project.as_ref().map(Entity::downgrade);
13981        let task_sources = self.lsp_task_sources(cx);
13982        let multi_buffer = self.buffer.downgrade();
13983        cx.spawn_in(window, async move |editor, cx| {
13984            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13985            let Some(project) = project.and_then(|p| p.upgrade()) else {
13986                return;
13987            };
13988            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13989                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13990            }) else {
13991                return;
13992            };
13993
13994            let hide_runnables = project
13995                .update(cx, |project, cx| {
13996                    // Do not display any test indicators in non-dev server remote projects.
13997                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13998                })
13999                .unwrap_or(true);
14000            if hide_runnables {
14001                return;
14002            }
14003            let new_rows =
14004                cx.background_spawn({
14005                    let snapshot = display_snapshot.clone();
14006                    async move {
14007                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14008                    }
14009                })
14010                    .await;
14011            let Ok(lsp_tasks) =
14012                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14013            else {
14014                return;
14015            };
14016            let lsp_tasks = lsp_tasks.await;
14017
14018            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14019                lsp_tasks
14020                    .into_iter()
14021                    .flat_map(|(kind, tasks)| {
14022                        tasks.into_iter().filter_map(move |(location, task)| {
14023                            Some((kind.clone(), location?, task))
14024                        })
14025                    })
14026                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14027                        let buffer = location.target.buffer;
14028                        let buffer_snapshot = buffer.read(cx).snapshot();
14029                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14030                            |(excerpt_id, snapshot, _)| {
14031                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14032                                    display_snapshot
14033                                        .buffer_snapshot
14034                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14035                                } else {
14036                                    None
14037                                }
14038                            },
14039                        );
14040                        if let Some(offset) = offset {
14041                            let task_buffer_range =
14042                                location.target.range.to_point(&buffer_snapshot);
14043                            let context_buffer_range =
14044                                task_buffer_range.to_offset(&buffer_snapshot);
14045                            let context_range = BufferOffset(context_buffer_range.start)
14046                                ..BufferOffset(context_buffer_range.end);
14047
14048                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14049                                .or_insert_with(|| RunnableTasks {
14050                                    templates: Vec::new(),
14051                                    offset,
14052                                    column: task_buffer_range.start.column,
14053                                    extra_variables: HashMap::default(),
14054                                    context_range,
14055                                })
14056                                .templates
14057                                .push((kind, task.original_task().clone()));
14058                        }
14059
14060                        acc
14061                    })
14062            }) else {
14063                return;
14064            };
14065
14066            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14067                buffer.language_settings(cx).tasks.prefer_lsp
14068            }) else {
14069                return;
14070            };
14071
14072            let rows = Self::runnable_rows(
14073                project,
14074                display_snapshot,
14075                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14076                new_rows,
14077                cx.clone(),
14078            )
14079            .await;
14080            editor
14081                .update(cx, |editor, _| {
14082                    editor.clear_tasks();
14083                    for (key, mut value) in rows {
14084                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14085                            value.templates.extend(lsp_tasks.templates);
14086                        }
14087
14088                        editor.insert_tasks(key, value);
14089                    }
14090                    for (key, value) in lsp_tasks_by_rows {
14091                        editor.insert_tasks(key, value);
14092                    }
14093                })
14094                .ok();
14095        })
14096    }
14097    fn fetch_runnable_ranges(
14098        snapshot: &DisplaySnapshot,
14099        range: Range<Anchor>,
14100    ) -> Vec<language::RunnableRange> {
14101        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14102    }
14103
14104    fn runnable_rows(
14105        project: Entity<Project>,
14106        snapshot: DisplaySnapshot,
14107        prefer_lsp: bool,
14108        runnable_ranges: Vec<RunnableRange>,
14109        cx: AsyncWindowContext,
14110    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14111        cx.spawn(async move |cx| {
14112            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14113            for mut runnable in runnable_ranges {
14114                let Some(tasks) = cx
14115                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14116                    .ok()
14117                else {
14118                    continue;
14119                };
14120                let mut tasks = tasks.await;
14121
14122                if prefer_lsp {
14123                    tasks.retain(|(task_kind, _)| {
14124                        !matches!(task_kind, TaskSourceKind::Language { .. })
14125                    });
14126                }
14127                if tasks.is_empty() {
14128                    continue;
14129                }
14130
14131                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14132                let Some(row) = snapshot
14133                    .buffer_snapshot
14134                    .buffer_line_for_row(MultiBufferRow(point.row))
14135                    .map(|(_, range)| range.start.row)
14136                else {
14137                    continue;
14138                };
14139
14140                let context_range =
14141                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14142                runnable_rows.push((
14143                    (runnable.buffer_id, row),
14144                    RunnableTasks {
14145                        templates: tasks,
14146                        offset: snapshot
14147                            .buffer_snapshot
14148                            .anchor_before(runnable.run_range.start),
14149                        context_range,
14150                        column: point.column,
14151                        extra_variables: runnable.extra_captures,
14152                    },
14153                ));
14154            }
14155            runnable_rows
14156        })
14157    }
14158
14159    fn templates_with_tags(
14160        project: &Entity<Project>,
14161        runnable: &mut Runnable,
14162        cx: &mut App,
14163    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14164        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14165            let (worktree_id, file) = project
14166                .buffer_for_id(runnable.buffer, cx)
14167                .and_then(|buffer| buffer.read(cx).file())
14168                .map(|file| (file.worktree_id(cx), file.clone()))
14169                .unzip();
14170
14171            (
14172                project.task_store().read(cx).task_inventory().cloned(),
14173                worktree_id,
14174                file,
14175            )
14176        });
14177
14178        let tags = mem::take(&mut runnable.tags);
14179        let language = runnable.language.clone();
14180        cx.spawn(async move |cx| {
14181            let mut templates_with_tags = Vec::new();
14182            if let Some(inventory) = inventory {
14183                for RunnableTag(tag) in tags {
14184                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14185                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14186                    }) else {
14187                        return templates_with_tags;
14188                    };
14189                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14190                        move |(_, template)| {
14191                            template.tags.iter().any(|source_tag| source_tag == &tag)
14192                        },
14193                    ));
14194                }
14195            }
14196            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14197
14198            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14199                // Strongest source wins; if we have worktree tag binding, prefer that to
14200                // global and language bindings;
14201                // if we have a global binding, prefer that to language binding.
14202                let first_mismatch = templates_with_tags
14203                    .iter()
14204                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14205                if let Some(index) = first_mismatch {
14206                    templates_with_tags.truncate(index);
14207                }
14208            }
14209
14210            templates_with_tags
14211        })
14212    }
14213
14214    pub fn move_to_enclosing_bracket(
14215        &mut self,
14216        _: &MoveToEnclosingBracket,
14217        window: &mut Window,
14218        cx: &mut Context<Self>,
14219    ) {
14220        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14221        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14222            s.move_offsets_with(|snapshot, selection| {
14223                let Some(enclosing_bracket_ranges) =
14224                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14225                else {
14226                    return;
14227                };
14228
14229                let mut best_length = usize::MAX;
14230                let mut best_inside = false;
14231                let mut best_in_bracket_range = false;
14232                let mut best_destination = None;
14233                for (open, close) in enclosing_bracket_ranges {
14234                    let close = close.to_inclusive();
14235                    let length = close.end() - open.start;
14236                    let inside = selection.start >= open.end && selection.end <= *close.start();
14237                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14238                        || close.contains(&selection.head());
14239
14240                    // If best is next to a bracket and current isn't, skip
14241                    if !in_bracket_range && best_in_bracket_range {
14242                        continue;
14243                    }
14244
14245                    // Prefer smaller lengths unless best is inside and current isn't
14246                    if length > best_length && (best_inside || !inside) {
14247                        continue;
14248                    }
14249
14250                    best_length = length;
14251                    best_inside = inside;
14252                    best_in_bracket_range = in_bracket_range;
14253                    best_destination = Some(
14254                        if close.contains(&selection.start) && close.contains(&selection.end) {
14255                            if inside { open.end } else { open.start }
14256                        } else if inside {
14257                            *close.start()
14258                        } else {
14259                            *close.end()
14260                        },
14261                    );
14262                }
14263
14264                if let Some(destination) = best_destination {
14265                    selection.collapse_to(destination, SelectionGoal::None);
14266                }
14267            })
14268        });
14269    }
14270
14271    pub fn undo_selection(
14272        &mut self,
14273        _: &UndoSelection,
14274        window: &mut Window,
14275        cx: &mut Context<Self>,
14276    ) {
14277        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14278        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14279            self.selection_history.mode = SelectionHistoryMode::Undoing;
14280            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14281                this.end_selection(window, cx);
14282                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14283                    s.select_anchors(entry.selections.to_vec())
14284                });
14285            });
14286            self.selection_history.mode = SelectionHistoryMode::Normal;
14287
14288            self.select_next_state = entry.select_next_state;
14289            self.select_prev_state = entry.select_prev_state;
14290            self.add_selections_state = entry.add_selections_state;
14291        }
14292    }
14293
14294    pub fn redo_selection(
14295        &mut self,
14296        _: &RedoSelection,
14297        window: &mut Window,
14298        cx: &mut Context<Self>,
14299    ) {
14300        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14301        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14302            self.selection_history.mode = SelectionHistoryMode::Redoing;
14303            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14304                this.end_selection(window, cx);
14305                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14306                    s.select_anchors(entry.selections.to_vec())
14307                });
14308            });
14309            self.selection_history.mode = SelectionHistoryMode::Normal;
14310
14311            self.select_next_state = entry.select_next_state;
14312            self.select_prev_state = entry.select_prev_state;
14313            self.add_selections_state = entry.add_selections_state;
14314        }
14315    }
14316
14317    pub fn expand_excerpts(
14318        &mut self,
14319        action: &ExpandExcerpts,
14320        _: &mut Window,
14321        cx: &mut Context<Self>,
14322    ) {
14323        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14324    }
14325
14326    pub fn expand_excerpts_down(
14327        &mut self,
14328        action: &ExpandExcerptsDown,
14329        _: &mut Window,
14330        cx: &mut Context<Self>,
14331    ) {
14332        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14333    }
14334
14335    pub fn expand_excerpts_up(
14336        &mut self,
14337        action: &ExpandExcerptsUp,
14338        _: &mut Window,
14339        cx: &mut Context<Self>,
14340    ) {
14341        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14342    }
14343
14344    pub fn expand_excerpts_for_direction(
14345        &mut self,
14346        lines: u32,
14347        direction: ExpandExcerptDirection,
14348
14349        cx: &mut Context<Self>,
14350    ) {
14351        let selections = self.selections.disjoint_anchors();
14352
14353        let lines = if lines == 0 {
14354            EditorSettings::get_global(cx).expand_excerpt_lines
14355        } else {
14356            lines
14357        };
14358
14359        self.buffer.update(cx, |buffer, cx| {
14360            let snapshot = buffer.snapshot(cx);
14361            let mut excerpt_ids = selections
14362                .iter()
14363                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14364                .collect::<Vec<_>>();
14365            excerpt_ids.sort();
14366            excerpt_ids.dedup();
14367            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14368        })
14369    }
14370
14371    pub fn expand_excerpt(
14372        &mut self,
14373        excerpt: ExcerptId,
14374        direction: ExpandExcerptDirection,
14375        window: &mut Window,
14376        cx: &mut Context<Self>,
14377    ) {
14378        let current_scroll_position = self.scroll_position(cx);
14379        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14380        let mut should_scroll_up = false;
14381
14382        if direction == ExpandExcerptDirection::Down {
14383            let multi_buffer = self.buffer.read(cx);
14384            let snapshot = multi_buffer.snapshot(cx);
14385            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14386                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14387                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14388                        let buffer_snapshot = buffer.read(cx).snapshot();
14389                        let excerpt_end_row =
14390                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14391                        let last_row = buffer_snapshot.max_point().row;
14392                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14393                        should_scroll_up = lines_below >= lines_to_expand;
14394                    }
14395                }
14396            }
14397        }
14398
14399        self.buffer.update(cx, |buffer, cx| {
14400            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14401        });
14402
14403        if should_scroll_up {
14404            let new_scroll_position =
14405                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14406            self.set_scroll_position(new_scroll_position, window, cx);
14407        }
14408    }
14409
14410    pub fn go_to_singleton_buffer_point(
14411        &mut self,
14412        point: Point,
14413        window: &mut Window,
14414        cx: &mut Context<Self>,
14415    ) {
14416        self.go_to_singleton_buffer_range(point..point, window, cx);
14417    }
14418
14419    pub fn go_to_singleton_buffer_range(
14420        &mut self,
14421        range: Range<Point>,
14422        window: &mut Window,
14423        cx: &mut Context<Self>,
14424    ) {
14425        let multibuffer = self.buffer().read(cx);
14426        let Some(buffer) = multibuffer.as_singleton() else {
14427            return;
14428        };
14429        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14430            return;
14431        };
14432        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14433            return;
14434        };
14435        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14436            s.select_anchor_ranges([start..end])
14437        });
14438    }
14439
14440    pub fn go_to_diagnostic(
14441        &mut self,
14442        _: &GoToDiagnostic,
14443        window: &mut Window,
14444        cx: &mut Context<Self>,
14445    ) {
14446        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14447        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14448    }
14449
14450    pub fn go_to_prev_diagnostic(
14451        &mut self,
14452        _: &GoToPreviousDiagnostic,
14453        window: &mut Window,
14454        cx: &mut Context<Self>,
14455    ) {
14456        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14457        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14458    }
14459
14460    pub fn go_to_diagnostic_impl(
14461        &mut self,
14462        direction: Direction,
14463        window: &mut Window,
14464        cx: &mut Context<Self>,
14465    ) {
14466        let buffer = self.buffer.read(cx).snapshot(cx);
14467        let selection = self.selections.newest::<usize>(cx);
14468
14469        let mut active_group_id = None;
14470        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14471            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14472                active_group_id = Some(active_group.group_id);
14473            }
14474        }
14475
14476        fn filtered(
14477            snapshot: EditorSnapshot,
14478            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14479        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14480            diagnostics
14481                .filter(|entry| entry.range.start != entry.range.end)
14482                .filter(|entry| !entry.diagnostic.is_unnecessary)
14483                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14484        }
14485
14486        let snapshot = self.snapshot(window, cx);
14487        let before = filtered(
14488            snapshot.clone(),
14489            buffer
14490                .diagnostics_in_range(0..selection.start)
14491                .filter(|entry| entry.range.start <= selection.start),
14492        );
14493        let after = filtered(
14494            snapshot,
14495            buffer
14496                .diagnostics_in_range(selection.start..buffer.len())
14497                .filter(|entry| entry.range.start >= selection.start),
14498        );
14499
14500        let mut found: Option<DiagnosticEntry<usize>> = None;
14501        if direction == Direction::Prev {
14502            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14503            {
14504                for diagnostic in prev_diagnostics.into_iter().rev() {
14505                    if diagnostic.range.start != selection.start
14506                        || active_group_id
14507                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14508                    {
14509                        found = Some(diagnostic);
14510                        break 'outer;
14511                    }
14512                }
14513            }
14514        } else {
14515            for diagnostic in after.chain(before) {
14516                if diagnostic.range.start != selection.start
14517                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14518                {
14519                    found = Some(diagnostic);
14520                    break;
14521                }
14522            }
14523        }
14524        let Some(next_diagnostic) = found else {
14525            return;
14526        };
14527
14528        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14529            return;
14530        };
14531        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14532            s.select_ranges(vec![
14533                next_diagnostic.range.start..next_diagnostic.range.start,
14534            ])
14535        });
14536        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14537        self.refresh_inline_completion(false, true, window, cx);
14538    }
14539
14540    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14541        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14542        let snapshot = self.snapshot(window, cx);
14543        let selection = self.selections.newest::<Point>(cx);
14544        self.go_to_hunk_before_or_after_position(
14545            &snapshot,
14546            selection.head(),
14547            Direction::Next,
14548            window,
14549            cx,
14550        );
14551    }
14552
14553    pub fn go_to_hunk_before_or_after_position(
14554        &mut self,
14555        snapshot: &EditorSnapshot,
14556        position: Point,
14557        direction: Direction,
14558        window: &mut Window,
14559        cx: &mut Context<Editor>,
14560    ) {
14561        let row = if direction == Direction::Next {
14562            self.hunk_after_position(snapshot, position)
14563                .map(|hunk| hunk.row_range.start)
14564        } else {
14565            self.hunk_before_position(snapshot, position)
14566        };
14567
14568        if let Some(row) = row {
14569            let destination = Point::new(row.0, 0);
14570            let autoscroll = Autoscroll::center();
14571
14572            self.unfold_ranges(&[destination..destination], false, false, cx);
14573            self.change_selections(Some(autoscroll), window, cx, |s| {
14574                s.select_ranges([destination..destination]);
14575            });
14576        }
14577    }
14578
14579    fn hunk_after_position(
14580        &mut self,
14581        snapshot: &EditorSnapshot,
14582        position: Point,
14583    ) -> Option<MultiBufferDiffHunk> {
14584        snapshot
14585            .buffer_snapshot
14586            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14587            .find(|hunk| hunk.row_range.start.0 > position.row)
14588            .or_else(|| {
14589                snapshot
14590                    .buffer_snapshot
14591                    .diff_hunks_in_range(Point::zero()..position)
14592                    .find(|hunk| hunk.row_range.end.0 < position.row)
14593            })
14594    }
14595
14596    fn go_to_prev_hunk(
14597        &mut self,
14598        _: &GoToPreviousHunk,
14599        window: &mut Window,
14600        cx: &mut Context<Self>,
14601    ) {
14602        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14603        let snapshot = self.snapshot(window, cx);
14604        let selection = self.selections.newest::<Point>(cx);
14605        self.go_to_hunk_before_or_after_position(
14606            &snapshot,
14607            selection.head(),
14608            Direction::Prev,
14609            window,
14610            cx,
14611        );
14612    }
14613
14614    fn hunk_before_position(
14615        &mut self,
14616        snapshot: &EditorSnapshot,
14617        position: Point,
14618    ) -> Option<MultiBufferRow> {
14619        snapshot
14620            .buffer_snapshot
14621            .diff_hunk_before(position)
14622            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14623    }
14624
14625    fn go_to_next_change(
14626        &mut self,
14627        _: &GoToNextChange,
14628        window: &mut Window,
14629        cx: &mut Context<Self>,
14630    ) {
14631        if let Some(selections) = self
14632            .change_list
14633            .next_change(1, Direction::Next)
14634            .map(|s| s.to_vec())
14635        {
14636            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14637                let map = s.display_map();
14638                s.select_display_ranges(selections.iter().map(|a| {
14639                    let point = a.to_display_point(&map);
14640                    point..point
14641                }))
14642            })
14643        }
14644    }
14645
14646    fn go_to_previous_change(
14647        &mut self,
14648        _: &GoToPreviousChange,
14649        window: &mut Window,
14650        cx: &mut Context<Self>,
14651    ) {
14652        if let Some(selections) = self
14653            .change_list
14654            .next_change(1, Direction::Prev)
14655            .map(|s| s.to_vec())
14656        {
14657            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14658                let map = s.display_map();
14659                s.select_display_ranges(selections.iter().map(|a| {
14660                    let point = a.to_display_point(&map);
14661                    point..point
14662                }))
14663            })
14664        }
14665    }
14666
14667    fn go_to_line<T: 'static>(
14668        &mut self,
14669        position: Anchor,
14670        highlight_color: Option<Hsla>,
14671        window: &mut Window,
14672        cx: &mut Context<Self>,
14673    ) {
14674        let snapshot = self.snapshot(window, cx).display_snapshot;
14675        let position = position.to_point(&snapshot.buffer_snapshot);
14676        let start = snapshot
14677            .buffer_snapshot
14678            .clip_point(Point::new(position.row, 0), Bias::Left);
14679        let end = start + Point::new(1, 0);
14680        let start = snapshot.buffer_snapshot.anchor_before(start);
14681        let end = snapshot.buffer_snapshot.anchor_before(end);
14682
14683        self.highlight_rows::<T>(
14684            start..end,
14685            highlight_color
14686                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14687            Default::default(),
14688            cx,
14689        );
14690
14691        if self.buffer.read(cx).is_singleton() {
14692            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14693        }
14694    }
14695
14696    pub fn go_to_definition(
14697        &mut self,
14698        _: &GoToDefinition,
14699        window: &mut Window,
14700        cx: &mut Context<Self>,
14701    ) -> Task<Result<Navigated>> {
14702        let definition =
14703            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14704        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14705        cx.spawn_in(window, async move |editor, cx| {
14706            if definition.await? == Navigated::Yes {
14707                return Ok(Navigated::Yes);
14708            }
14709            match fallback_strategy {
14710                GoToDefinitionFallback::None => Ok(Navigated::No),
14711                GoToDefinitionFallback::FindAllReferences => {
14712                    match editor.update_in(cx, |editor, window, cx| {
14713                        editor.find_all_references(&FindAllReferences, window, cx)
14714                    })? {
14715                        Some(references) => references.await,
14716                        None => Ok(Navigated::No),
14717                    }
14718                }
14719            }
14720        })
14721    }
14722
14723    pub fn go_to_declaration(
14724        &mut self,
14725        _: &GoToDeclaration,
14726        window: &mut Window,
14727        cx: &mut Context<Self>,
14728    ) -> Task<Result<Navigated>> {
14729        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14730    }
14731
14732    pub fn go_to_declaration_split(
14733        &mut self,
14734        _: &GoToDeclaration,
14735        window: &mut Window,
14736        cx: &mut Context<Self>,
14737    ) -> Task<Result<Navigated>> {
14738        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14739    }
14740
14741    pub fn go_to_implementation(
14742        &mut self,
14743        _: &GoToImplementation,
14744        window: &mut Window,
14745        cx: &mut Context<Self>,
14746    ) -> Task<Result<Navigated>> {
14747        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14748    }
14749
14750    pub fn go_to_implementation_split(
14751        &mut self,
14752        _: &GoToImplementationSplit,
14753        window: &mut Window,
14754        cx: &mut Context<Self>,
14755    ) -> Task<Result<Navigated>> {
14756        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14757    }
14758
14759    pub fn go_to_type_definition(
14760        &mut self,
14761        _: &GoToTypeDefinition,
14762        window: &mut Window,
14763        cx: &mut Context<Self>,
14764    ) -> Task<Result<Navigated>> {
14765        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14766    }
14767
14768    pub fn go_to_definition_split(
14769        &mut self,
14770        _: &GoToDefinitionSplit,
14771        window: &mut Window,
14772        cx: &mut Context<Self>,
14773    ) -> Task<Result<Navigated>> {
14774        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14775    }
14776
14777    pub fn go_to_type_definition_split(
14778        &mut self,
14779        _: &GoToTypeDefinitionSplit,
14780        window: &mut Window,
14781        cx: &mut Context<Self>,
14782    ) -> Task<Result<Navigated>> {
14783        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14784    }
14785
14786    fn go_to_definition_of_kind(
14787        &mut self,
14788        kind: GotoDefinitionKind,
14789        split: bool,
14790        window: &mut Window,
14791        cx: &mut Context<Self>,
14792    ) -> Task<Result<Navigated>> {
14793        let Some(provider) = self.semantics_provider.clone() else {
14794            return Task::ready(Ok(Navigated::No));
14795        };
14796        let head = self.selections.newest::<usize>(cx).head();
14797        let buffer = self.buffer.read(cx);
14798        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14799            text_anchor
14800        } else {
14801            return Task::ready(Ok(Navigated::No));
14802        };
14803
14804        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14805            return Task::ready(Ok(Navigated::No));
14806        };
14807
14808        cx.spawn_in(window, async move |editor, cx| {
14809            let definitions = definitions.await?;
14810            let navigated = editor
14811                .update_in(cx, |editor, window, cx| {
14812                    editor.navigate_to_hover_links(
14813                        Some(kind),
14814                        definitions
14815                            .into_iter()
14816                            .filter(|location| {
14817                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14818                            })
14819                            .map(HoverLink::Text)
14820                            .collect::<Vec<_>>(),
14821                        split,
14822                        window,
14823                        cx,
14824                    )
14825                })?
14826                .await?;
14827            anyhow::Ok(navigated)
14828        })
14829    }
14830
14831    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14832        let selection = self.selections.newest_anchor();
14833        let head = selection.head();
14834        let tail = selection.tail();
14835
14836        let Some((buffer, start_position)) =
14837            self.buffer.read(cx).text_anchor_for_position(head, cx)
14838        else {
14839            return;
14840        };
14841
14842        let end_position = if head != tail {
14843            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14844                return;
14845            };
14846            Some(pos)
14847        } else {
14848            None
14849        };
14850
14851        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14852            let url = if let Some(end_pos) = end_position {
14853                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14854            } else {
14855                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14856            };
14857
14858            if let Some(url) = url {
14859                editor.update(cx, |_, cx| {
14860                    cx.open_url(&url);
14861                })
14862            } else {
14863                Ok(())
14864            }
14865        });
14866
14867        url_finder.detach();
14868    }
14869
14870    pub fn open_selected_filename(
14871        &mut self,
14872        _: &OpenSelectedFilename,
14873        window: &mut Window,
14874        cx: &mut Context<Self>,
14875    ) {
14876        let Some(workspace) = self.workspace() else {
14877            return;
14878        };
14879
14880        let position = self.selections.newest_anchor().head();
14881
14882        let Some((buffer, buffer_position)) =
14883            self.buffer.read(cx).text_anchor_for_position(position, cx)
14884        else {
14885            return;
14886        };
14887
14888        let project = self.project.clone();
14889
14890        cx.spawn_in(window, async move |_, cx| {
14891            let result = find_file(&buffer, project, buffer_position, cx).await;
14892
14893            if let Some((_, path)) = result {
14894                workspace
14895                    .update_in(cx, |workspace, window, cx| {
14896                        workspace.open_resolved_path(path, window, cx)
14897                    })?
14898                    .await?;
14899            }
14900            anyhow::Ok(())
14901        })
14902        .detach();
14903    }
14904
14905    pub(crate) fn navigate_to_hover_links(
14906        &mut self,
14907        kind: Option<GotoDefinitionKind>,
14908        mut definitions: Vec<HoverLink>,
14909        split: bool,
14910        window: &mut Window,
14911        cx: &mut Context<Editor>,
14912    ) -> Task<Result<Navigated>> {
14913        // If there is one definition, just open it directly
14914        if definitions.len() == 1 {
14915            let definition = definitions.pop().unwrap();
14916
14917            enum TargetTaskResult {
14918                Location(Option<Location>),
14919                AlreadyNavigated,
14920            }
14921
14922            let target_task = match definition {
14923                HoverLink::Text(link) => {
14924                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14925                }
14926                HoverLink::InlayHint(lsp_location, server_id) => {
14927                    let computation =
14928                        self.compute_target_location(lsp_location, server_id, window, cx);
14929                    cx.background_spawn(async move {
14930                        let location = computation.await?;
14931                        Ok(TargetTaskResult::Location(location))
14932                    })
14933                }
14934                HoverLink::Url(url) => {
14935                    cx.open_url(&url);
14936                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14937                }
14938                HoverLink::File(path) => {
14939                    if let Some(workspace) = self.workspace() {
14940                        cx.spawn_in(window, async move |_, cx| {
14941                            workspace
14942                                .update_in(cx, |workspace, window, cx| {
14943                                    workspace.open_resolved_path(path, window, cx)
14944                                })?
14945                                .await
14946                                .map(|_| TargetTaskResult::AlreadyNavigated)
14947                        })
14948                    } else {
14949                        Task::ready(Ok(TargetTaskResult::Location(None)))
14950                    }
14951                }
14952            };
14953            cx.spawn_in(window, async move |editor, cx| {
14954                let target = match target_task.await.context("target resolution task")? {
14955                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14956                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14957                    TargetTaskResult::Location(Some(target)) => target,
14958                };
14959
14960                editor.update_in(cx, |editor, window, cx| {
14961                    let Some(workspace) = editor.workspace() else {
14962                        return Navigated::No;
14963                    };
14964                    let pane = workspace.read(cx).active_pane().clone();
14965
14966                    let range = target.range.to_point(target.buffer.read(cx));
14967                    let range = editor.range_for_match(&range);
14968                    let range = collapse_multiline_range(range);
14969
14970                    if !split
14971                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14972                    {
14973                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14974                    } else {
14975                        window.defer(cx, move |window, cx| {
14976                            let target_editor: Entity<Self> =
14977                                workspace.update(cx, |workspace, cx| {
14978                                    let pane = if split {
14979                                        workspace.adjacent_pane(window, cx)
14980                                    } else {
14981                                        workspace.active_pane().clone()
14982                                    };
14983
14984                                    workspace.open_project_item(
14985                                        pane,
14986                                        target.buffer.clone(),
14987                                        true,
14988                                        true,
14989                                        window,
14990                                        cx,
14991                                    )
14992                                });
14993                            target_editor.update(cx, |target_editor, cx| {
14994                                // When selecting a definition in a different buffer, disable the nav history
14995                                // to avoid creating a history entry at the previous cursor location.
14996                                pane.update(cx, |pane, _| pane.disable_history());
14997                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14998                                pane.update(cx, |pane, _| pane.enable_history());
14999                            });
15000                        });
15001                    }
15002                    Navigated::Yes
15003                })
15004            })
15005        } else if !definitions.is_empty() {
15006            cx.spawn_in(window, async move |editor, cx| {
15007                let (title, location_tasks, workspace) = editor
15008                    .update_in(cx, |editor, window, cx| {
15009                        let tab_kind = match kind {
15010                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15011                            _ => "Definitions",
15012                        };
15013                        let title = definitions
15014                            .iter()
15015                            .find_map(|definition| match definition {
15016                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15017                                    let buffer = origin.buffer.read(cx);
15018                                    format!(
15019                                        "{} for {}",
15020                                        tab_kind,
15021                                        buffer
15022                                            .text_for_range(origin.range.clone())
15023                                            .collect::<String>()
15024                                    )
15025                                }),
15026                                HoverLink::InlayHint(_, _) => None,
15027                                HoverLink::Url(_) => None,
15028                                HoverLink::File(_) => None,
15029                            })
15030                            .unwrap_or(tab_kind.to_string());
15031                        let location_tasks = definitions
15032                            .into_iter()
15033                            .map(|definition| match definition {
15034                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15035                                HoverLink::InlayHint(lsp_location, server_id) => editor
15036                                    .compute_target_location(lsp_location, server_id, window, cx),
15037                                HoverLink::Url(_) => Task::ready(Ok(None)),
15038                                HoverLink::File(_) => Task::ready(Ok(None)),
15039                            })
15040                            .collect::<Vec<_>>();
15041                        (title, location_tasks, editor.workspace().clone())
15042                    })
15043                    .context("location tasks preparation")?;
15044
15045                let locations = future::join_all(location_tasks)
15046                    .await
15047                    .into_iter()
15048                    .filter_map(|location| location.transpose())
15049                    .collect::<Result<_>>()
15050                    .context("location tasks")?;
15051
15052                let Some(workspace) = workspace else {
15053                    return Ok(Navigated::No);
15054                };
15055                let opened = workspace
15056                    .update_in(cx, |workspace, window, cx| {
15057                        Self::open_locations_in_multibuffer(
15058                            workspace,
15059                            locations,
15060                            title,
15061                            split,
15062                            MultibufferSelectionMode::First,
15063                            window,
15064                            cx,
15065                        )
15066                    })
15067                    .ok();
15068
15069                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15070            })
15071        } else {
15072            Task::ready(Ok(Navigated::No))
15073        }
15074    }
15075
15076    fn compute_target_location(
15077        &self,
15078        lsp_location: lsp::Location,
15079        server_id: LanguageServerId,
15080        window: &mut Window,
15081        cx: &mut Context<Self>,
15082    ) -> Task<anyhow::Result<Option<Location>>> {
15083        let Some(project) = self.project.clone() else {
15084            return Task::ready(Ok(None));
15085        };
15086
15087        cx.spawn_in(window, async move |editor, cx| {
15088            let location_task = editor.update(cx, |_, cx| {
15089                project.update(cx, |project, cx| {
15090                    let language_server_name = project
15091                        .language_server_statuses(cx)
15092                        .find(|(id, _)| server_id == *id)
15093                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15094                    language_server_name.map(|language_server_name| {
15095                        project.open_local_buffer_via_lsp(
15096                            lsp_location.uri.clone(),
15097                            server_id,
15098                            language_server_name,
15099                            cx,
15100                        )
15101                    })
15102                })
15103            })?;
15104            let location = match location_task {
15105                Some(task) => Some({
15106                    let target_buffer_handle = task.await.context("open local buffer")?;
15107                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15108                        let target_start = target_buffer
15109                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15110                        let target_end = target_buffer
15111                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15112                        target_buffer.anchor_after(target_start)
15113                            ..target_buffer.anchor_before(target_end)
15114                    })?;
15115                    Location {
15116                        buffer: target_buffer_handle,
15117                        range,
15118                    }
15119                }),
15120                None => None,
15121            };
15122            Ok(location)
15123        })
15124    }
15125
15126    pub fn find_all_references(
15127        &mut self,
15128        _: &FindAllReferences,
15129        window: &mut Window,
15130        cx: &mut Context<Self>,
15131    ) -> Option<Task<Result<Navigated>>> {
15132        let selection = self.selections.newest::<usize>(cx);
15133        let multi_buffer = self.buffer.read(cx);
15134        let head = selection.head();
15135
15136        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15137        let head_anchor = multi_buffer_snapshot.anchor_at(
15138            head,
15139            if head < selection.tail() {
15140                Bias::Right
15141            } else {
15142                Bias::Left
15143            },
15144        );
15145
15146        match self
15147            .find_all_references_task_sources
15148            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15149        {
15150            Ok(_) => {
15151                log::info!(
15152                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15153                );
15154                return None;
15155            }
15156            Err(i) => {
15157                self.find_all_references_task_sources.insert(i, head_anchor);
15158            }
15159        }
15160
15161        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15162        let workspace = self.workspace()?;
15163        let project = workspace.read(cx).project().clone();
15164        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15165        Some(cx.spawn_in(window, async move |editor, cx| {
15166            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15167                if let Ok(i) = editor
15168                    .find_all_references_task_sources
15169                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15170                {
15171                    editor.find_all_references_task_sources.remove(i);
15172                }
15173            });
15174
15175            let locations = references.await?;
15176            if locations.is_empty() {
15177                return anyhow::Ok(Navigated::No);
15178            }
15179
15180            workspace.update_in(cx, |workspace, window, cx| {
15181                let title = locations
15182                    .first()
15183                    .as_ref()
15184                    .map(|location| {
15185                        let buffer = location.buffer.read(cx);
15186                        format!(
15187                            "References to `{}`",
15188                            buffer
15189                                .text_for_range(location.range.clone())
15190                                .collect::<String>()
15191                        )
15192                    })
15193                    .unwrap();
15194                Self::open_locations_in_multibuffer(
15195                    workspace,
15196                    locations,
15197                    title,
15198                    false,
15199                    MultibufferSelectionMode::First,
15200                    window,
15201                    cx,
15202                );
15203                Navigated::Yes
15204            })
15205        }))
15206    }
15207
15208    /// Opens a multibuffer with the given project locations in it
15209    pub fn open_locations_in_multibuffer(
15210        workspace: &mut Workspace,
15211        mut locations: Vec<Location>,
15212        title: String,
15213        split: bool,
15214        multibuffer_selection_mode: MultibufferSelectionMode,
15215        window: &mut Window,
15216        cx: &mut Context<Workspace>,
15217    ) {
15218        // If there are multiple definitions, open them in a multibuffer
15219        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15220        let mut locations = locations.into_iter().peekable();
15221        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15222        let capability = workspace.project().read(cx).capability();
15223
15224        let excerpt_buffer = cx.new(|cx| {
15225            let mut multibuffer = MultiBuffer::new(capability);
15226            while let Some(location) = locations.next() {
15227                let buffer = location.buffer.read(cx);
15228                let mut ranges_for_buffer = Vec::new();
15229                let range = location.range.to_point(buffer);
15230                ranges_for_buffer.push(range.clone());
15231
15232                while let Some(next_location) = locations.peek() {
15233                    if next_location.buffer == location.buffer {
15234                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15235                        locations.next();
15236                    } else {
15237                        break;
15238                    }
15239                }
15240
15241                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15242                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15243                    PathKey::for_buffer(&location.buffer, cx),
15244                    location.buffer.clone(),
15245                    ranges_for_buffer,
15246                    DEFAULT_MULTIBUFFER_CONTEXT,
15247                    cx,
15248                );
15249                ranges.extend(new_ranges)
15250            }
15251
15252            multibuffer.with_title(title)
15253        });
15254
15255        let editor = cx.new(|cx| {
15256            Editor::for_multibuffer(
15257                excerpt_buffer,
15258                Some(workspace.project().clone()),
15259                window,
15260                cx,
15261            )
15262        });
15263        editor.update(cx, |editor, cx| {
15264            match multibuffer_selection_mode {
15265                MultibufferSelectionMode::First => {
15266                    if let Some(first_range) = ranges.first() {
15267                        editor.change_selections(None, window, cx, |selections| {
15268                            selections.clear_disjoint();
15269                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15270                        });
15271                    }
15272                    editor.highlight_background::<Self>(
15273                        &ranges,
15274                        |theme| theme.colors().editor_highlighted_line_background,
15275                        cx,
15276                    );
15277                }
15278                MultibufferSelectionMode::All => {
15279                    editor.change_selections(None, window, cx, |selections| {
15280                        selections.clear_disjoint();
15281                        selections.select_anchor_ranges(ranges);
15282                    });
15283                }
15284            }
15285            editor.register_buffers_with_language_servers(cx);
15286        });
15287
15288        let item = Box::new(editor);
15289        let item_id = item.item_id();
15290
15291        if split {
15292            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15293        } else {
15294            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15295                let (preview_item_id, preview_item_idx) =
15296                    workspace.active_pane().read_with(cx, |pane, _| {
15297                        (pane.preview_item_id(), pane.preview_item_idx())
15298                    });
15299
15300                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15301
15302                if let Some(preview_item_id) = preview_item_id {
15303                    workspace.active_pane().update(cx, |pane, cx| {
15304                        pane.remove_item(preview_item_id, false, false, window, cx);
15305                    });
15306                }
15307            } else {
15308                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15309            }
15310        }
15311        workspace.active_pane().update(cx, |pane, cx| {
15312            pane.set_preview_item_id(Some(item_id), cx);
15313        });
15314    }
15315
15316    pub fn rename(
15317        &mut self,
15318        _: &Rename,
15319        window: &mut Window,
15320        cx: &mut Context<Self>,
15321    ) -> Option<Task<Result<()>>> {
15322        use language::ToOffset as _;
15323
15324        let provider = self.semantics_provider.clone()?;
15325        let selection = self.selections.newest_anchor().clone();
15326        let (cursor_buffer, cursor_buffer_position) = self
15327            .buffer
15328            .read(cx)
15329            .text_anchor_for_position(selection.head(), cx)?;
15330        let (tail_buffer, cursor_buffer_position_end) = self
15331            .buffer
15332            .read(cx)
15333            .text_anchor_for_position(selection.tail(), cx)?;
15334        if tail_buffer != cursor_buffer {
15335            return None;
15336        }
15337
15338        let snapshot = cursor_buffer.read(cx).snapshot();
15339        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15340        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15341        let prepare_rename = provider
15342            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15343            .unwrap_or_else(|| Task::ready(Ok(None)));
15344        drop(snapshot);
15345
15346        Some(cx.spawn_in(window, async move |this, cx| {
15347            let rename_range = if let Some(range) = prepare_rename.await? {
15348                Some(range)
15349            } else {
15350                this.update(cx, |this, cx| {
15351                    let buffer = this.buffer.read(cx).snapshot(cx);
15352                    let mut buffer_highlights = this
15353                        .document_highlights_for_position(selection.head(), &buffer)
15354                        .filter(|highlight| {
15355                            highlight.start.excerpt_id == selection.head().excerpt_id
15356                                && highlight.end.excerpt_id == selection.head().excerpt_id
15357                        });
15358                    buffer_highlights
15359                        .next()
15360                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15361                })?
15362            };
15363            if let Some(rename_range) = rename_range {
15364                this.update_in(cx, |this, window, cx| {
15365                    let snapshot = cursor_buffer.read(cx).snapshot();
15366                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15367                    let cursor_offset_in_rename_range =
15368                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15369                    let cursor_offset_in_rename_range_end =
15370                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15371
15372                    this.take_rename(false, window, cx);
15373                    let buffer = this.buffer.read(cx).read(cx);
15374                    let cursor_offset = selection.head().to_offset(&buffer);
15375                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15376                    let rename_end = rename_start + rename_buffer_range.len();
15377                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15378                    let mut old_highlight_id = None;
15379                    let old_name: Arc<str> = buffer
15380                        .chunks(rename_start..rename_end, true)
15381                        .map(|chunk| {
15382                            if old_highlight_id.is_none() {
15383                                old_highlight_id = chunk.syntax_highlight_id;
15384                            }
15385                            chunk.text
15386                        })
15387                        .collect::<String>()
15388                        .into();
15389
15390                    drop(buffer);
15391
15392                    // Position the selection in the rename editor so that it matches the current selection.
15393                    this.show_local_selections = false;
15394                    let rename_editor = cx.new(|cx| {
15395                        let mut editor = Editor::single_line(window, cx);
15396                        editor.buffer.update(cx, |buffer, cx| {
15397                            buffer.edit([(0..0, old_name.clone())], None, cx)
15398                        });
15399                        let rename_selection_range = match cursor_offset_in_rename_range
15400                            .cmp(&cursor_offset_in_rename_range_end)
15401                        {
15402                            Ordering::Equal => {
15403                                editor.select_all(&SelectAll, window, cx);
15404                                return editor;
15405                            }
15406                            Ordering::Less => {
15407                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15408                            }
15409                            Ordering::Greater => {
15410                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15411                            }
15412                        };
15413                        if rename_selection_range.end > old_name.len() {
15414                            editor.select_all(&SelectAll, window, cx);
15415                        } else {
15416                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15417                                s.select_ranges([rename_selection_range]);
15418                            });
15419                        }
15420                        editor
15421                    });
15422                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15423                        if e == &EditorEvent::Focused {
15424                            cx.emit(EditorEvent::FocusedIn)
15425                        }
15426                    })
15427                    .detach();
15428
15429                    let write_highlights = this
15430                        .clear_background_highlights::<DocumentHighlightWrite>(cx)
15431                        .unwrap_or_default();
15432                    let read_highlights = this
15433                        .clear_background_highlights::<DocumentHighlightRead>(cx)
15434                        .unwrap_or_default();
15435                    let ranges = write_highlights
15436                        .iter()
15437                        .chain(read_highlights.iter())
15438                        .cloned()
15439                        .map(|highlight| {
15440                            (
15441                                highlight.range,
15442                                HighlightStyle {
15443                                    fade_out: Some(0.6),
15444                                    ..Default::default()
15445                                },
15446                            )
15447                        })
15448                        .collect();
15449
15450                    this.highlight_text::<Rename>(ranges, cx);
15451                    let rename_focus_handle = rename_editor.focus_handle(cx);
15452                    window.focus(&rename_focus_handle);
15453                    let block_id = this.insert_blocks(
15454                        [BlockProperties {
15455                            style: BlockStyle::Flex,
15456                            placement: BlockPlacement::Below(range.start),
15457                            height: Some(1),
15458                            render: Arc::new({
15459                                let rename_editor = rename_editor.clone();
15460                                move |cx: &mut BlockContext| {
15461                                    let mut text_style = cx.editor_style.text.clone();
15462                                    if let Some(highlight_style) = old_highlight_id
15463                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15464                                    {
15465                                        text_style = text_style.highlight(highlight_style);
15466                                    }
15467                                    div()
15468                                        .block_mouse_except_scroll()
15469                                        .pl(cx.anchor_x)
15470                                        .child(EditorElement::new(
15471                                            &rename_editor,
15472                                            EditorStyle {
15473                                                background: cx.theme().system().transparent,
15474                                                local_player: cx.editor_style.local_player,
15475                                                text: text_style,
15476                                                scrollbar_width: cx.editor_style.scrollbar_width,
15477                                                syntax: cx.editor_style.syntax.clone(),
15478                                                status: cx.editor_style.status.clone(),
15479                                                inlay_hints_style: HighlightStyle {
15480                                                    font_weight: Some(FontWeight::BOLD),
15481                                                    ..make_inlay_hints_style(cx.app)
15482                                                },
15483                                                inline_completion_styles: make_suggestion_styles(
15484                                                    cx.app,
15485                                                ),
15486                                                ..EditorStyle::default()
15487                                            },
15488                                        ))
15489                                        .into_any_element()
15490                                }
15491                            }),
15492                            priority: 0,
15493                            render_in_minimap: true,
15494                        }],
15495                        Some(Autoscroll::fit()),
15496                        cx,
15497                    )[0];
15498                    this.pending_rename = Some(RenameState {
15499                        range,
15500                        old_name,
15501                        editor: rename_editor,
15502                        block_id,
15503                    });
15504                })?;
15505            }
15506
15507            Ok(())
15508        }))
15509    }
15510
15511    pub fn confirm_rename(
15512        &mut self,
15513        _: &ConfirmRename,
15514        window: &mut Window,
15515        cx: &mut Context<Self>,
15516    ) -> Option<Task<Result<()>>> {
15517        let rename = self.take_rename(false, window, cx)?;
15518        let workspace = self.workspace()?.downgrade();
15519        let (buffer, start) = self
15520            .buffer
15521            .read(cx)
15522            .text_anchor_for_position(rename.range.start, cx)?;
15523        let (end_buffer, _) = self
15524            .buffer
15525            .read(cx)
15526            .text_anchor_for_position(rename.range.end, cx)?;
15527        if buffer != end_buffer {
15528            return None;
15529        }
15530
15531        let old_name = rename.old_name;
15532        let new_name = rename.editor.read(cx).text(cx);
15533
15534        let rename = self.semantics_provider.as_ref()?.perform_rename(
15535            &buffer,
15536            start,
15537            new_name.clone(),
15538            cx,
15539        )?;
15540
15541        Some(cx.spawn_in(window, async move |editor, cx| {
15542            let project_transaction = rename.await?;
15543            Self::open_project_transaction(
15544                &editor,
15545                workspace,
15546                project_transaction,
15547                format!("Rename: {}{}", old_name, new_name),
15548                cx,
15549            )
15550            .await?;
15551
15552            editor.update(cx, |editor, cx| {
15553                editor.refresh_document_highlights(cx);
15554            })?;
15555            Ok(())
15556        }))
15557    }
15558
15559    fn take_rename(
15560        &mut self,
15561        moving_cursor: bool,
15562        window: &mut Window,
15563        cx: &mut Context<Self>,
15564    ) -> Option<RenameState> {
15565        let rename = self.pending_rename.take()?;
15566        if rename.editor.focus_handle(cx).is_focused(window) {
15567            window.focus(&self.focus_handle);
15568        }
15569
15570        self.remove_blocks(
15571            [rename.block_id].into_iter().collect(),
15572            Some(Autoscroll::fit()),
15573            cx,
15574        );
15575        self.clear_highlights::<Rename>(cx);
15576        self.show_local_selections = true;
15577
15578        if moving_cursor {
15579            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15580                editor.selections.newest::<usize>(cx).head()
15581            });
15582
15583            // Update the selection to match the position of the selection inside
15584            // the rename editor.
15585            let snapshot = self.buffer.read(cx).read(cx);
15586            let rename_range = rename.range.to_offset(&snapshot);
15587            let cursor_in_editor = snapshot
15588                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15589                .min(rename_range.end);
15590            drop(snapshot);
15591
15592            self.change_selections(None, window, cx, |s| {
15593                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15594            });
15595        } else {
15596            self.refresh_document_highlights(cx);
15597        }
15598
15599        Some(rename)
15600    }
15601
15602    pub fn pending_rename(&self) -> Option<&RenameState> {
15603        self.pending_rename.as_ref()
15604    }
15605
15606    fn format(
15607        &mut self,
15608        _: &Format,
15609        window: &mut Window,
15610        cx: &mut Context<Self>,
15611    ) -> Option<Task<Result<()>>> {
15612        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15613
15614        let project = match &self.project {
15615            Some(project) => project.clone(),
15616            None => return None,
15617        };
15618
15619        Some(self.perform_format(
15620            project,
15621            FormatTrigger::Manual,
15622            FormatTarget::Buffers,
15623            window,
15624            cx,
15625        ))
15626    }
15627
15628    fn format_selections(
15629        &mut self,
15630        _: &FormatSelections,
15631        window: &mut Window,
15632        cx: &mut Context<Self>,
15633    ) -> Option<Task<Result<()>>> {
15634        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15635
15636        let project = match &self.project {
15637            Some(project) => project.clone(),
15638            None => return None,
15639        };
15640
15641        let ranges = self
15642            .selections
15643            .all_adjusted(cx)
15644            .into_iter()
15645            .map(|selection| selection.range())
15646            .collect_vec();
15647
15648        Some(self.perform_format(
15649            project,
15650            FormatTrigger::Manual,
15651            FormatTarget::Ranges(ranges),
15652            window,
15653            cx,
15654        ))
15655    }
15656
15657    fn perform_format(
15658        &mut self,
15659        project: Entity<Project>,
15660        trigger: FormatTrigger,
15661        target: FormatTarget,
15662        window: &mut Window,
15663        cx: &mut Context<Self>,
15664    ) -> Task<Result<()>> {
15665        let buffer = self.buffer.clone();
15666        let (buffers, target) = match target {
15667            FormatTarget::Buffers => {
15668                let mut buffers = buffer.read(cx).all_buffers();
15669                if trigger == FormatTrigger::Save {
15670                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15671                }
15672                (buffers, LspFormatTarget::Buffers)
15673            }
15674            FormatTarget::Ranges(selection_ranges) => {
15675                let multi_buffer = buffer.read(cx);
15676                let snapshot = multi_buffer.read(cx);
15677                let mut buffers = HashSet::default();
15678                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15679                    BTreeMap::new();
15680                for selection_range in selection_ranges {
15681                    for (buffer, buffer_range, _) in
15682                        snapshot.range_to_buffer_ranges(selection_range)
15683                    {
15684                        let buffer_id = buffer.remote_id();
15685                        let start = buffer.anchor_before(buffer_range.start);
15686                        let end = buffer.anchor_after(buffer_range.end);
15687                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15688                        buffer_id_to_ranges
15689                            .entry(buffer_id)
15690                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15691                            .or_insert_with(|| vec![start..end]);
15692                    }
15693                }
15694                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15695            }
15696        };
15697
15698        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15699        let selections_prev = transaction_id_prev
15700            .and_then(|transaction_id_prev| {
15701                // default to selections as they were after the last edit, if we have them,
15702                // instead of how they are now.
15703                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15704                // will take you back to where you made the last edit, instead of staying where you scrolled
15705                self.selection_history
15706                    .transaction(transaction_id_prev)
15707                    .map(|t| t.0.clone())
15708            })
15709            .unwrap_or_else(|| {
15710                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15711                self.selections.disjoint_anchors()
15712            });
15713
15714        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15715        let format = project.update(cx, |project, cx| {
15716            project.format(buffers, target, true, trigger, cx)
15717        });
15718
15719        cx.spawn_in(window, async move |editor, cx| {
15720            let transaction = futures::select_biased! {
15721                transaction = format.log_err().fuse() => transaction,
15722                () = timeout => {
15723                    log::warn!("timed out waiting for formatting");
15724                    None
15725                }
15726            };
15727
15728            buffer
15729                .update(cx, |buffer, cx| {
15730                    if let Some(transaction) = transaction {
15731                        if !buffer.is_singleton() {
15732                            buffer.push_transaction(&transaction.0, cx);
15733                        }
15734                    }
15735                    cx.notify();
15736                })
15737                .ok();
15738
15739            if let Some(transaction_id_now) =
15740                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15741            {
15742                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15743                if has_new_transaction {
15744                    _ = editor.update(cx, |editor, _| {
15745                        editor
15746                            .selection_history
15747                            .insert_transaction(transaction_id_now, selections_prev);
15748                    });
15749                }
15750            }
15751
15752            Ok(())
15753        })
15754    }
15755
15756    fn organize_imports(
15757        &mut self,
15758        _: &OrganizeImports,
15759        window: &mut Window,
15760        cx: &mut Context<Self>,
15761    ) -> Option<Task<Result<()>>> {
15762        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15763        let project = match &self.project {
15764            Some(project) => project.clone(),
15765            None => return None,
15766        };
15767        Some(self.perform_code_action_kind(
15768            project,
15769            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15770            window,
15771            cx,
15772        ))
15773    }
15774
15775    fn perform_code_action_kind(
15776        &mut self,
15777        project: Entity<Project>,
15778        kind: CodeActionKind,
15779        window: &mut Window,
15780        cx: &mut Context<Self>,
15781    ) -> Task<Result<()>> {
15782        let buffer = self.buffer.clone();
15783        let buffers = buffer.read(cx).all_buffers();
15784        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15785        let apply_action = project.update(cx, |project, cx| {
15786            project.apply_code_action_kind(buffers, kind, true, cx)
15787        });
15788        cx.spawn_in(window, async move |_, cx| {
15789            let transaction = futures::select_biased! {
15790                () = timeout => {
15791                    log::warn!("timed out waiting for executing code action");
15792                    None
15793                }
15794                transaction = apply_action.log_err().fuse() => transaction,
15795            };
15796            buffer
15797                .update(cx, |buffer, cx| {
15798                    // check if we need this
15799                    if let Some(transaction) = transaction {
15800                        if !buffer.is_singleton() {
15801                            buffer.push_transaction(&transaction.0, cx);
15802                        }
15803                    }
15804                    cx.notify();
15805                })
15806                .ok();
15807            Ok(())
15808        })
15809    }
15810
15811    fn restart_language_server(
15812        &mut self,
15813        _: &RestartLanguageServer,
15814        _: &mut Window,
15815        cx: &mut Context<Self>,
15816    ) {
15817        if let Some(project) = self.project.clone() {
15818            self.buffer.update(cx, |multi_buffer, cx| {
15819                project.update(cx, |project, cx| {
15820                    project.restart_language_servers_for_buffers(
15821                        multi_buffer.all_buffers().into_iter().collect(),
15822                        cx,
15823                    );
15824                });
15825            })
15826        }
15827    }
15828
15829    fn stop_language_server(
15830        &mut self,
15831        _: &StopLanguageServer,
15832        _: &mut Window,
15833        cx: &mut Context<Self>,
15834    ) {
15835        if let Some(project) = self.project.clone() {
15836            self.buffer.update(cx, |multi_buffer, cx| {
15837                project.update(cx, |project, cx| {
15838                    project.stop_language_servers_for_buffers(
15839                        multi_buffer.all_buffers().into_iter().collect(),
15840                        cx,
15841                    );
15842                    cx.emit(project::Event::RefreshInlayHints);
15843                });
15844            });
15845        }
15846    }
15847
15848    fn cancel_language_server_work(
15849        workspace: &mut Workspace,
15850        _: &actions::CancelLanguageServerWork,
15851        _: &mut Window,
15852        cx: &mut Context<Workspace>,
15853    ) {
15854        let project = workspace.project();
15855        let buffers = workspace
15856            .active_item(cx)
15857            .and_then(|item| item.act_as::<Editor>(cx))
15858            .map_or(HashSet::default(), |editor| {
15859                editor.read(cx).buffer.read(cx).all_buffers()
15860            });
15861        project.update(cx, |project, cx| {
15862            project.cancel_language_server_work_for_buffers(buffers, cx);
15863        });
15864    }
15865
15866    fn show_character_palette(
15867        &mut self,
15868        _: &ShowCharacterPalette,
15869        window: &mut Window,
15870        _: &mut Context<Self>,
15871    ) {
15872        window.show_character_palette();
15873    }
15874
15875    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15876        if self.mode.is_minimap() {
15877            return;
15878        }
15879
15880        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15881            let buffer = self.buffer.read(cx).snapshot(cx);
15882            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15883            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15884            let is_valid = buffer
15885                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15886                .any(|entry| {
15887                    entry.diagnostic.is_primary
15888                        && !entry.range.is_empty()
15889                        && entry.range.start == primary_range_start
15890                        && entry.diagnostic.message == active_diagnostics.active_message
15891                });
15892
15893            if !is_valid {
15894                self.dismiss_diagnostics(cx);
15895            }
15896        }
15897    }
15898
15899    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15900        match &self.active_diagnostics {
15901            ActiveDiagnostic::Group(group) => Some(group),
15902            _ => None,
15903        }
15904    }
15905
15906    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15907        self.dismiss_diagnostics(cx);
15908        self.active_diagnostics = ActiveDiagnostic::All;
15909    }
15910
15911    fn activate_diagnostics(
15912        &mut self,
15913        buffer_id: BufferId,
15914        diagnostic: DiagnosticEntry<usize>,
15915        window: &mut Window,
15916        cx: &mut Context<Self>,
15917    ) {
15918        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15919            return;
15920        }
15921        self.dismiss_diagnostics(cx);
15922        let snapshot = self.snapshot(window, cx);
15923        let buffer = self.buffer.read(cx).snapshot(cx);
15924        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15925            return;
15926        };
15927
15928        let diagnostic_group = buffer
15929            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15930            .collect::<Vec<_>>();
15931
15932        let blocks =
15933            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15934
15935        let blocks = self.display_map.update(cx, |display_map, cx| {
15936            display_map.insert_blocks(blocks, cx).into_iter().collect()
15937        });
15938        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15939            active_range: buffer.anchor_before(diagnostic.range.start)
15940                ..buffer.anchor_after(diagnostic.range.end),
15941            active_message: diagnostic.diagnostic.message.clone(),
15942            group_id: diagnostic.diagnostic.group_id,
15943            blocks,
15944        });
15945        cx.notify();
15946    }
15947
15948    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15949        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15950            return;
15951        };
15952
15953        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15954        if let ActiveDiagnostic::Group(group) = prev {
15955            self.display_map.update(cx, |display_map, cx| {
15956                display_map.remove_blocks(group.blocks, cx);
15957            });
15958            cx.notify();
15959        }
15960    }
15961
15962    /// Disable inline diagnostics rendering for this editor.
15963    pub fn disable_inline_diagnostics(&mut self) {
15964        self.inline_diagnostics_enabled = false;
15965        self.inline_diagnostics_update = Task::ready(());
15966        self.inline_diagnostics.clear();
15967    }
15968
15969    pub fn diagnostics_enabled(&self) -> bool {
15970        self.mode.is_full()
15971    }
15972
15973    pub fn inline_diagnostics_enabled(&self) -> bool {
15974        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15975    }
15976
15977    pub fn show_inline_diagnostics(&self) -> bool {
15978        self.show_inline_diagnostics
15979    }
15980
15981    pub fn toggle_inline_diagnostics(
15982        &mut self,
15983        _: &ToggleInlineDiagnostics,
15984        window: &mut Window,
15985        cx: &mut Context<Editor>,
15986    ) {
15987        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15988        self.refresh_inline_diagnostics(false, window, cx);
15989    }
15990
15991    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15992        self.diagnostics_max_severity = severity;
15993        self.display_map.update(cx, |display_map, _| {
15994            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15995        });
15996    }
15997
15998    pub fn toggle_diagnostics(
15999        &mut self,
16000        _: &ToggleDiagnostics,
16001        window: &mut Window,
16002        cx: &mut Context<Editor>,
16003    ) {
16004        if !self.diagnostics_enabled() {
16005            return;
16006        }
16007
16008        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16009            EditorSettings::get_global(cx)
16010                .diagnostics_max_severity
16011                .filter(|severity| severity != &DiagnosticSeverity::Off)
16012                .unwrap_or(DiagnosticSeverity::Hint)
16013        } else {
16014            DiagnosticSeverity::Off
16015        };
16016        self.set_max_diagnostics_severity(new_severity, cx);
16017        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16018            self.active_diagnostics = ActiveDiagnostic::None;
16019            self.inline_diagnostics_update = Task::ready(());
16020            self.inline_diagnostics.clear();
16021        } else {
16022            self.refresh_inline_diagnostics(false, window, cx);
16023        }
16024
16025        cx.notify();
16026    }
16027
16028    pub fn toggle_minimap(
16029        &mut self,
16030        _: &ToggleMinimap,
16031        window: &mut Window,
16032        cx: &mut Context<Editor>,
16033    ) {
16034        if self.supports_minimap(cx) {
16035            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16036        }
16037    }
16038
16039    fn refresh_inline_diagnostics(
16040        &mut self,
16041        debounce: bool,
16042        window: &mut Window,
16043        cx: &mut Context<Self>,
16044    ) {
16045        let max_severity = ProjectSettings::get_global(cx)
16046            .diagnostics
16047            .inline
16048            .max_severity
16049            .unwrap_or(self.diagnostics_max_severity);
16050
16051        if !self.inline_diagnostics_enabled()
16052            || !self.show_inline_diagnostics
16053            || max_severity == DiagnosticSeverity::Off
16054        {
16055            self.inline_diagnostics_update = Task::ready(());
16056            self.inline_diagnostics.clear();
16057            return;
16058        }
16059
16060        let debounce_ms = ProjectSettings::get_global(cx)
16061            .diagnostics
16062            .inline
16063            .update_debounce_ms;
16064        let debounce = if debounce && debounce_ms > 0 {
16065            Some(Duration::from_millis(debounce_ms))
16066        } else {
16067            None
16068        };
16069        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16070            if let Some(debounce) = debounce {
16071                cx.background_executor().timer(debounce).await;
16072            }
16073            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16074                editor
16075                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16076                    .ok()
16077            }) else {
16078                return;
16079            };
16080
16081            let new_inline_diagnostics = cx
16082                .background_spawn(async move {
16083                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16084                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16085                        let message = diagnostic_entry
16086                            .diagnostic
16087                            .message
16088                            .split_once('\n')
16089                            .map(|(line, _)| line)
16090                            .map(SharedString::new)
16091                            .unwrap_or_else(|| {
16092                                SharedString::from(diagnostic_entry.diagnostic.message)
16093                            });
16094                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16095                        let (Ok(i) | Err(i)) = inline_diagnostics
16096                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16097                        inline_diagnostics.insert(
16098                            i,
16099                            (
16100                                start_anchor,
16101                                InlineDiagnostic {
16102                                    message,
16103                                    group_id: diagnostic_entry.diagnostic.group_id,
16104                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16105                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16106                                    severity: diagnostic_entry.diagnostic.severity,
16107                                },
16108                            ),
16109                        );
16110                    }
16111                    inline_diagnostics
16112                })
16113                .await;
16114
16115            editor
16116                .update(cx, |editor, cx| {
16117                    editor.inline_diagnostics = new_inline_diagnostics;
16118                    cx.notify();
16119                })
16120                .ok();
16121        });
16122    }
16123
16124    fn pull_diagnostics(
16125        &mut self,
16126        buffer_id: Option<BufferId>,
16127        window: &Window,
16128        cx: &mut Context<Self>,
16129    ) -> Option<()> {
16130        if !self.mode().is_full() {
16131            return None;
16132        }
16133        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16134            .diagnostics
16135            .lsp_pull_diagnostics;
16136        if !pull_diagnostics_settings.enabled {
16137            return None;
16138        }
16139        let project = self.project.as_ref()?.downgrade();
16140        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16141        let mut buffers = self.buffer.read(cx).all_buffers();
16142        if let Some(buffer_id) = buffer_id {
16143            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16144        }
16145
16146        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16147            cx.background_executor().timer(debounce).await;
16148
16149            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16150                buffers
16151                    .into_iter()
16152                    .flat_map(|buffer| {
16153                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16154                    })
16155                    .collect::<FuturesUnordered<_>>()
16156            }) else {
16157                return;
16158            };
16159
16160            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16161                match pull_task {
16162                    Ok(()) => {
16163                        if editor
16164                            .update_in(cx, |editor, window, cx| {
16165                                editor.update_diagnostics_state(window, cx);
16166                            })
16167                            .is_err()
16168                        {
16169                            return;
16170                        }
16171                    }
16172                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16173                }
16174            }
16175        });
16176
16177        Some(())
16178    }
16179
16180    pub fn set_selections_from_remote(
16181        &mut self,
16182        selections: Vec<Selection<Anchor>>,
16183        pending_selection: Option<Selection<Anchor>>,
16184        window: &mut Window,
16185        cx: &mut Context<Self>,
16186    ) {
16187        let old_cursor_position = self.selections.newest_anchor().head();
16188        self.selections.change_with(cx, |s| {
16189            s.select_anchors(selections);
16190            if let Some(pending_selection) = pending_selection {
16191                s.set_pending(pending_selection, SelectMode::Character);
16192            } else {
16193                s.clear_pending();
16194            }
16195        });
16196        self.selections_did_change(false, &old_cursor_position, true, window, cx);
16197    }
16198
16199    pub fn transact(
16200        &mut self,
16201        window: &mut Window,
16202        cx: &mut Context<Self>,
16203        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16204    ) -> Option<TransactionId> {
16205        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16206            this.start_transaction_at(Instant::now(), window, cx);
16207            update(this, window, cx);
16208            this.end_transaction_at(Instant::now(), cx)
16209        })
16210    }
16211
16212    pub fn start_transaction_at(
16213        &mut self,
16214        now: Instant,
16215        window: &mut Window,
16216        cx: &mut Context<Self>,
16217    ) {
16218        self.end_selection(window, cx);
16219        if let Some(tx_id) = self
16220            .buffer
16221            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16222        {
16223            self.selection_history
16224                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16225            cx.emit(EditorEvent::TransactionBegun {
16226                transaction_id: tx_id,
16227            })
16228        }
16229    }
16230
16231    pub fn end_transaction_at(
16232        &mut self,
16233        now: Instant,
16234        cx: &mut Context<Self>,
16235    ) -> Option<TransactionId> {
16236        if let Some(transaction_id) = self
16237            .buffer
16238            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16239        {
16240            if let Some((_, end_selections)) =
16241                self.selection_history.transaction_mut(transaction_id)
16242            {
16243                *end_selections = Some(self.selections.disjoint_anchors());
16244            } else {
16245                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16246            }
16247
16248            cx.emit(EditorEvent::Edited { transaction_id });
16249            Some(transaction_id)
16250        } else {
16251            None
16252        }
16253    }
16254
16255    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16256        if self.selection_mark_mode {
16257            self.change_selections(None, window, cx, |s| {
16258                s.move_with(|_, sel| {
16259                    sel.collapse_to(sel.head(), SelectionGoal::None);
16260                });
16261            })
16262        }
16263        self.selection_mark_mode = true;
16264        cx.notify();
16265    }
16266
16267    pub fn swap_selection_ends(
16268        &mut self,
16269        _: &actions::SwapSelectionEnds,
16270        window: &mut Window,
16271        cx: &mut Context<Self>,
16272    ) {
16273        self.change_selections(None, window, cx, |s| {
16274            s.move_with(|_, sel| {
16275                if sel.start != sel.end {
16276                    sel.reversed = !sel.reversed
16277                }
16278            });
16279        });
16280        self.request_autoscroll(Autoscroll::newest(), cx);
16281        cx.notify();
16282    }
16283
16284    pub fn toggle_fold(
16285        &mut self,
16286        _: &actions::ToggleFold,
16287        window: &mut Window,
16288        cx: &mut Context<Self>,
16289    ) {
16290        if self.is_singleton(cx) {
16291            let selection = self.selections.newest::<Point>(cx);
16292
16293            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16294            let range = if selection.is_empty() {
16295                let point = selection.head().to_display_point(&display_map);
16296                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16297                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16298                    .to_point(&display_map);
16299                start..end
16300            } else {
16301                selection.range()
16302            };
16303            if display_map.folds_in_range(range).next().is_some() {
16304                self.unfold_lines(&Default::default(), window, cx)
16305            } else {
16306                self.fold(&Default::default(), window, cx)
16307            }
16308        } else {
16309            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16310            let buffer_ids: HashSet<_> = self
16311                .selections
16312                .disjoint_anchor_ranges()
16313                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16314                .collect();
16315
16316            let should_unfold = buffer_ids
16317                .iter()
16318                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16319
16320            for buffer_id in buffer_ids {
16321                if should_unfold {
16322                    self.unfold_buffer(buffer_id, cx);
16323                } else {
16324                    self.fold_buffer(buffer_id, cx);
16325                }
16326            }
16327        }
16328    }
16329
16330    pub fn toggle_fold_recursive(
16331        &mut self,
16332        _: &actions::ToggleFoldRecursive,
16333        window: &mut Window,
16334        cx: &mut Context<Self>,
16335    ) {
16336        let selection = self.selections.newest::<Point>(cx);
16337
16338        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16339        let range = if selection.is_empty() {
16340            let point = selection.head().to_display_point(&display_map);
16341            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16342            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16343                .to_point(&display_map);
16344            start..end
16345        } else {
16346            selection.range()
16347        };
16348        if display_map.folds_in_range(range).next().is_some() {
16349            self.unfold_recursive(&Default::default(), window, cx)
16350        } else {
16351            self.fold_recursive(&Default::default(), window, cx)
16352        }
16353    }
16354
16355    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16356        if self.is_singleton(cx) {
16357            let mut to_fold = Vec::new();
16358            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16359            let selections = self.selections.all_adjusted(cx);
16360
16361            for selection in selections {
16362                let range = selection.range().sorted();
16363                let buffer_start_row = range.start.row;
16364
16365                if range.start.row != range.end.row {
16366                    let mut found = false;
16367                    let mut row = range.start.row;
16368                    while row <= range.end.row {
16369                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16370                        {
16371                            found = true;
16372                            row = crease.range().end.row + 1;
16373                            to_fold.push(crease);
16374                        } else {
16375                            row += 1
16376                        }
16377                    }
16378                    if found {
16379                        continue;
16380                    }
16381                }
16382
16383                for row in (0..=range.start.row).rev() {
16384                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16385                        if crease.range().end.row >= buffer_start_row {
16386                            to_fold.push(crease);
16387                            if row <= range.start.row {
16388                                break;
16389                            }
16390                        }
16391                    }
16392                }
16393            }
16394
16395            self.fold_creases(to_fold, true, window, cx);
16396        } else {
16397            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16398            let buffer_ids = self
16399                .selections
16400                .disjoint_anchor_ranges()
16401                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16402                .collect::<HashSet<_>>();
16403            for buffer_id in buffer_ids {
16404                self.fold_buffer(buffer_id, cx);
16405            }
16406        }
16407    }
16408
16409    fn fold_at_level(
16410        &mut self,
16411        fold_at: &FoldAtLevel,
16412        window: &mut Window,
16413        cx: &mut Context<Self>,
16414    ) {
16415        if !self.buffer.read(cx).is_singleton() {
16416            return;
16417        }
16418
16419        let fold_at_level = fold_at.0;
16420        let snapshot = self.buffer.read(cx).snapshot(cx);
16421        let mut to_fold = Vec::new();
16422        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16423
16424        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16425            while start_row < end_row {
16426                match self
16427                    .snapshot(window, cx)
16428                    .crease_for_buffer_row(MultiBufferRow(start_row))
16429                {
16430                    Some(crease) => {
16431                        let nested_start_row = crease.range().start.row + 1;
16432                        let nested_end_row = crease.range().end.row;
16433
16434                        if current_level < fold_at_level {
16435                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16436                        } else if current_level == fold_at_level {
16437                            to_fold.push(crease);
16438                        }
16439
16440                        start_row = nested_end_row + 1;
16441                    }
16442                    None => start_row += 1,
16443                }
16444            }
16445        }
16446
16447        self.fold_creases(to_fold, true, window, cx);
16448    }
16449
16450    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16451        if self.buffer.read(cx).is_singleton() {
16452            let mut fold_ranges = Vec::new();
16453            let snapshot = self.buffer.read(cx).snapshot(cx);
16454
16455            for row in 0..snapshot.max_row().0 {
16456                if let Some(foldable_range) = self
16457                    .snapshot(window, cx)
16458                    .crease_for_buffer_row(MultiBufferRow(row))
16459                {
16460                    fold_ranges.push(foldable_range);
16461                }
16462            }
16463
16464            self.fold_creases(fold_ranges, true, window, cx);
16465        } else {
16466            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16467                editor
16468                    .update_in(cx, |editor, _, cx| {
16469                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16470                            editor.fold_buffer(buffer_id, cx);
16471                        }
16472                    })
16473                    .ok();
16474            });
16475        }
16476    }
16477
16478    pub fn fold_function_bodies(
16479        &mut self,
16480        _: &actions::FoldFunctionBodies,
16481        window: &mut Window,
16482        cx: &mut Context<Self>,
16483    ) {
16484        let snapshot = self.buffer.read(cx).snapshot(cx);
16485
16486        let ranges = snapshot
16487            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16488            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16489            .collect::<Vec<_>>();
16490
16491        let creases = ranges
16492            .into_iter()
16493            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16494            .collect();
16495
16496        self.fold_creases(creases, true, window, cx);
16497    }
16498
16499    pub fn fold_recursive(
16500        &mut self,
16501        _: &actions::FoldRecursive,
16502        window: &mut Window,
16503        cx: &mut Context<Self>,
16504    ) {
16505        let mut to_fold = Vec::new();
16506        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16507        let selections = self.selections.all_adjusted(cx);
16508
16509        for selection in selections {
16510            let range = selection.range().sorted();
16511            let buffer_start_row = range.start.row;
16512
16513            if range.start.row != range.end.row {
16514                let mut found = false;
16515                for row in range.start.row..=range.end.row {
16516                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16517                        found = true;
16518                        to_fold.push(crease);
16519                    }
16520                }
16521                if found {
16522                    continue;
16523                }
16524            }
16525
16526            for row in (0..=range.start.row).rev() {
16527                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16528                    if crease.range().end.row >= buffer_start_row {
16529                        to_fold.push(crease);
16530                    } else {
16531                        break;
16532                    }
16533                }
16534            }
16535        }
16536
16537        self.fold_creases(to_fold, true, window, cx);
16538    }
16539
16540    pub fn fold_at(
16541        &mut self,
16542        buffer_row: MultiBufferRow,
16543        window: &mut Window,
16544        cx: &mut Context<Self>,
16545    ) {
16546        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16547
16548        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16549            let autoscroll = self
16550                .selections
16551                .all::<Point>(cx)
16552                .iter()
16553                .any(|selection| crease.range().overlaps(&selection.range()));
16554
16555            self.fold_creases(vec![crease], autoscroll, window, cx);
16556        }
16557    }
16558
16559    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16560        if self.is_singleton(cx) {
16561            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16562            let buffer = &display_map.buffer_snapshot;
16563            let selections = self.selections.all::<Point>(cx);
16564            let ranges = selections
16565                .iter()
16566                .map(|s| {
16567                    let range = s.display_range(&display_map).sorted();
16568                    let mut start = range.start.to_point(&display_map);
16569                    let mut end = range.end.to_point(&display_map);
16570                    start.column = 0;
16571                    end.column = buffer.line_len(MultiBufferRow(end.row));
16572                    start..end
16573                })
16574                .collect::<Vec<_>>();
16575
16576            self.unfold_ranges(&ranges, true, true, cx);
16577        } else {
16578            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16579            let buffer_ids = self
16580                .selections
16581                .disjoint_anchor_ranges()
16582                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16583                .collect::<HashSet<_>>();
16584            for buffer_id in buffer_ids {
16585                self.unfold_buffer(buffer_id, cx);
16586            }
16587        }
16588    }
16589
16590    pub fn unfold_recursive(
16591        &mut self,
16592        _: &UnfoldRecursive,
16593        _window: &mut Window,
16594        cx: &mut Context<Self>,
16595    ) {
16596        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16597        let selections = self.selections.all::<Point>(cx);
16598        let ranges = selections
16599            .iter()
16600            .map(|s| {
16601                let mut range = s.display_range(&display_map).sorted();
16602                *range.start.column_mut() = 0;
16603                *range.end.column_mut() = display_map.line_len(range.end.row());
16604                let start = range.start.to_point(&display_map);
16605                let end = range.end.to_point(&display_map);
16606                start..end
16607            })
16608            .collect::<Vec<_>>();
16609
16610        self.unfold_ranges(&ranges, true, true, cx);
16611    }
16612
16613    pub fn unfold_at(
16614        &mut self,
16615        buffer_row: MultiBufferRow,
16616        _window: &mut Window,
16617        cx: &mut Context<Self>,
16618    ) {
16619        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16620
16621        let intersection_range = Point::new(buffer_row.0, 0)
16622            ..Point::new(
16623                buffer_row.0,
16624                display_map.buffer_snapshot.line_len(buffer_row),
16625            );
16626
16627        let autoscroll = self
16628            .selections
16629            .all::<Point>(cx)
16630            .iter()
16631            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16632
16633        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16634    }
16635
16636    pub fn unfold_all(
16637        &mut self,
16638        _: &actions::UnfoldAll,
16639        _window: &mut Window,
16640        cx: &mut Context<Self>,
16641    ) {
16642        if self.buffer.read(cx).is_singleton() {
16643            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16644            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16645        } else {
16646            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16647                editor
16648                    .update(cx, |editor, cx| {
16649                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16650                            editor.unfold_buffer(buffer_id, cx);
16651                        }
16652                    })
16653                    .ok();
16654            });
16655        }
16656    }
16657
16658    pub fn fold_selected_ranges(
16659        &mut self,
16660        _: &FoldSelectedRanges,
16661        window: &mut Window,
16662        cx: &mut Context<Self>,
16663    ) {
16664        let selections = self.selections.all_adjusted(cx);
16665        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16666        let ranges = selections
16667            .into_iter()
16668            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16669            .collect::<Vec<_>>();
16670        self.fold_creases(ranges, true, window, cx);
16671    }
16672
16673    pub fn fold_ranges<T: ToOffset + Clone>(
16674        &mut self,
16675        ranges: Vec<Range<T>>,
16676        auto_scroll: bool,
16677        window: &mut Window,
16678        cx: &mut Context<Self>,
16679    ) {
16680        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16681        let ranges = ranges
16682            .into_iter()
16683            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16684            .collect::<Vec<_>>();
16685        self.fold_creases(ranges, auto_scroll, window, cx);
16686    }
16687
16688    pub fn fold_creases<T: ToOffset + Clone>(
16689        &mut self,
16690        creases: Vec<Crease<T>>,
16691        auto_scroll: bool,
16692        _window: &mut Window,
16693        cx: &mut Context<Self>,
16694    ) {
16695        if creases.is_empty() {
16696            return;
16697        }
16698
16699        let mut buffers_affected = HashSet::default();
16700        let multi_buffer = self.buffer().read(cx);
16701        for crease in &creases {
16702            if let Some((_, buffer, _)) =
16703                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16704            {
16705                buffers_affected.insert(buffer.read(cx).remote_id());
16706            };
16707        }
16708
16709        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16710
16711        if auto_scroll {
16712            self.request_autoscroll(Autoscroll::fit(), cx);
16713        }
16714
16715        cx.notify();
16716
16717        self.scrollbar_marker_state.dirty = true;
16718        self.folds_did_change(cx);
16719    }
16720
16721    /// Removes any folds whose ranges intersect any of the given ranges.
16722    pub fn unfold_ranges<T: ToOffset + Clone>(
16723        &mut self,
16724        ranges: &[Range<T>],
16725        inclusive: bool,
16726        auto_scroll: bool,
16727        cx: &mut Context<Self>,
16728    ) {
16729        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16730            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16731        });
16732        self.folds_did_change(cx);
16733    }
16734
16735    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16736        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16737            return;
16738        }
16739        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16740        self.display_map.update(cx, |display_map, cx| {
16741            display_map.fold_buffers([buffer_id], cx)
16742        });
16743        cx.emit(EditorEvent::BufferFoldToggled {
16744            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16745            folded: true,
16746        });
16747        cx.notify();
16748    }
16749
16750    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16751        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16752            return;
16753        }
16754        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16755        self.display_map.update(cx, |display_map, cx| {
16756            display_map.unfold_buffers([buffer_id], cx);
16757        });
16758        cx.emit(EditorEvent::BufferFoldToggled {
16759            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16760            folded: false,
16761        });
16762        cx.notify();
16763    }
16764
16765    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16766        self.display_map.read(cx).is_buffer_folded(buffer)
16767    }
16768
16769    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16770        self.display_map.read(cx).folded_buffers()
16771    }
16772
16773    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16774        self.display_map.update(cx, |display_map, cx| {
16775            display_map.disable_header_for_buffer(buffer_id, cx);
16776        });
16777        cx.notify();
16778    }
16779
16780    /// Removes any folds with the given ranges.
16781    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16782        &mut self,
16783        ranges: &[Range<T>],
16784        type_id: TypeId,
16785        auto_scroll: bool,
16786        cx: &mut Context<Self>,
16787    ) {
16788        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16789            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16790        });
16791        self.folds_did_change(cx);
16792    }
16793
16794    fn remove_folds_with<T: ToOffset + Clone>(
16795        &mut self,
16796        ranges: &[Range<T>],
16797        auto_scroll: bool,
16798        cx: &mut Context<Self>,
16799        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16800    ) {
16801        if ranges.is_empty() {
16802            return;
16803        }
16804
16805        let mut buffers_affected = HashSet::default();
16806        let multi_buffer = self.buffer().read(cx);
16807        for range in ranges {
16808            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16809                buffers_affected.insert(buffer.read(cx).remote_id());
16810            };
16811        }
16812
16813        self.display_map.update(cx, update);
16814
16815        if auto_scroll {
16816            self.request_autoscroll(Autoscroll::fit(), cx);
16817        }
16818
16819        cx.notify();
16820        self.scrollbar_marker_state.dirty = true;
16821        self.active_indent_guides_state.dirty = true;
16822    }
16823
16824    pub fn update_fold_widths(
16825        &mut self,
16826        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16827        cx: &mut Context<Self>,
16828    ) -> bool {
16829        self.display_map
16830            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16831    }
16832
16833    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16834        self.display_map.read(cx).fold_placeholder.clone()
16835    }
16836
16837    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16838        self.buffer.update(cx, |buffer, cx| {
16839            buffer.set_all_diff_hunks_expanded(cx);
16840        });
16841    }
16842
16843    pub fn expand_all_diff_hunks(
16844        &mut self,
16845        _: &ExpandAllDiffHunks,
16846        _window: &mut Window,
16847        cx: &mut Context<Self>,
16848    ) {
16849        self.buffer.update(cx, |buffer, cx| {
16850            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16851        });
16852    }
16853
16854    pub fn toggle_selected_diff_hunks(
16855        &mut self,
16856        _: &ToggleSelectedDiffHunks,
16857        _window: &mut Window,
16858        cx: &mut Context<Self>,
16859    ) {
16860        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16861        self.toggle_diff_hunks_in_ranges(ranges, cx);
16862    }
16863
16864    pub fn diff_hunks_in_ranges<'a>(
16865        &'a self,
16866        ranges: &'a [Range<Anchor>],
16867        buffer: &'a MultiBufferSnapshot,
16868    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16869        ranges.iter().flat_map(move |range| {
16870            let end_excerpt_id = range.end.excerpt_id;
16871            let range = range.to_point(buffer);
16872            let mut peek_end = range.end;
16873            if range.end.row < buffer.max_row().0 {
16874                peek_end = Point::new(range.end.row + 1, 0);
16875            }
16876            buffer
16877                .diff_hunks_in_range(range.start..peek_end)
16878                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16879        })
16880    }
16881
16882    pub fn has_stageable_diff_hunks_in_ranges(
16883        &self,
16884        ranges: &[Range<Anchor>],
16885        snapshot: &MultiBufferSnapshot,
16886    ) -> bool {
16887        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16888        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16889    }
16890
16891    pub fn toggle_staged_selected_diff_hunks(
16892        &mut self,
16893        _: &::git::ToggleStaged,
16894        _: &mut Window,
16895        cx: &mut Context<Self>,
16896    ) {
16897        let snapshot = self.buffer.read(cx).snapshot(cx);
16898        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16899        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16900        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16901    }
16902
16903    pub fn set_render_diff_hunk_controls(
16904        &mut self,
16905        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16906        cx: &mut Context<Self>,
16907    ) {
16908        self.render_diff_hunk_controls = render_diff_hunk_controls;
16909        cx.notify();
16910    }
16911
16912    pub fn stage_and_next(
16913        &mut self,
16914        _: &::git::StageAndNext,
16915        window: &mut Window,
16916        cx: &mut Context<Self>,
16917    ) {
16918        self.do_stage_or_unstage_and_next(true, window, cx);
16919    }
16920
16921    pub fn unstage_and_next(
16922        &mut self,
16923        _: &::git::UnstageAndNext,
16924        window: &mut Window,
16925        cx: &mut Context<Self>,
16926    ) {
16927        self.do_stage_or_unstage_and_next(false, window, cx);
16928    }
16929
16930    pub fn stage_or_unstage_diff_hunks(
16931        &mut self,
16932        stage: bool,
16933        ranges: Vec<Range<Anchor>>,
16934        cx: &mut Context<Self>,
16935    ) {
16936        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16937        cx.spawn(async move |this, cx| {
16938            task.await?;
16939            this.update(cx, |this, cx| {
16940                let snapshot = this.buffer.read(cx).snapshot(cx);
16941                let chunk_by = this
16942                    .diff_hunks_in_ranges(&ranges, &snapshot)
16943                    .chunk_by(|hunk| hunk.buffer_id);
16944                for (buffer_id, hunks) in &chunk_by {
16945                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16946                }
16947            })
16948        })
16949        .detach_and_log_err(cx);
16950    }
16951
16952    fn save_buffers_for_ranges_if_needed(
16953        &mut self,
16954        ranges: &[Range<Anchor>],
16955        cx: &mut Context<Editor>,
16956    ) -> Task<Result<()>> {
16957        let multibuffer = self.buffer.read(cx);
16958        let snapshot = multibuffer.read(cx);
16959        let buffer_ids: HashSet<_> = ranges
16960            .iter()
16961            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16962            .collect();
16963        drop(snapshot);
16964
16965        let mut buffers = HashSet::default();
16966        for buffer_id in buffer_ids {
16967            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16968                let buffer = buffer_entity.read(cx);
16969                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16970                {
16971                    buffers.insert(buffer_entity);
16972                }
16973            }
16974        }
16975
16976        if let Some(project) = &self.project {
16977            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16978        } else {
16979            Task::ready(Ok(()))
16980        }
16981    }
16982
16983    fn do_stage_or_unstage_and_next(
16984        &mut self,
16985        stage: bool,
16986        window: &mut Window,
16987        cx: &mut Context<Self>,
16988    ) {
16989        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16990
16991        if ranges.iter().any(|range| range.start != range.end) {
16992            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16993            return;
16994        }
16995
16996        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16997        let snapshot = self.snapshot(window, cx);
16998        let position = self.selections.newest::<Point>(cx).head();
16999        let mut row = snapshot
17000            .buffer_snapshot
17001            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17002            .find(|hunk| hunk.row_range.start.0 > position.row)
17003            .map(|hunk| hunk.row_range.start);
17004
17005        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17006        // Outside of the project diff editor, wrap around to the beginning.
17007        if !all_diff_hunks_expanded {
17008            row = row.or_else(|| {
17009                snapshot
17010                    .buffer_snapshot
17011                    .diff_hunks_in_range(Point::zero()..position)
17012                    .find(|hunk| hunk.row_range.end.0 < position.row)
17013                    .map(|hunk| hunk.row_range.start)
17014            });
17015        }
17016
17017        if let Some(row) = row {
17018            let destination = Point::new(row.0, 0);
17019            let autoscroll = Autoscroll::center();
17020
17021            self.unfold_ranges(&[destination..destination], false, false, cx);
17022            self.change_selections(Some(autoscroll), window, cx, |s| {
17023                s.select_ranges([destination..destination]);
17024            });
17025        }
17026    }
17027
17028    fn do_stage_or_unstage(
17029        &self,
17030        stage: bool,
17031        buffer_id: BufferId,
17032        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17033        cx: &mut App,
17034    ) -> Option<()> {
17035        let project = self.project.as_ref()?;
17036        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17037        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17038        let buffer_snapshot = buffer.read(cx).snapshot();
17039        let file_exists = buffer_snapshot
17040            .file()
17041            .is_some_and(|file| file.disk_state().exists());
17042        diff.update(cx, |diff, cx| {
17043            diff.stage_or_unstage_hunks(
17044                stage,
17045                &hunks
17046                    .map(|hunk| buffer_diff::DiffHunk {
17047                        buffer_range: hunk.buffer_range,
17048                        diff_base_byte_range: hunk.diff_base_byte_range,
17049                        secondary_status: hunk.secondary_status,
17050                        range: Point::zero()..Point::zero(), // unused
17051                    })
17052                    .collect::<Vec<_>>(),
17053                &buffer_snapshot,
17054                file_exists,
17055                cx,
17056            )
17057        });
17058        None
17059    }
17060
17061    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17062        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17063        self.buffer
17064            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17065    }
17066
17067    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17068        self.buffer.update(cx, |buffer, cx| {
17069            let ranges = vec![Anchor::min()..Anchor::max()];
17070            if !buffer.all_diff_hunks_expanded()
17071                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17072            {
17073                buffer.collapse_diff_hunks(ranges, cx);
17074                true
17075            } else {
17076                false
17077            }
17078        })
17079    }
17080
17081    fn toggle_diff_hunks_in_ranges(
17082        &mut self,
17083        ranges: Vec<Range<Anchor>>,
17084        cx: &mut Context<Editor>,
17085    ) {
17086        self.buffer.update(cx, |buffer, cx| {
17087            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17088            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17089        })
17090    }
17091
17092    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17093        self.buffer.update(cx, |buffer, cx| {
17094            let snapshot = buffer.snapshot(cx);
17095            let excerpt_id = range.end.excerpt_id;
17096            let point_range = range.to_point(&snapshot);
17097            let expand = !buffer.single_hunk_is_expanded(range, cx);
17098            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17099        })
17100    }
17101
17102    pub(crate) fn apply_all_diff_hunks(
17103        &mut self,
17104        _: &ApplyAllDiffHunks,
17105        window: &mut Window,
17106        cx: &mut Context<Self>,
17107    ) {
17108        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17109
17110        let buffers = self.buffer.read(cx).all_buffers();
17111        for branch_buffer in buffers {
17112            branch_buffer.update(cx, |branch_buffer, cx| {
17113                branch_buffer.merge_into_base(Vec::new(), cx);
17114            });
17115        }
17116
17117        if let Some(project) = self.project.clone() {
17118            self.save(true, project, window, cx).detach_and_log_err(cx);
17119        }
17120    }
17121
17122    pub(crate) fn apply_selected_diff_hunks(
17123        &mut self,
17124        _: &ApplyDiffHunk,
17125        window: &mut Window,
17126        cx: &mut Context<Self>,
17127    ) {
17128        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17129        let snapshot = self.snapshot(window, cx);
17130        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17131        let mut ranges_by_buffer = HashMap::default();
17132        self.transact(window, cx, |editor, _window, cx| {
17133            for hunk in hunks {
17134                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17135                    ranges_by_buffer
17136                        .entry(buffer.clone())
17137                        .or_insert_with(Vec::new)
17138                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17139                }
17140            }
17141
17142            for (buffer, ranges) in ranges_by_buffer {
17143                buffer.update(cx, |buffer, cx| {
17144                    buffer.merge_into_base(ranges, cx);
17145                });
17146            }
17147        });
17148
17149        if let Some(project) = self.project.clone() {
17150            self.save(true, project, window, cx).detach_and_log_err(cx);
17151        }
17152    }
17153
17154    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17155        if hovered != self.gutter_hovered {
17156            self.gutter_hovered = hovered;
17157            cx.notify();
17158        }
17159    }
17160
17161    pub fn insert_blocks(
17162        &mut self,
17163        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17164        autoscroll: Option<Autoscroll>,
17165        cx: &mut Context<Self>,
17166    ) -> Vec<CustomBlockId> {
17167        let blocks = self
17168            .display_map
17169            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17170        if let Some(autoscroll) = autoscroll {
17171            self.request_autoscroll(autoscroll, cx);
17172        }
17173        cx.notify();
17174        blocks
17175    }
17176
17177    pub fn resize_blocks(
17178        &mut self,
17179        heights: HashMap<CustomBlockId, u32>,
17180        autoscroll: Option<Autoscroll>,
17181        cx: &mut Context<Self>,
17182    ) {
17183        self.display_map
17184            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17185        if let Some(autoscroll) = autoscroll {
17186            self.request_autoscroll(autoscroll, cx);
17187        }
17188        cx.notify();
17189    }
17190
17191    pub fn replace_blocks(
17192        &mut self,
17193        renderers: HashMap<CustomBlockId, RenderBlock>,
17194        autoscroll: Option<Autoscroll>,
17195        cx: &mut Context<Self>,
17196    ) {
17197        self.display_map
17198            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17199        if let Some(autoscroll) = autoscroll {
17200            self.request_autoscroll(autoscroll, cx);
17201        }
17202        cx.notify();
17203    }
17204
17205    pub fn remove_blocks(
17206        &mut self,
17207        block_ids: HashSet<CustomBlockId>,
17208        autoscroll: Option<Autoscroll>,
17209        cx: &mut Context<Self>,
17210    ) {
17211        self.display_map.update(cx, |display_map, cx| {
17212            display_map.remove_blocks(block_ids, cx)
17213        });
17214        if let Some(autoscroll) = autoscroll {
17215            self.request_autoscroll(autoscroll, cx);
17216        }
17217        cx.notify();
17218    }
17219
17220    pub fn row_for_block(
17221        &self,
17222        block_id: CustomBlockId,
17223        cx: &mut Context<Self>,
17224    ) -> Option<DisplayRow> {
17225        self.display_map
17226            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17227    }
17228
17229    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17230        self.focused_block = Some(focused_block);
17231    }
17232
17233    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17234        self.focused_block.take()
17235    }
17236
17237    pub fn insert_creases(
17238        &mut self,
17239        creases: impl IntoIterator<Item = Crease<Anchor>>,
17240        cx: &mut Context<Self>,
17241    ) -> Vec<CreaseId> {
17242        self.display_map
17243            .update(cx, |map, cx| map.insert_creases(creases, cx))
17244    }
17245
17246    pub fn remove_creases(
17247        &mut self,
17248        ids: impl IntoIterator<Item = CreaseId>,
17249        cx: &mut Context<Self>,
17250    ) -> Vec<(CreaseId, Range<Anchor>)> {
17251        self.display_map
17252            .update(cx, |map, cx| map.remove_creases(ids, cx))
17253    }
17254
17255    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17256        self.display_map
17257            .update(cx, |map, cx| map.snapshot(cx))
17258            .longest_row()
17259    }
17260
17261    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17262        self.display_map
17263            .update(cx, |map, cx| map.snapshot(cx))
17264            .max_point()
17265    }
17266
17267    pub fn text(&self, cx: &App) -> String {
17268        self.buffer.read(cx).read(cx).text()
17269    }
17270
17271    pub fn is_empty(&self, cx: &App) -> bool {
17272        self.buffer.read(cx).read(cx).is_empty()
17273    }
17274
17275    pub fn text_option(&self, cx: &App) -> Option<String> {
17276        let text = self.text(cx);
17277        let text = text.trim();
17278
17279        if text.is_empty() {
17280            return None;
17281        }
17282
17283        Some(text.to_string())
17284    }
17285
17286    pub fn set_text(
17287        &mut self,
17288        text: impl Into<Arc<str>>,
17289        window: &mut Window,
17290        cx: &mut Context<Self>,
17291    ) {
17292        self.transact(window, cx, |this, _, cx| {
17293            this.buffer
17294                .read(cx)
17295                .as_singleton()
17296                .expect("you can only call set_text on editors for singleton buffers")
17297                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17298        });
17299    }
17300
17301    pub fn display_text(&self, cx: &mut App) -> String {
17302        self.display_map
17303            .update(cx, |map, cx| map.snapshot(cx))
17304            .text()
17305    }
17306
17307    fn create_minimap(
17308        &self,
17309        minimap_settings: MinimapSettings,
17310        window: &mut Window,
17311        cx: &mut Context<Self>,
17312    ) -> Option<Entity<Self>> {
17313        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17314            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17315    }
17316
17317    fn initialize_new_minimap(
17318        &self,
17319        minimap_settings: MinimapSettings,
17320        window: &mut Window,
17321        cx: &mut Context<Self>,
17322    ) -> Entity<Self> {
17323        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17324
17325        let mut minimap = Editor::new_internal(
17326            EditorMode::Minimap {
17327                parent: cx.weak_entity(),
17328            },
17329            self.buffer.clone(),
17330            self.project.clone(),
17331            Some(self.display_map.clone()),
17332            window,
17333            cx,
17334        );
17335        minimap.scroll_manager.clone_state(&self.scroll_manager);
17336        minimap.set_text_style_refinement(TextStyleRefinement {
17337            font_size: Some(MINIMAP_FONT_SIZE),
17338            font_weight: Some(MINIMAP_FONT_WEIGHT),
17339            ..Default::default()
17340        });
17341        minimap.update_minimap_configuration(minimap_settings, cx);
17342        cx.new(|_| minimap)
17343    }
17344
17345    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17346        let current_line_highlight = minimap_settings
17347            .current_line_highlight
17348            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17349        self.set_current_line_highlight(Some(current_line_highlight));
17350    }
17351
17352    pub fn minimap(&self) -> Option<&Entity<Self>> {
17353        self.minimap
17354            .as_ref()
17355            .filter(|_| self.minimap_visibility.visible())
17356    }
17357
17358    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17359        let mut wrap_guides = smallvec![];
17360
17361        if self.show_wrap_guides == Some(false) {
17362            return wrap_guides;
17363        }
17364
17365        let settings = self.buffer.read(cx).language_settings(cx);
17366        if settings.show_wrap_guides {
17367            match self.soft_wrap_mode(cx) {
17368                SoftWrap::Column(soft_wrap) => {
17369                    wrap_guides.push((soft_wrap as usize, true));
17370                }
17371                SoftWrap::Bounded(soft_wrap) => {
17372                    wrap_guides.push((soft_wrap as usize, true));
17373                }
17374                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17375            }
17376            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17377        }
17378
17379        wrap_guides
17380    }
17381
17382    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17383        let settings = self.buffer.read(cx).language_settings(cx);
17384        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17385        match mode {
17386            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17387                SoftWrap::None
17388            }
17389            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17390            language_settings::SoftWrap::PreferredLineLength => {
17391                SoftWrap::Column(settings.preferred_line_length)
17392            }
17393            language_settings::SoftWrap::Bounded => {
17394                SoftWrap::Bounded(settings.preferred_line_length)
17395            }
17396        }
17397    }
17398
17399    pub fn set_soft_wrap_mode(
17400        &mut self,
17401        mode: language_settings::SoftWrap,
17402
17403        cx: &mut Context<Self>,
17404    ) {
17405        self.soft_wrap_mode_override = Some(mode);
17406        cx.notify();
17407    }
17408
17409    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17410        self.hard_wrap = hard_wrap;
17411        cx.notify();
17412    }
17413
17414    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17415        self.text_style_refinement = Some(style);
17416    }
17417
17418    /// called by the Element so we know what style we were most recently rendered with.
17419    pub(crate) fn set_style(
17420        &mut self,
17421        style: EditorStyle,
17422        window: &mut Window,
17423        cx: &mut Context<Self>,
17424    ) {
17425        // We intentionally do not inform the display map about the minimap style
17426        // so that wrapping is not recalculated and stays consistent for the editor
17427        // and its linked minimap.
17428        if !self.mode.is_minimap() {
17429            let rem_size = window.rem_size();
17430            self.display_map.update(cx, |map, cx| {
17431                map.set_font(
17432                    style.text.font(),
17433                    style.text.font_size.to_pixels(rem_size),
17434                    cx,
17435                )
17436            });
17437        }
17438        self.style = Some(style);
17439    }
17440
17441    pub fn style(&self) -> Option<&EditorStyle> {
17442        self.style.as_ref()
17443    }
17444
17445    // Called by the element. This method is not designed to be called outside of the editor
17446    // element's layout code because it does not notify when rewrapping is computed synchronously.
17447    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17448        self.display_map
17449            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17450    }
17451
17452    pub fn set_soft_wrap(&mut self) {
17453        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17454    }
17455
17456    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17457        if self.soft_wrap_mode_override.is_some() {
17458            self.soft_wrap_mode_override.take();
17459        } else {
17460            let soft_wrap = match self.soft_wrap_mode(cx) {
17461                SoftWrap::GitDiff => return,
17462                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17463                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17464                    language_settings::SoftWrap::None
17465                }
17466            };
17467            self.soft_wrap_mode_override = Some(soft_wrap);
17468        }
17469        cx.notify();
17470    }
17471
17472    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17473        let Some(workspace) = self.workspace() else {
17474            return;
17475        };
17476        let fs = workspace.read(cx).app_state().fs.clone();
17477        let current_show = TabBarSettings::get_global(cx).show;
17478        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17479            setting.show = Some(!current_show);
17480        });
17481    }
17482
17483    pub fn toggle_indent_guides(
17484        &mut self,
17485        _: &ToggleIndentGuides,
17486        _: &mut Window,
17487        cx: &mut Context<Self>,
17488    ) {
17489        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17490            self.buffer
17491                .read(cx)
17492                .language_settings(cx)
17493                .indent_guides
17494                .enabled
17495        });
17496        self.show_indent_guides = Some(!currently_enabled);
17497        cx.notify();
17498    }
17499
17500    fn should_show_indent_guides(&self) -> Option<bool> {
17501        self.show_indent_guides
17502    }
17503
17504    pub fn toggle_line_numbers(
17505        &mut self,
17506        _: &ToggleLineNumbers,
17507        _: &mut Window,
17508        cx: &mut Context<Self>,
17509    ) {
17510        let mut editor_settings = EditorSettings::get_global(cx).clone();
17511        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17512        EditorSettings::override_global(editor_settings, cx);
17513    }
17514
17515    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17516        if let Some(show_line_numbers) = self.show_line_numbers {
17517            return show_line_numbers;
17518        }
17519        EditorSettings::get_global(cx).gutter.line_numbers
17520    }
17521
17522    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17523        self.use_relative_line_numbers
17524            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17525    }
17526
17527    pub fn toggle_relative_line_numbers(
17528        &mut self,
17529        _: &ToggleRelativeLineNumbers,
17530        _: &mut Window,
17531        cx: &mut Context<Self>,
17532    ) {
17533        let is_relative = self.should_use_relative_line_numbers(cx);
17534        self.set_relative_line_number(Some(!is_relative), cx)
17535    }
17536
17537    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17538        self.use_relative_line_numbers = is_relative;
17539        cx.notify();
17540    }
17541
17542    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17543        self.show_gutter = show_gutter;
17544        cx.notify();
17545    }
17546
17547    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17548        self.show_scrollbars = ScrollbarAxes {
17549            horizontal: show,
17550            vertical: show,
17551        };
17552        cx.notify();
17553    }
17554
17555    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17556        self.show_scrollbars.vertical = show;
17557        cx.notify();
17558    }
17559
17560    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17561        self.show_scrollbars.horizontal = show;
17562        cx.notify();
17563    }
17564
17565    pub fn set_minimap_visibility(
17566        &mut self,
17567        minimap_visibility: MinimapVisibility,
17568        window: &mut Window,
17569        cx: &mut Context<Self>,
17570    ) {
17571        if self.minimap_visibility != minimap_visibility {
17572            if minimap_visibility.visible() && self.minimap.is_none() {
17573                let minimap_settings = EditorSettings::get_global(cx).minimap;
17574                self.minimap =
17575                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17576            }
17577            self.minimap_visibility = minimap_visibility;
17578            cx.notify();
17579        }
17580    }
17581
17582    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17583        self.set_show_scrollbars(false, cx);
17584        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17585    }
17586
17587    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17588        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17589    }
17590
17591    /// Normally the text in full mode and auto height editors is padded on the
17592    /// left side by roughly half a character width for improved hit testing.
17593    ///
17594    /// Use this method to disable this for cases where this is not wanted (e.g.
17595    /// if you want to align the editor text with some other text above or below)
17596    /// or if you want to add this padding to single-line editors.
17597    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17598        self.offset_content = offset_content;
17599        cx.notify();
17600    }
17601
17602    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17603        self.show_line_numbers = Some(show_line_numbers);
17604        cx.notify();
17605    }
17606
17607    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17608        self.disable_expand_excerpt_buttons = true;
17609        cx.notify();
17610    }
17611
17612    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17613        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17614        cx.notify();
17615    }
17616
17617    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17618        self.show_code_actions = Some(show_code_actions);
17619        cx.notify();
17620    }
17621
17622    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17623        self.show_runnables = Some(show_runnables);
17624        cx.notify();
17625    }
17626
17627    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17628        self.show_breakpoints = Some(show_breakpoints);
17629        cx.notify();
17630    }
17631
17632    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17633        if self.display_map.read(cx).masked != masked {
17634            self.display_map.update(cx, |map, _| map.masked = masked);
17635        }
17636        cx.notify()
17637    }
17638
17639    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17640        self.show_wrap_guides = Some(show_wrap_guides);
17641        cx.notify();
17642    }
17643
17644    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17645        self.show_indent_guides = Some(show_indent_guides);
17646        cx.notify();
17647    }
17648
17649    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17650        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17651            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17652                if let Some(dir) = file.abs_path(cx).parent() {
17653                    return Some(dir.to_owned());
17654                }
17655            }
17656
17657            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17658                return Some(project_path.path.to_path_buf());
17659            }
17660        }
17661
17662        None
17663    }
17664
17665    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17666        self.active_excerpt(cx)?
17667            .1
17668            .read(cx)
17669            .file()
17670            .and_then(|f| f.as_local())
17671    }
17672
17673    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17674        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17675            let buffer = buffer.read(cx);
17676            if let Some(project_path) = buffer.project_path(cx) {
17677                let project = self.project.as_ref()?.read(cx);
17678                project.absolute_path(&project_path, cx)
17679            } else {
17680                buffer
17681                    .file()
17682                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17683            }
17684        })
17685    }
17686
17687    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17688        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17689            let project_path = buffer.read(cx).project_path(cx)?;
17690            let project = self.project.as_ref()?.read(cx);
17691            let entry = project.entry_for_path(&project_path, cx)?;
17692            let path = entry.path.to_path_buf();
17693            Some(path)
17694        })
17695    }
17696
17697    pub fn reveal_in_finder(
17698        &mut self,
17699        _: &RevealInFileManager,
17700        _window: &mut Window,
17701        cx: &mut Context<Self>,
17702    ) {
17703        if let Some(target) = self.target_file(cx) {
17704            cx.reveal_path(&target.abs_path(cx));
17705        }
17706    }
17707
17708    pub fn copy_path(
17709        &mut self,
17710        _: &zed_actions::workspace::CopyPath,
17711        _window: &mut Window,
17712        cx: &mut Context<Self>,
17713    ) {
17714        if let Some(path) = self.target_file_abs_path(cx) {
17715            if let Some(path) = path.to_str() {
17716                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17717            }
17718        }
17719    }
17720
17721    pub fn copy_relative_path(
17722        &mut self,
17723        _: &zed_actions::workspace::CopyRelativePath,
17724        _window: &mut Window,
17725        cx: &mut Context<Self>,
17726    ) {
17727        if let Some(path) = self.target_file_path(cx) {
17728            if let Some(path) = path.to_str() {
17729                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17730            }
17731        }
17732    }
17733
17734    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17735        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17736            buffer.read(cx).project_path(cx)
17737        } else {
17738            None
17739        }
17740    }
17741
17742    // Returns true if the editor handled a go-to-line request
17743    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17744        maybe!({
17745            let breakpoint_store = self.breakpoint_store.as_ref()?;
17746
17747            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17748            else {
17749                self.clear_row_highlights::<ActiveDebugLine>();
17750                return None;
17751            };
17752
17753            let position = active_stack_frame.position;
17754            let buffer_id = position.buffer_id?;
17755            let snapshot = self
17756                .project
17757                .as_ref()?
17758                .read(cx)
17759                .buffer_for_id(buffer_id, cx)?
17760                .read(cx)
17761                .snapshot();
17762
17763            let mut handled = false;
17764            for (id, ExcerptRange { context, .. }) in
17765                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17766            {
17767                if context.start.cmp(&position, &snapshot).is_ge()
17768                    || context.end.cmp(&position, &snapshot).is_lt()
17769                {
17770                    continue;
17771                }
17772                let snapshot = self.buffer.read(cx).snapshot(cx);
17773                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17774
17775                handled = true;
17776                self.clear_row_highlights::<ActiveDebugLine>();
17777
17778                self.go_to_line::<ActiveDebugLine>(
17779                    multibuffer_anchor,
17780                    Some(cx.theme().colors().editor_debugger_active_line_background),
17781                    window,
17782                    cx,
17783                );
17784
17785                cx.notify();
17786            }
17787
17788            handled.then_some(())
17789        })
17790        .is_some()
17791    }
17792
17793    pub fn copy_file_name_without_extension(
17794        &mut self,
17795        _: &CopyFileNameWithoutExtension,
17796        _: &mut Window,
17797        cx: &mut Context<Self>,
17798    ) {
17799        if let Some(file) = self.target_file(cx) {
17800            if let Some(file_stem) = file.path().file_stem() {
17801                if let Some(name) = file_stem.to_str() {
17802                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17803                }
17804            }
17805        }
17806    }
17807
17808    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17809        if let Some(file) = self.target_file(cx) {
17810            if let Some(file_name) = file.path().file_name() {
17811                if let Some(name) = file_name.to_str() {
17812                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17813                }
17814            }
17815        }
17816    }
17817
17818    pub fn toggle_git_blame(
17819        &mut self,
17820        _: &::git::Blame,
17821        window: &mut Window,
17822        cx: &mut Context<Self>,
17823    ) {
17824        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17825
17826        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17827            self.start_git_blame(true, window, cx);
17828        }
17829
17830        cx.notify();
17831    }
17832
17833    pub fn toggle_git_blame_inline(
17834        &mut self,
17835        _: &ToggleGitBlameInline,
17836        window: &mut Window,
17837        cx: &mut Context<Self>,
17838    ) {
17839        self.toggle_git_blame_inline_internal(true, window, cx);
17840        cx.notify();
17841    }
17842
17843    pub fn open_git_blame_commit(
17844        &mut self,
17845        _: &OpenGitBlameCommit,
17846        window: &mut Window,
17847        cx: &mut Context<Self>,
17848    ) {
17849        self.open_git_blame_commit_internal(window, cx);
17850    }
17851
17852    fn open_git_blame_commit_internal(
17853        &mut self,
17854        window: &mut Window,
17855        cx: &mut Context<Self>,
17856    ) -> Option<()> {
17857        let blame = self.blame.as_ref()?;
17858        let snapshot = self.snapshot(window, cx);
17859        let cursor = self.selections.newest::<Point>(cx).head();
17860        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17861        let blame_entry = blame
17862            .update(cx, |blame, cx| {
17863                blame
17864                    .blame_for_rows(
17865                        &[RowInfo {
17866                            buffer_id: Some(buffer.remote_id()),
17867                            buffer_row: Some(point.row),
17868                            ..Default::default()
17869                        }],
17870                        cx,
17871                    )
17872                    .next()
17873            })
17874            .flatten()?;
17875        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17876        let repo = blame.read(cx).repository(cx)?;
17877        let workspace = self.workspace()?.downgrade();
17878        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17879        None
17880    }
17881
17882    pub fn git_blame_inline_enabled(&self) -> bool {
17883        self.git_blame_inline_enabled
17884    }
17885
17886    pub fn toggle_selection_menu(
17887        &mut self,
17888        _: &ToggleSelectionMenu,
17889        _: &mut Window,
17890        cx: &mut Context<Self>,
17891    ) {
17892        self.show_selection_menu = self
17893            .show_selection_menu
17894            .map(|show_selections_menu| !show_selections_menu)
17895            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17896
17897        cx.notify();
17898    }
17899
17900    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17901        self.show_selection_menu
17902            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17903    }
17904
17905    fn start_git_blame(
17906        &mut self,
17907        user_triggered: bool,
17908        window: &mut Window,
17909        cx: &mut Context<Self>,
17910    ) {
17911        if let Some(project) = self.project.as_ref() {
17912            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17913                return;
17914            };
17915
17916            if buffer.read(cx).file().is_none() {
17917                return;
17918            }
17919
17920            let focused = self.focus_handle(cx).contains_focused(window, cx);
17921
17922            let project = project.clone();
17923            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17924            self.blame_subscription =
17925                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17926            self.blame = Some(blame);
17927        }
17928    }
17929
17930    fn toggle_git_blame_inline_internal(
17931        &mut self,
17932        user_triggered: bool,
17933        window: &mut Window,
17934        cx: &mut Context<Self>,
17935    ) {
17936        if self.git_blame_inline_enabled {
17937            self.git_blame_inline_enabled = false;
17938            self.show_git_blame_inline = false;
17939            self.show_git_blame_inline_delay_task.take();
17940        } else {
17941            self.git_blame_inline_enabled = true;
17942            self.start_git_blame_inline(user_triggered, window, cx);
17943        }
17944
17945        cx.notify();
17946    }
17947
17948    fn start_git_blame_inline(
17949        &mut self,
17950        user_triggered: bool,
17951        window: &mut Window,
17952        cx: &mut Context<Self>,
17953    ) {
17954        self.start_git_blame(user_triggered, window, cx);
17955
17956        if ProjectSettings::get_global(cx)
17957            .git
17958            .inline_blame_delay()
17959            .is_some()
17960        {
17961            self.start_inline_blame_timer(window, cx);
17962        } else {
17963            self.show_git_blame_inline = true
17964        }
17965    }
17966
17967    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17968        self.blame.as_ref()
17969    }
17970
17971    pub fn show_git_blame_gutter(&self) -> bool {
17972        self.show_git_blame_gutter
17973    }
17974
17975    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17976        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17977    }
17978
17979    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17980        self.show_git_blame_inline
17981            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17982            && !self.newest_selection_head_on_empty_line(cx)
17983            && self.has_blame_entries(cx)
17984    }
17985
17986    fn has_blame_entries(&self, cx: &App) -> bool {
17987        self.blame()
17988            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17989    }
17990
17991    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17992        let cursor_anchor = self.selections.newest_anchor().head();
17993
17994        let snapshot = self.buffer.read(cx).snapshot(cx);
17995        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17996
17997        snapshot.line_len(buffer_row) == 0
17998    }
17999
18000    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18001        let buffer_and_selection = maybe!({
18002            let selection = self.selections.newest::<Point>(cx);
18003            let selection_range = selection.range();
18004
18005            let multi_buffer = self.buffer().read(cx);
18006            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18007            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18008
18009            let (buffer, range, _) = if selection.reversed {
18010                buffer_ranges.first()
18011            } else {
18012                buffer_ranges.last()
18013            }?;
18014
18015            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18016                ..text::ToPoint::to_point(&range.end, &buffer).row;
18017            Some((
18018                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18019                selection,
18020            ))
18021        });
18022
18023        let Some((buffer, selection)) = buffer_and_selection else {
18024            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18025        };
18026
18027        let Some(project) = self.project.as_ref() else {
18028            return Task::ready(Err(anyhow!("editor does not have project")));
18029        };
18030
18031        project.update(cx, |project, cx| {
18032            project.get_permalink_to_line(&buffer, selection, cx)
18033        })
18034    }
18035
18036    pub fn copy_permalink_to_line(
18037        &mut self,
18038        _: &CopyPermalinkToLine,
18039        window: &mut Window,
18040        cx: &mut Context<Self>,
18041    ) {
18042        let permalink_task = self.get_permalink_to_line(cx);
18043        let workspace = self.workspace();
18044
18045        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18046            Ok(permalink) => {
18047                cx.update(|_, cx| {
18048                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18049                })
18050                .ok();
18051            }
18052            Err(err) => {
18053                let message = format!("Failed to copy permalink: {err}");
18054
18055                anyhow::Result::<()>::Err(err).log_err();
18056
18057                if let Some(workspace) = workspace {
18058                    workspace
18059                        .update_in(cx, |workspace, _, cx| {
18060                            struct CopyPermalinkToLine;
18061
18062                            workspace.show_toast(
18063                                Toast::new(
18064                                    NotificationId::unique::<CopyPermalinkToLine>(),
18065                                    message,
18066                                ),
18067                                cx,
18068                            )
18069                        })
18070                        .ok();
18071                }
18072            }
18073        })
18074        .detach();
18075    }
18076
18077    pub fn copy_file_location(
18078        &mut self,
18079        _: &CopyFileLocation,
18080        _: &mut Window,
18081        cx: &mut Context<Self>,
18082    ) {
18083        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18084        if let Some(file) = self.target_file(cx) {
18085            if let Some(path) = file.path().to_str() {
18086                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18087            }
18088        }
18089    }
18090
18091    pub fn open_permalink_to_line(
18092        &mut self,
18093        _: &OpenPermalinkToLine,
18094        window: &mut Window,
18095        cx: &mut Context<Self>,
18096    ) {
18097        let permalink_task = self.get_permalink_to_line(cx);
18098        let workspace = self.workspace();
18099
18100        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18101            Ok(permalink) => {
18102                cx.update(|_, cx| {
18103                    cx.open_url(permalink.as_ref());
18104                })
18105                .ok();
18106            }
18107            Err(err) => {
18108                let message = format!("Failed to open permalink: {err}");
18109
18110                anyhow::Result::<()>::Err(err).log_err();
18111
18112                if let Some(workspace) = workspace {
18113                    workspace
18114                        .update(cx, |workspace, cx| {
18115                            struct OpenPermalinkToLine;
18116
18117                            workspace.show_toast(
18118                                Toast::new(
18119                                    NotificationId::unique::<OpenPermalinkToLine>(),
18120                                    message,
18121                                ),
18122                                cx,
18123                            )
18124                        })
18125                        .ok();
18126                }
18127            }
18128        })
18129        .detach();
18130    }
18131
18132    pub fn insert_uuid_v4(
18133        &mut self,
18134        _: &InsertUuidV4,
18135        window: &mut Window,
18136        cx: &mut Context<Self>,
18137    ) {
18138        self.insert_uuid(UuidVersion::V4, window, cx);
18139    }
18140
18141    pub fn insert_uuid_v7(
18142        &mut self,
18143        _: &InsertUuidV7,
18144        window: &mut Window,
18145        cx: &mut Context<Self>,
18146    ) {
18147        self.insert_uuid(UuidVersion::V7, window, cx);
18148    }
18149
18150    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18151        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
18152        self.transact(window, cx, |this, window, cx| {
18153            let edits = this
18154                .selections
18155                .all::<Point>(cx)
18156                .into_iter()
18157                .map(|selection| {
18158                    let uuid = match version {
18159                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18160                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18161                    };
18162
18163                    (selection.range(), uuid.to_string())
18164                });
18165            this.edit(edits, cx);
18166            this.refresh_inline_completion(true, false, window, cx);
18167        });
18168    }
18169
18170    pub fn open_selections_in_multibuffer(
18171        &mut self,
18172        _: &OpenSelectionsInMultibuffer,
18173        window: &mut Window,
18174        cx: &mut Context<Self>,
18175    ) {
18176        let multibuffer = self.buffer.read(cx);
18177
18178        let Some(buffer) = multibuffer.as_singleton() else {
18179            return;
18180        };
18181
18182        let Some(workspace) = self.workspace() else {
18183            return;
18184        };
18185
18186        let locations = self
18187            .selections
18188            .disjoint_anchors()
18189            .iter()
18190            .map(|range| Location {
18191                buffer: buffer.clone(),
18192                range: range.start.text_anchor..range.end.text_anchor,
18193            })
18194            .collect::<Vec<_>>();
18195
18196        let title = multibuffer.title(cx).to_string();
18197
18198        cx.spawn_in(window, async move |_, cx| {
18199            workspace.update_in(cx, |workspace, window, cx| {
18200                Self::open_locations_in_multibuffer(
18201                    workspace,
18202                    locations,
18203                    format!("Selections for '{title}'"),
18204                    false,
18205                    MultibufferSelectionMode::All,
18206                    window,
18207                    cx,
18208                );
18209            })
18210        })
18211        .detach();
18212    }
18213
18214    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18215    /// last highlight added will be used.
18216    ///
18217    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18218    pub fn highlight_rows<T: 'static>(
18219        &mut self,
18220        range: Range<Anchor>,
18221        color: Hsla,
18222        options: RowHighlightOptions,
18223        cx: &mut Context<Self>,
18224    ) {
18225        let snapshot = self.buffer().read(cx).snapshot(cx);
18226        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18227        let ix = row_highlights.binary_search_by(|highlight| {
18228            Ordering::Equal
18229                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18230                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18231        });
18232
18233        if let Err(mut ix) = ix {
18234            let index = post_inc(&mut self.highlight_order);
18235
18236            // If this range intersects with the preceding highlight, then merge it with
18237            // the preceding highlight. Otherwise insert a new highlight.
18238            let mut merged = false;
18239            if ix > 0 {
18240                let prev_highlight = &mut row_highlights[ix - 1];
18241                if prev_highlight
18242                    .range
18243                    .end
18244                    .cmp(&range.start, &snapshot)
18245                    .is_ge()
18246                {
18247                    ix -= 1;
18248                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18249                        prev_highlight.range.end = range.end;
18250                    }
18251                    merged = true;
18252                    prev_highlight.index = index;
18253                    prev_highlight.color = color;
18254                    prev_highlight.options = options;
18255                }
18256            }
18257
18258            if !merged {
18259                row_highlights.insert(
18260                    ix,
18261                    RowHighlight {
18262                        range: range.clone(),
18263                        index,
18264                        color,
18265                        options,
18266                        type_id: TypeId::of::<T>(),
18267                    },
18268                );
18269            }
18270
18271            // If any of the following highlights intersect with this one, merge them.
18272            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18273                let highlight = &row_highlights[ix];
18274                if next_highlight
18275                    .range
18276                    .start
18277                    .cmp(&highlight.range.end, &snapshot)
18278                    .is_le()
18279                {
18280                    if next_highlight
18281                        .range
18282                        .end
18283                        .cmp(&highlight.range.end, &snapshot)
18284                        .is_gt()
18285                    {
18286                        row_highlights[ix].range.end = next_highlight.range.end;
18287                    }
18288                    row_highlights.remove(ix + 1);
18289                } else {
18290                    break;
18291                }
18292            }
18293        }
18294    }
18295
18296    /// Remove any highlighted row ranges of the given type that intersect the
18297    /// given ranges.
18298    pub fn remove_highlighted_rows<T: 'static>(
18299        &mut self,
18300        ranges_to_remove: Vec<Range<Anchor>>,
18301        cx: &mut Context<Self>,
18302    ) {
18303        let snapshot = self.buffer().read(cx).snapshot(cx);
18304        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18305        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18306        row_highlights.retain(|highlight| {
18307            while let Some(range_to_remove) = ranges_to_remove.peek() {
18308                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18309                    Ordering::Less | Ordering::Equal => {
18310                        ranges_to_remove.next();
18311                    }
18312                    Ordering::Greater => {
18313                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18314                            Ordering::Less | Ordering::Equal => {
18315                                return false;
18316                            }
18317                            Ordering::Greater => break,
18318                        }
18319                    }
18320                }
18321            }
18322
18323            true
18324        })
18325    }
18326
18327    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18328    pub fn clear_row_highlights<T: 'static>(&mut self) {
18329        self.highlighted_rows.remove(&TypeId::of::<T>());
18330    }
18331
18332    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18333    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18334        self.highlighted_rows
18335            .get(&TypeId::of::<T>())
18336            .map_or(&[] as &[_], |vec| vec.as_slice())
18337            .iter()
18338            .map(|highlight| (highlight.range.clone(), highlight.color))
18339    }
18340
18341    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18342    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18343    /// Allows to ignore certain kinds of highlights.
18344    pub fn highlighted_display_rows(
18345        &self,
18346        window: &mut Window,
18347        cx: &mut App,
18348    ) -> BTreeMap<DisplayRow, LineHighlight> {
18349        let snapshot = self.snapshot(window, cx);
18350        let mut used_highlight_orders = HashMap::default();
18351        self.highlighted_rows
18352            .iter()
18353            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18354            .fold(
18355                BTreeMap::<DisplayRow, LineHighlight>::new(),
18356                |mut unique_rows, highlight| {
18357                    let start = highlight.range.start.to_display_point(&snapshot);
18358                    let end = highlight.range.end.to_display_point(&snapshot);
18359                    let start_row = start.row().0;
18360                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18361                        && end.column() == 0
18362                    {
18363                        end.row().0.saturating_sub(1)
18364                    } else {
18365                        end.row().0
18366                    };
18367                    for row in start_row..=end_row {
18368                        let used_index =
18369                            used_highlight_orders.entry(row).or_insert(highlight.index);
18370                        if highlight.index >= *used_index {
18371                            *used_index = highlight.index;
18372                            unique_rows.insert(
18373                                DisplayRow(row),
18374                                LineHighlight {
18375                                    include_gutter: highlight.options.include_gutter,
18376                                    border: None,
18377                                    background: highlight.color.into(),
18378                                    type_id: Some(highlight.type_id),
18379                                },
18380                            );
18381                        }
18382                    }
18383                    unique_rows
18384                },
18385            )
18386    }
18387
18388    pub fn highlighted_display_row_for_autoscroll(
18389        &self,
18390        snapshot: &DisplaySnapshot,
18391    ) -> Option<DisplayRow> {
18392        self.highlighted_rows
18393            .values()
18394            .flat_map(|highlighted_rows| highlighted_rows.iter())
18395            .filter_map(|highlight| {
18396                if highlight.options.autoscroll {
18397                    Some(highlight.range.start.to_display_point(snapshot).row())
18398                } else {
18399                    None
18400                }
18401            })
18402            .min()
18403    }
18404
18405    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18406        self.highlight_background::<SearchWithinRange>(
18407            ranges,
18408            |theme| theme.colors().editor_document_highlight_read_background,
18409            cx,
18410        )
18411    }
18412
18413    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18414        self.breadcrumb_header = Some(new_header);
18415    }
18416
18417    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18418        self.clear_background_highlights::<SearchWithinRange>(cx);
18419    }
18420
18421    pub fn highlight_background<T: 'static>(
18422        &mut self,
18423        ranges: &[Range<Anchor>],
18424        color_fetcher: fn(&Theme) -> Hsla,
18425        cx: &mut Context<Self>,
18426    ) {
18427        let highlights = ranges
18428            .iter()
18429            .map(|range| BackgroundHighlight {
18430                range: range.clone(),
18431                color_fetcher,
18432            })
18433            .collect();
18434        self.background_highlights
18435            .insert(TypeId::of::<T>(), highlights);
18436        self.scrollbar_marker_state.dirty = true;
18437        cx.notify();
18438    }
18439
18440    pub fn highlight_background_ranges<T: 'static>(
18441        &mut self,
18442        background_highlights: Vec<BackgroundHighlight>,
18443        cx: &mut Context<'_, Editor>,
18444    ) {
18445        self.background_highlights
18446            .insert(TypeId::of::<T>(), background_highlights);
18447        self.scrollbar_marker_state.dirty = true;
18448        cx.notify();
18449    }
18450
18451    pub fn clear_background_highlights<T: 'static>(
18452        &mut self,
18453        cx: &mut Context<Self>,
18454    ) -> Option<Vec<BackgroundHighlight>> {
18455        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18456        if !text_highlights.is_empty() {
18457            self.scrollbar_marker_state.dirty = true;
18458            cx.notify();
18459        }
18460        Some(text_highlights)
18461    }
18462
18463    pub fn highlight_gutter<T: 'static>(
18464        &mut self,
18465        ranges: impl Into<Vec<Range<Anchor>>>,
18466        color_fetcher: fn(&App) -> Hsla,
18467        cx: &mut Context<Self>,
18468    ) {
18469        self.gutter_highlights
18470            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18471        cx.notify();
18472    }
18473
18474    pub fn clear_gutter_highlights<T: 'static>(
18475        &mut self,
18476        cx: &mut Context<Self>,
18477    ) -> Option<GutterHighlight> {
18478        cx.notify();
18479        self.gutter_highlights.remove(&TypeId::of::<T>())
18480    }
18481
18482    pub fn insert_gutter_highlight<T: 'static>(
18483        &mut self,
18484        range: Range<Anchor>,
18485        color_fetcher: fn(&App) -> Hsla,
18486        cx: &mut Context<Self>,
18487    ) {
18488        let snapshot = self.buffer().read(cx).snapshot(cx);
18489        let mut highlights = self
18490            .gutter_highlights
18491            .remove(&TypeId::of::<T>())
18492            .map(|(_, highlights)| highlights)
18493            .unwrap_or_default();
18494        let ix = highlights.binary_search_by(|highlight| {
18495            Ordering::Equal
18496                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18497                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18498        });
18499        if let Err(ix) = ix {
18500            highlights.insert(ix, range);
18501        }
18502        self.gutter_highlights
18503            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18504    }
18505
18506    pub fn remove_gutter_highlights<T: 'static>(
18507        &mut self,
18508        ranges_to_remove: Vec<Range<Anchor>>,
18509        cx: &mut Context<Self>,
18510    ) {
18511        let snapshot = self.buffer().read(cx).snapshot(cx);
18512        let Some((color_fetcher, mut gutter_highlights)) =
18513            self.gutter_highlights.remove(&TypeId::of::<T>())
18514        else {
18515            return;
18516        };
18517        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18518        gutter_highlights.retain(|highlight| {
18519            while let Some(range_to_remove) = ranges_to_remove.peek() {
18520                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18521                    Ordering::Less | Ordering::Equal => {
18522                        ranges_to_remove.next();
18523                    }
18524                    Ordering::Greater => {
18525                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18526                            Ordering::Less | Ordering::Equal => {
18527                                return false;
18528                            }
18529                            Ordering::Greater => break,
18530                        }
18531                    }
18532                }
18533            }
18534
18535            true
18536        });
18537        self.gutter_highlights
18538            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18539    }
18540
18541    #[cfg(feature = "test-support")]
18542    pub fn all_text_background_highlights(
18543        &self,
18544        window: &mut Window,
18545        cx: &mut Context<Self>,
18546    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18547        let snapshot = self.snapshot(window, cx);
18548        let buffer = &snapshot.buffer_snapshot;
18549        let start = buffer.anchor_before(0);
18550        let end = buffer.anchor_after(buffer.len());
18551        let theme = cx.theme();
18552        self.background_highlights_in_range(start..end, &snapshot, theme)
18553    }
18554
18555    #[cfg(feature = "test-support")]
18556    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18557        let snapshot = self.buffer().read(cx).snapshot(cx);
18558
18559        let highlights = self
18560            .background_highlights
18561            .get(&TypeId::of::<items::BufferSearchHighlights>());
18562
18563        if let Some(highlights) = highlights {
18564            highlights
18565                .iter()
18566                .map(|highlight| {
18567                    highlight.range.start.to_point(&snapshot)
18568                        ..highlight.range.end.to_point(&snapshot)
18569                })
18570                .collect_vec()
18571        } else {
18572            vec![]
18573        }
18574    }
18575
18576    fn document_highlights_for_position<'a>(
18577        &'a self,
18578        position: Anchor,
18579        buffer: &'a MultiBufferSnapshot,
18580    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18581        let read_highlights = self
18582            .background_highlights
18583            .get(&TypeId::of::<DocumentHighlightRead>());
18584        let write_highlights = self
18585            .background_highlights
18586            .get(&TypeId::of::<DocumentHighlightWrite>());
18587        let left_position = position.bias_left(buffer);
18588        let right_position = position.bias_right(buffer);
18589        read_highlights
18590            .into_iter()
18591            .chain(write_highlights)
18592            .flat_map(move |highlights| {
18593                let start_ix = match highlights.binary_search_by(|probe| {
18594                    let cmp = probe.range.end.cmp(&left_position, buffer);
18595                    if cmp.is_ge() {
18596                        Ordering::Greater
18597                    } else {
18598                        Ordering::Less
18599                    }
18600                }) {
18601                    Ok(i) | Err(i) => i,
18602                };
18603
18604                highlights[start_ix..]
18605                    .iter()
18606                    .take_while(move |highlight| {
18607                        highlight.range.start.cmp(&right_position, buffer).is_le()
18608                    })
18609                    .map(|highlight| &highlight.range)
18610            })
18611    }
18612
18613    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18614        self.background_highlights
18615            .get(&TypeId::of::<T>())
18616            .map_or(false, |highlights| !highlights.is_empty())
18617    }
18618
18619    pub fn background_highlights_in_range(
18620        &self,
18621        search_range: Range<Anchor>,
18622        display_snapshot: &DisplaySnapshot,
18623        theme: &Theme,
18624    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18625        let mut results = Vec::new();
18626        for highlights in self.background_highlights.values() {
18627            let start_ix = match highlights.binary_search_by(|probe| {
18628                let cmp = probe
18629                    .range
18630                    .end
18631                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18632                if cmp.is_gt() {
18633                    Ordering::Greater
18634                } else {
18635                    Ordering::Less
18636                }
18637            }) {
18638                Ok(i) | Err(i) => i,
18639            };
18640            for highlight in &highlights[start_ix..] {
18641                if highlight
18642                    .range
18643                    .start
18644                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18645                    .is_ge()
18646                {
18647                    break;
18648                }
18649
18650                let start = highlight.range.start.to_display_point(display_snapshot);
18651                let end = highlight.range.end.to_display_point(display_snapshot);
18652                let color = (highlight.color_fetcher)(theme);
18653                results.push((start..end, color))
18654            }
18655        }
18656        results
18657    }
18658
18659    pub fn background_highlight_row_ranges<T: 'static>(
18660        &self,
18661        search_range: Range<Anchor>,
18662        display_snapshot: &DisplaySnapshot,
18663        count: usize,
18664    ) -> Vec<RangeInclusive<DisplayPoint>> {
18665        let mut results = Vec::new();
18666        let Some(highlights) = self.background_highlights.get(&TypeId::of::<T>()) else {
18667            return vec![];
18668        };
18669
18670        let start_ix = match highlights.binary_search_by(|probe| {
18671            let cmp = probe
18672                .range
18673                .end
18674                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18675            if cmp.is_gt() {
18676                Ordering::Greater
18677            } else {
18678                Ordering::Less
18679            }
18680        }) {
18681            Ok(i) | Err(i) => i,
18682        };
18683        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18684            if let (Some(start_display), Some(end_display)) = (start, end) {
18685                results.push(
18686                    start_display.to_display_point(display_snapshot)
18687                        ..=end_display.to_display_point(display_snapshot),
18688                );
18689            }
18690        };
18691        let mut start_row: Option<Point> = None;
18692        let mut end_row: Option<Point> = None;
18693        if highlights.len() > count {
18694            return Vec::new();
18695        }
18696        for highlight in &highlights[start_ix..] {
18697            if highlight
18698                .range
18699                .start
18700                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18701                .is_ge()
18702            {
18703                break;
18704            }
18705            let end = highlight
18706                .range
18707                .end
18708                .to_point(&display_snapshot.buffer_snapshot);
18709            if let Some(current_row) = &end_row {
18710                if end.row == current_row.row {
18711                    continue;
18712                }
18713            }
18714            let start = highlight
18715                .range
18716                .start
18717                .to_point(&display_snapshot.buffer_snapshot);
18718            if start_row.is_none() {
18719                assert_eq!(end_row, None);
18720                start_row = Some(start);
18721                end_row = Some(end);
18722                continue;
18723            }
18724            if let Some(current_end) = end_row.as_mut() {
18725                if start.row > current_end.row + 1 {
18726                    push_region(start_row, end_row);
18727                    start_row = Some(start);
18728                    end_row = Some(end);
18729                } else {
18730                    // Merge two hunks.
18731                    *current_end = end;
18732                }
18733            } else {
18734                unreachable!();
18735            }
18736        }
18737        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18738        push_region(start_row, end_row);
18739        results
18740    }
18741
18742    pub fn gutter_highlights_in_range(
18743        &self,
18744        search_range: Range<Anchor>,
18745        display_snapshot: &DisplaySnapshot,
18746        cx: &App,
18747    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18748        let mut results = Vec::new();
18749        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18750            let color = color_fetcher(cx);
18751            let start_ix = match ranges.binary_search_by(|probe| {
18752                let cmp = probe
18753                    .end
18754                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18755                if cmp.is_gt() {
18756                    Ordering::Greater
18757                } else {
18758                    Ordering::Less
18759                }
18760            }) {
18761                Ok(i) | Err(i) => i,
18762            };
18763            for range in &ranges[start_ix..] {
18764                if range
18765                    .start
18766                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18767                    .is_ge()
18768                {
18769                    break;
18770                }
18771
18772                let start = range.start.to_display_point(display_snapshot);
18773                let end = range.end.to_display_point(display_snapshot);
18774                results.push((start..end, color))
18775            }
18776        }
18777        results
18778    }
18779
18780    /// Get the text ranges corresponding to the redaction query
18781    pub fn redacted_ranges(
18782        &self,
18783        search_range: Range<Anchor>,
18784        display_snapshot: &DisplaySnapshot,
18785        cx: &App,
18786    ) -> Vec<Range<DisplayPoint>> {
18787        display_snapshot
18788            .buffer_snapshot
18789            .redacted_ranges(search_range, |file| {
18790                if let Some(file) = file {
18791                    file.is_private()
18792                        && EditorSettings::get(
18793                            Some(SettingsLocation {
18794                                worktree_id: file.worktree_id(cx),
18795                                path: file.path().as_ref(),
18796                            }),
18797                            cx,
18798                        )
18799                        .redact_private_values
18800                } else {
18801                    false
18802                }
18803            })
18804            .map(|range| {
18805                range.start.to_display_point(display_snapshot)
18806                    ..range.end.to_display_point(display_snapshot)
18807            })
18808            .collect()
18809    }
18810
18811    pub fn highlight_text<T: 'static>(
18812        &mut self,
18813        ranges: Vec<(Range<Anchor>, HighlightStyle)>,
18814        cx: &mut Context<Self>,
18815    ) {
18816        self.display_map
18817            .update(cx, |map, _| map.highlight_text(TypeId::of::<T>(), ranges));
18818        cx.notify();
18819    }
18820
18821    pub(crate) fn highlight_inlays<T: 'static>(
18822        &mut self,
18823        highlights: Vec<InlayHighlight>,
18824        style: HighlightStyle,
18825        cx: &mut Context<Self>,
18826    ) {
18827        self.display_map.update(cx, |map, _| {
18828            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18829        });
18830        cx.notify();
18831    }
18832
18833    pub fn text_highlights<'a, T: 'static>(
18834        &'a self,
18835        cx: &'a App,
18836    ) -> Option<&'a [(Range<Anchor>, HighlightStyle)]> {
18837        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18838    }
18839
18840    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18841        let cleared = self
18842            .display_map
18843            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18844        if cleared {
18845            cx.notify();
18846        }
18847    }
18848
18849    pub fn remove_text_highlights<T: 'static>(
18850        &mut self,
18851        cx: &mut Context<Self>,
18852    ) -> Option<Vec<(Range<Anchor>, HighlightStyle)>> {
18853        self.display_map
18854            .update(cx, |map, _| map.remove_text_highlights(TypeId::of::<T>()))
18855    }
18856
18857    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18858        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18859            && self.focus_handle.is_focused(window)
18860    }
18861
18862    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18863        self.show_cursor_when_unfocused = is_enabled;
18864        cx.notify();
18865    }
18866
18867    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18868        cx.notify();
18869    }
18870
18871    fn on_debug_session_event(
18872        &mut self,
18873        _session: Entity<Session>,
18874        event: &SessionEvent,
18875        cx: &mut Context<Self>,
18876    ) {
18877        match event {
18878            SessionEvent::InvalidateInlineValue => {
18879                self.refresh_inline_values(cx);
18880            }
18881            _ => {}
18882        }
18883    }
18884
18885    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18886        let Some(project) = self.project.clone() else {
18887            return;
18888        };
18889
18890        if !self.inline_value_cache.enabled {
18891            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18892            self.splice_inlays(&inlays, Vec::new(), cx);
18893            return;
18894        }
18895
18896        let current_execution_position = self
18897            .highlighted_rows
18898            .get(&TypeId::of::<ActiveDebugLine>())
18899            .and_then(|lines| lines.last().map(|line| line.range.start));
18900
18901        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18902            let inline_values = editor
18903                .update(cx, |editor, cx| {
18904                    let Some(current_execution_position) = current_execution_position else {
18905                        return Some(Task::ready(Ok(Vec::new())));
18906                    };
18907
18908                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18909                        let snapshot = buffer.snapshot(cx);
18910
18911                        let excerpt = snapshot.excerpt_containing(
18912                            current_execution_position..current_execution_position,
18913                        )?;
18914
18915                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18916                    })?;
18917
18918                    let range =
18919                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18920
18921                    project.inline_values(buffer, range, cx)
18922                })
18923                .ok()
18924                .flatten()?
18925                .await
18926                .context("refreshing debugger inlays")
18927                .log_err()?;
18928
18929            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18930
18931            for (buffer_id, inline_value) in inline_values
18932                .into_iter()
18933                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18934            {
18935                buffer_inline_values
18936                    .entry(buffer_id)
18937                    .or_default()
18938                    .push(inline_value);
18939            }
18940
18941            editor
18942                .update(cx, |editor, cx| {
18943                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18944                    let mut new_inlays = Vec::default();
18945
18946                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18947                        let buffer_id = buffer_snapshot.remote_id();
18948                        buffer_inline_values
18949                            .get(&buffer_id)
18950                            .into_iter()
18951                            .flatten()
18952                            .for_each(|hint| {
18953                                let inlay = Inlay::debugger_hint(
18954                                    post_inc(&mut editor.next_inlay_id),
18955                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18956                                    hint.text(),
18957                                );
18958
18959                                new_inlays.push(inlay);
18960                            });
18961                    }
18962
18963                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18964                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18965
18966                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18967                })
18968                .ok()?;
18969            Some(())
18970        });
18971    }
18972
18973    fn on_buffer_event(
18974        &mut self,
18975        multibuffer: &Entity<MultiBuffer>,
18976        event: &multi_buffer::Event,
18977        window: &mut Window,
18978        cx: &mut Context<Self>,
18979    ) {
18980        match event {
18981            multi_buffer::Event::Edited {
18982                singleton_buffer_edited,
18983                edited_buffer,
18984            } => {
18985                self.scrollbar_marker_state.dirty = true;
18986                self.active_indent_guides_state.dirty = true;
18987                self.refresh_active_diagnostics(cx);
18988                self.refresh_code_actions(window, cx);
18989                self.refresh_selected_text_highlights(true, window, cx);
18990                refresh_matching_bracket_highlights(self, window, cx);
18991                if self.has_active_inline_completion() {
18992                    self.update_visible_inline_completion(window, cx);
18993                }
18994                if let Some(project) = self.project.as_ref() {
18995                    if let Some(edited_buffer) = edited_buffer {
18996                        project.update(cx, |project, cx| {
18997                            self.registered_buffers
18998                                .entry(edited_buffer.read(cx).remote_id())
18999                                .or_insert_with(|| {
19000                                    project
19001                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19002                                });
19003                        });
19004                        if edited_buffer.read(cx).file().is_some() {
19005                            self.pull_diagnostics(
19006                                Some(edited_buffer.read(cx).remote_id()),
19007                                window,
19008                                cx,
19009                            );
19010                        }
19011                    }
19012                }
19013                cx.emit(EditorEvent::BufferEdited);
19014                cx.emit(SearchEvent::MatchesInvalidated);
19015                if *singleton_buffer_edited {
19016                    if let Some(buffer) = edited_buffer {
19017                        if buffer.read(cx).file().is_none() {
19018                            cx.emit(EditorEvent::TitleChanged);
19019                        }
19020                    }
19021                    if let Some(project) = &self.project {
19022                        #[allow(clippy::mutable_key_type)]
19023                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19024                            multibuffer
19025                                .all_buffers()
19026                                .into_iter()
19027                                .filter_map(|buffer| {
19028                                    buffer.update(cx, |buffer, cx| {
19029                                        let language = buffer.language()?;
19030                                        let should_discard = project.update(cx, |project, cx| {
19031                                            project.is_local()
19032                                                && !project.has_language_servers_for(buffer, cx)
19033                                        });
19034                                        should_discard.not().then_some(language.clone())
19035                                    })
19036                                })
19037                                .collect::<HashSet<_>>()
19038                        });
19039                        if !languages_affected.is_empty() {
19040                            self.refresh_inlay_hints(
19041                                InlayHintRefreshReason::BufferEdited(languages_affected),
19042                                cx,
19043                            );
19044                        }
19045                    }
19046                }
19047
19048                let Some(project) = &self.project else { return };
19049                let (telemetry, is_via_ssh) = {
19050                    let project = project.read(cx);
19051                    let telemetry = project.client().telemetry().clone();
19052                    let is_via_ssh = project.is_via_ssh();
19053                    (telemetry, is_via_ssh)
19054                };
19055                refresh_linked_ranges(self, window, cx);
19056                telemetry.log_edit_event("editor", is_via_ssh);
19057            }
19058            multi_buffer::Event::ExcerptsAdded {
19059                buffer,
19060                predecessor,
19061                excerpts,
19062            } => {
19063                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19064                let buffer_id = buffer.read(cx).remote_id();
19065                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19066                    if let Some(project) = &self.project {
19067                        update_uncommitted_diff_for_buffer(
19068                            cx.entity(),
19069                            project,
19070                            [buffer.clone()],
19071                            self.buffer.clone(),
19072                            cx,
19073                        )
19074                        .detach();
19075                    }
19076                }
19077                cx.emit(EditorEvent::ExcerptsAdded {
19078                    buffer: buffer.clone(),
19079                    predecessor: *predecessor,
19080                    excerpts: excerpts.clone(),
19081                });
19082                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19083            }
19084            multi_buffer::Event::ExcerptsRemoved {
19085                ids,
19086                removed_buffer_ids,
19087            } => {
19088                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19089                let buffer = self.buffer.read(cx);
19090                self.registered_buffers
19091                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19092                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19093                cx.emit(EditorEvent::ExcerptsRemoved {
19094                    ids: ids.clone(),
19095                    removed_buffer_ids: removed_buffer_ids.clone(),
19096                })
19097            }
19098            multi_buffer::Event::ExcerptsEdited {
19099                excerpt_ids,
19100                buffer_ids,
19101            } => {
19102                self.display_map.update(cx, |map, cx| {
19103                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19104                });
19105                cx.emit(EditorEvent::ExcerptsEdited {
19106                    ids: excerpt_ids.clone(),
19107                })
19108            }
19109            multi_buffer::Event::ExcerptsExpanded { ids } => {
19110                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19111                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19112            }
19113            multi_buffer::Event::Reparsed(buffer_id) => {
19114                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19115                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19116
19117                cx.emit(EditorEvent::Reparsed(*buffer_id));
19118            }
19119            multi_buffer::Event::DiffHunksToggled => {
19120                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19121            }
19122            multi_buffer::Event::LanguageChanged(buffer_id) => {
19123                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19124                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19125                cx.emit(EditorEvent::Reparsed(*buffer_id));
19126                cx.notify();
19127            }
19128            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19129            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19130            multi_buffer::Event::FileHandleChanged
19131            | multi_buffer::Event::Reloaded
19132            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19133            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19134            multi_buffer::Event::DiagnosticsUpdated => {
19135                self.update_diagnostics_state(window, cx);
19136            }
19137            _ => {}
19138        };
19139    }
19140
19141    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19142        self.refresh_active_diagnostics(cx);
19143        self.refresh_inline_diagnostics(true, window, cx);
19144        self.scrollbar_marker_state.dirty = true;
19145        cx.notify();
19146    }
19147
19148    pub fn start_temporary_diff_override(&mut self) {
19149        self.load_diff_task.take();
19150        self.temporary_diff_override = true;
19151    }
19152
19153    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19154        self.temporary_diff_override = false;
19155        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19156        self.buffer.update(cx, |buffer, cx| {
19157            buffer.set_all_diff_hunks_collapsed(cx);
19158        });
19159
19160        if let Some(project) = self.project.clone() {
19161            self.load_diff_task = Some(
19162                update_uncommitted_diff_for_buffer(
19163                    cx.entity(),
19164                    &project,
19165                    self.buffer.read(cx).all_buffers(),
19166                    self.buffer.clone(),
19167                    cx,
19168                )
19169                .shared(),
19170            );
19171        }
19172    }
19173
19174    fn on_display_map_changed(
19175        &mut self,
19176        _: Entity<DisplayMap>,
19177        _: &mut Window,
19178        cx: &mut Context<Self>,
19179    ) {
19180        cx.notify();
19181    }
19182
19183    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19184        let new_severity = if self.diagnostics_enabled() {
19185            EditorSettings::get_global(cx)
19186                .diagnostics_max_severity
19187                .unwrap_or(DiagnosticSeverity::Hint)
19188        } else {
19189            DiagnosticSeverity::Off
19190        };
19191        self.set_max_diagnostics_severity(new_severity, cx);
19192        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19193        self.update_edit_prediction_settings(cx);
19194        self.refresh_inline_completion(true, false, window, cx);
19195        self.refresh_inlay_hints(
19196            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19197                self.selections.newest_anchor().head(),
19198                &self.buffer.read(cx).snapshot(cx),
19199                cx,
19200            )),
19201            cx,
19202        );
19203
19204        let old_cursor_shape = self.cursor_shape;
19205
19206        {
19207            let editor_settings = EditorSettings::get_global(cx);
19208            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19209            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19210            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19211            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19212            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19213        }
19214
19215        if old_cursor_shape != self.cursor_shape {
19216            cx.emit(EditorEvent::CursorShapeChanged);
19217        }
19218
19219        let project_settings = ProjectSettings::get_global(cx);
19220        self.serialize_dirty_buffers =
19221            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19222
19223        if self.mode.is_full() {
19224            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19225            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19226            if self.show_inline_diagnostics != show_inline_diagnostics {
19227                self.show_inline_diagnostics = show_inline_diagnostics;
19228                self.refresh_inline_diagnostics(false, window, cx);
19229            }
19230
19231            if self.git_blame_inline_enabled != inline_blame_enabled {
19232                self.toggle_git_blame_inline_internal(false, window, cx);
19233            }
19234
19235            let minimap_settings = EditorSettings::get_global(cx).minimap;
19236            if self.minimap_visibility != MinimapVisibility::Disabled {
19237                if self.minimap_visibility.settings_visibility()
19238                    != minimap_settings.minimap_enabled()
19239                {
19240                    self.set_minimap_visibility(
19241                        MinimapVisibility::for_mode(self.mode(), cx),
19242                        window,
19243                        cx,
19244                    );
19245                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19246                    minimap_entity.update(cx, |minimap_editor, cx| {
19247                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19248                    })
19249                }
19250            }
19251        }
19252
19253        cx.notify();
19254    }
19255
19256    pub fn set_searchable(&mut self, searchable: bool) {
19257        self.searchable = searchable;
19258    }
19259
19260    pub fn searchable(&self) -> bool {
19261        self.searchable
19262    }
19263
19264    fn open_proposed_changes_editor(
19265        &mut self,
19266        _: &OpenProposedChangesEditor,
19267        window: &mut Window,
19268        cx: &mut Context<Self>,
19269    ) {
19270        let Some(workspace) = self.workspace() else {
19271            cx.propagate();
19272            return;
19273        };
19274
19275        let selections = self.selections.all::<usize>(cx);
19276        let multi_buffer = self.buffer.read(cx);
19277        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19278        let mut new_selections_by_buffer = HashMap::default();
19279        for selection in selections {
19280            for (buffer, range, _) in
19281                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19282            {
19283                let mut range = range.to_point(buffer);
19284                range.start.column = 0;
19285                range.end.column = buffer.line_len(range.end.row);
19286                new_selections_by_buffer
19287                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19288                    .or_insert(Vec::new())
19289                    .push(range)
19290            }
19291        }
19292
19293        let proposed_changes_buffers = new_selections_by_buffer
19294            .into_iter()
19295            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19296            .collect::<Vec<_>>();
19297        let proposed_changes_editor = cx.new(|cx| {
19298            ProposedChangesEditor::new(
19299                "Proposed changes",
19300                proposed_changes_buffers,
19301                self.project.clone(),
19302                window,
19303                cx,
19304            )
19305        });
19306
19307        window.defer(cx, move |window, cx| {
19308            workspace.update(cx, |workspace, cx| {
19309                workspace.active_pane().update(cx, |pane, cx| {
19310                    pane.add_item(
19311                        Box::new(proposed_changes_editor),
19312                        true,
19313                        true,
19314                        None,
19315                        window,
19316                        cx,
19317                    );
19318                });
19319            });
19320        });
19321    }
19322
19323    pub fn open_excerpts_in_split(
19324        &mut self,
19325        _: &OpenExcerptsSplit,
19326        window: &mut Window,
19327        cx: &mut Context<Self>,
19328    ) {
19329        self.open_excerpts_common(None, true, window, cx)
19330    }
19331
19332    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19333        self.open_excerpts_common(None, false, window, cx)
19334    }
19335
19336    fn open_excerpts_common(
19337        &mut self,
19338        jump_data: Option<JumpData>,
19339        split: bool,
19340        window: &mut Window,
19341        cx: &mut Context<Self>,
19342    ) {
19343        let Some(workspace) = self.workspace() else {
19344            cx.propagate();
19345            return;
19346        };
19347
19348        if self.buffer.read(cx).is_singleton() {
19349            cx.propagate();
19350            return;
19351        }
19352
19353        let mut new_selections_by_buffer = HashMap::default();
19354        match &jump_data {
19355            Some(JumpData::MultiBufferPoint {
19356                excerpt_id,
19357                position,
19358                anchor,
19359                line_offset_from_top,
19360            }) => {
19361                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19362                if let Some(buffer) = multi_buffer_snapshot
19363                    .buffer_id_for_excerpt(*excerpt_id)
19364                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19365                {
19366                    let buffer_snapshot = buffer.read(cx).snapshot();
19367                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19368                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19369                    } else {
19370                        buffer_snapshot.clip_point(*position, Bias::Left)
19371                    };
19372                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19373                    new_selections_by_buffer.insert(
19374                        buffer,
19375                        (
19376                            vec![jump_to_offset..jump_to_offset],
19377                            Some(*line_offset_from_top),
19378                        ),
19379                    );
19380                }
19381            }
19382            Some(JumpData::MultiBufferRow {
19383                row,
19384                line_offset_from_top,
19385            }) => {
19386                let point = MultiBufferPoint::new(row.0, 0);
19387                if let Some((buffer, buffer_point, _)) =
19388                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19389                {
19390                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19391                    new_selections_by_buffer
19392                        .entry(buffer)
19393                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19394                        .0
19395                        .push(buffer_offset..buffer_offset)
19396                }
19397            }
19398            None => {
19399                let selections = self.selections.all::<usize>(cx);
19400                let multi_buffer = self.buffer.read(cx);
19401                for selection in selections {
19402                    for (snapshot, range, _, anchor) in multi_buffer
19403                        .snapshot(cx)
19404                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19405                    {
19406                        if let Some(anchor) = anchor {
19407                            // selection is in a deleted hunk
19408                            let Some(buffer_id) = anchor.buffer_id else {
19409                                continue;
19410                            };
19411                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19412                                continue;
19413                            };
19414                            let offset = text::ToOffset::to_offset(
19415                                &anchor.text_anchor,
19416                                &buffer_handle.read(cx).snapshot(),
19417                            );
19418                            let range = offset..offset;
19419                            new_selections_by_buffer
19420                                .entry(buffer_handle)
19421                                .or_insert((Vec::new(), None))
19422                                .0
19423                                .push(range)
19424                        } else {
19425                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19426                            else {
19427                                continue;
19428                            };
19429                            new_selections_by_buffer
19430                                .entry(buffer_handle)
19431                                .or_insert((Vec::new(), None))
19432                                .0
19433                                .push(range)
19434                        }
19435                    }
19436                }
19437            }
19438        }
19439
19440        new_selections_by_buffer
19441            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19442
19443        if new_selections_by_buffer.is_empty() {
19444            return;
19445        }
19446
19447        // We defer the pane interaction because we ourselves are a workspace item
19448        // and activating a new item causes the pane to call a method on us reentrantly,
19449        // which panics if we're on the stack.
19450        window.defer(cx, move |window, cx| {
19451            workspace.update(cx, |workspace, cx| {
19452                let pane = if split {
19453                    workspace.adjacent_pane(window, cx)
19454                } else {
19455                    workspace.active_pane().clone()
19456                };
19457
19458                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19459                    let editor = buffer
19460                        .read(cx)
19461                        .file()
19462                        .is_none()
19463                        .then(|| {
19464                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19465                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19466                            // Instead, we try to activate the existing editor in the pane first.
19467                            let (editor, pane_item_index) =
19468                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19469                                    let editor = item.downcast::<Editor>()?;
19470                                    let singleton_buffer =
19471                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19472                                    if singleton_buffer == buffer {
19473                                        Some((editor, i))
19474                                    } else {
19475                                        None
19476                                    }
19477                                })?;
19478                            pane.update(cx, |pane, cx| {
19479                                pane.activate_item(pane_item_index, true, true, window, cx)
19480                            });
19481                            Some(editor)
19482                        })
19483                        .flatten()
19484                        .unwrap_or_else(|| {
19485                            workspace.open_project_item::<Self>(
19486                                pane.clone(),
19487                                buffer,
19488                                true,
19489                                true,
19490                                window,
19491                                cx,
19492                            )
19493                        });
19494
19495                    editor.update(cx, |editor, cx| {
19496                        let autoscroll = match scroll_offset {
19497                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19498                            None => Autoscroll::newest(),
19499                        };
19500                        let nav_history = editor.nav_history.take();
19501                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19502                            s.select_ranges(ranges);
19503                        });
19504                        editor.nav_history = nav_history;
19505                    });
19506                }
19507            })
19508        });
19509    }
19510
19511    // For now, don't allow opening excerpts in buffers that aren't backed by
19512    // regular project files.
19513    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19514        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19515    }
19516
19517    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19518        let snapshot = self.buffer.read(cx).read(cx);
19519        let ranges = self.text_highlights::<InputComposition>(cx)?;
19520        Some(
19521            ranges
19522                .iter()
19523                .map(move |(range, _)| {
19524                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19525                })
19526                .collect(),
19527        )
19528    }
19529
19530    fn selection_replacement_ranges(
19531        &self,
19532        range: Range<OffsetUtf16>,
19533        cx: &mut App,
19534    ) -> Vec<Range<OffsetUtf16>> {
19535        let selections = self.selections.all::<OffsetUtf16>(cx);
19536        let newest_selection = selections
19537            .iter()
19538            .max_by_key(|selection| selection.id)
19539            .unwrap();
19540        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19541        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19542        let snapshot = self.buffer.read(cx).read(cx);
19543        selections
19544            .into_iter()
19545            .map(|mut selection| {
19546                selection.start.0 =
19547                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19548                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19549                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19550                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19551            })
19552            .collect()
19553    }
19554
19555    fn report_editor_event(
19556        &self,
19557        event_type: &'static str,
19558        file_extension: Option<String>,
19559        cx: &App,
19560    ) {
19561        if cfg!(any(test, feature = "test-support")) {
19562            return;
19563        }
19564
19565        let Some(project) = &self.project else { return };
19566
19567        // If None, we are in a file without an extension
19568        let file = self
19569            .buffer
19570            .read(cx)
19571            .as_singleton()
19572            .and_then(|b| b.read(cx).file());
19573        let file_extension = file_extension.or(file
19574            .as_ref()
19575            .and_then(|file| Path::new(file.file_name(cx)).extension())
19576            .and_then(|e| e.to_str())
19577            .map(|a| a.to_string()));
19578
19579        let vim_mode = vim_enabled(cx);
19580
19581        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19582        let copilot_enabled = edit_predictions_provider
19583            == language::language_settings::EditPredictionProvider::Copilot;
19584        let copilot_enabled_for_language = self
19585            .buffer
19586            .read(cx)
19587            .language_settings(cx)
19588            .show_edit_predictions;
19589
19590        let project = project.read(cx);
19591        telemetry::event!(
19592            event_type,
19593            file_extension,
19594            vim_mode,
19595            copilot_enabled,
19596            copilot_enabled_for_language,
19597            edit_predictions_provider,
19598            is_via_ssh = project.is_via_ssh(),
19599        );
19600    }
19601
19602    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19603    /// with each line being an array of {text, highlight} objects.
19604    fn copy_highlight_json(
19605        &mut self,
19606        _: &CopyHighlightJson,
19607        window: &mut Window,
19608        cx: &mut Context<Self>,
19609    ) {
19610        #[derive(Serialize)]
19611        struct Chunk<'a> {
19612            text: String,
19613            highlight: Option<&'a str>,
19614        }
19615
19616        let snapshot = self.buffer.read(cx).snapshot(cx);
19617        let range = self
19618            .selected_text_range(false, window, cx)
19619            .and_then(|selection| {
19620                if selection.range.is_empty() {
19621                    None
19622                } else {
19623                    Some(selection.range)
19624                }
19625            })
19626            .unwrap_or_else(|| 0..snapshot.len());
19627
19628        let chunks = snapshot.chunks(range, true);
19629        let mut lines = Vec::new();
19630        let mut line: VecDeque<Chunk> = VecDeque::new();
19631
19632        let Some(style) = self.style.as_ref() else {
19633            return;
19634        };
19635
19636        for chunk in chunks {
19637            let highlight = chunk
19638                .syntax_highlight_id
19639                .and_then(|id| id.name(&style.syntax));
19640            let mut chunk_lines = chunk.text.split('\n').peekable();
19641            while let Some(text) = chunk_lines.next() {
19642                let mut merged_with_last_token = false;
19643                if let Some(last_token) = line.back_mut() {
19644                    if last_token.highlight == highlight {
19645                        last_token.text.push_str(text);
19646                        merged_with_last_token = true;
19647                    }
19648                }
19649
19650                if !merged_with_last_token {
19651                    line.push_back(Chunk {
19652                        text: text.into(),
19653                        highlight,
19654                    });
19655                }
19656
19657                if chunk_lines.peek().is_some() {
19658                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19659                        line.pop_front();
19660                    }
19661                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19662                        line.pop_back();
19663                    }
19664
19665                    lines.push(mem::take(&mut line));
19666                }
19667            }
19668        }
19669
19670        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19671            return;
19672        };
19673        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19674    }
19675
19676    pub fn open_context_menu(
19677        &mut self,
19678        _: &OpenContextMenu,
19679        window: &mut Window,
19680        cx: &mut Context<Self>,
19681    ) {
19682        self.request_autoscroll(Autoscroll::newest(), cx);
19683        let position = self.selections.newest_display(cx).start;
19684        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19685    }
19686
19687    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19688        &self.inlay_hint_cache
19689    }
19690
19691    pub fn replay_insert_event(
19692        &mut self,
19693        text: &str,
19694        relative_utf16_range: Option<Range<isize>>,
19695        window: &mut Window,
19696        cx: &mut Context<Self>,
19697    ) {
19698        if !self.input_enabled {
19699            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19700            return;
19701        }
19702        if let Some(relative_utf16_range) = relative_utf16_range {
19703            let selections = self.selections.all::<OffsetUtf16>(cx);
19704            self.change_selections(None, window, cx, |s| {
19705                let new_ranges = selections.into_iter().map(|range| {
19706                    let start = OffsetUtf16(
19707                        range
19708                            .head()
19709                            .0
19710                            .saturating_add_signed(relative_utf16_range.start),
19711                    );
19712                    let end = OffsetUtf16(
19713                        range
19714                            .head()
19715                            .0
19716                            .saturating_add_signed(relative_utf16_range.end),
19717                    );
19718                    start..end
19719                });
19720                s.select_ranges(new_ranges);
19721            });
19722        }
19723
19724        self.handle_input(text, window, cx);
19725    }
19726
19727    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19728        let Some(provider) = self.semantics_provider.as_ref() else {
19729            return false;
19730        };
19731
19732        let mut supports = false;
19733        self.buffer().update(cx, |this, cx| {
19734            this.for_each_buffer(|buffer| {
19735                supports |= provider.supports_inlay_hints(buffer, cx);
19736            });
19737        });
19738
19739        supports
19740    }
19741
19742    pub fn is_focused(&self, window: &Window) -> bool {
19743        self.focus_handle.is_focused(window)
19744    }
19745
19746    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19747        cx.emit(EditorEvent::Focused);
19748
19749        if let Some(descendant) = self
19750            .last_focused_descendant
19751            .take()
19752            .and_then(|descendant| descendant.upgrade())
19753        {
19754            window.focus(&descendant);
19755        } else {
19756            if let Some(blame) = self.blame.as_ref() {
19757                blame.update(cx, GitBlame::focus)
19758            }
19759
19760            self.blink_manager.update(cx, BlinkManager::enable);
19761            self.show_cursor_names(window, cx);
19762            self.buffer.update(cx, |buffer, cx| {
19763                buffer.finalize_last_transaction(cx);
19764                if self.leader_id.is_none() {
19765                    buffer.set_active_selections(
19766                        &self.selections.disjoint_anchors(),
19767                        self.selections.line_mode,
19768                        self.cursor_shape,
19769                        cx,
19770                    );
19771                }
19772            });
19773        }
19774    }
19775
19776    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19777        cx.emit(EditorEvent::FocusedIn)
19778    }
19779
19780    fn handle_focus_out(
19781        &mut self,
19782        event: FocusOutEvent,
19783        _window: &mut Window,
19784        cx: &mut Context<Self>,
19785    ) {
19786        if event.blurred != self.focus_handle {
19787            self.last_focused_descendant = Some(event.blurred);
19788        }
19789        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19790    }
19791
19792    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19793        self.blink_manager.update(cx, BlinkManager::disable);
19794        self.buffer
19795            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19796
19797        if let Some(blame) = self.blame.as_ref() {
19798            blame.update(cx, GitBlame::blur)
19799        }
19800        if !self.hover_state.focused(window, cx) {
19801            hide_hover(self, cx);
19802        }
19803        if !self
19804            .context_menu
19805            .borrow()
19806            .as_ref()
19807            .is_some_and(|context_menu| context_menu.focused(window, cx))
19808        {
19809            self.hide_context_menu(window, cx);
19810        }
19811        self.discard_inline_completion(false, cx);
19812        cx.emit(EditorEvent::Blurred);
19813        cx.notify();
19814    }
19815
19816    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19817        let mut pending: String = window
19818            .pending_input_keystrokes()
19819            .into_iter()
19820            .flatten()
19821            .filter_map(|keystroke| {
19822                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19823                    keystroke.key_char.clone()
19824                } else {
19825                    None
19826                }
19827            })
19828            .collect();
19829
19830        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19831            pending = "".to_string();
19832        }
19833
19834        let existing_pending = self.text_highlights::<PendingInput>(cx).map(|ranges| {
19835            ranges
19836                .iter()
19837                .map(|(range, _)| range.clone())
19838                .collect::<Vec<_>>()
19839        });
19840        if existing_pending.is_none() && pending.is_empty() {
19841            return;
19842        }
19843        let transaction =
19844            self.transact(window, cx, |this, window, cx| {
19845                let selections = this.selections.all::<usize>(cx);
19846                let edits = selections
19847                    .iter()
19848                    .map(|selection| (selection.end..selection.end, pending.clone()));
19849                this.edit(edits, cx);
19850                this.change_selections(None, window, cx, |s| {
19851                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19852                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19853                    }));
19854                });
19855                if let Some(existing_ranges) = existing_pending {
19856                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19857                    this.edit(edits, cx);
19858                }
19859            });
19860
19861        let snapshot = self.snapshot(window, cx);
19862        let ranges = self
19863            .selections
19864            .all::<usize>(cx)
19865            .into_iter()
19866            .map(|selection| {
19867                (
19868                    snapshot.buffer_snapshot.anchor_after(selection.end)
19869                        ..snapshot
19870                            .buffer_snapshot
19871                            .anchor_before(selection.end + pending.len()),
19872                    HighlightStyle {
19873                        underline: Some(UnderlineStyle {
19874                            thickness: px(1.),
19875                            color: None,
19876                            wavy: false,
19877                        }),
19878                        ..Default::default()
19879                    },
19880                )
19881            })
19882            .collect();
19883
19884        if pending.is_empty() {
19885            self.clear_highlights::<PendingInput>(cx);
19886        } else {
19887            self.highlight_text::<PendingInput>(ranges, cx);
19888        }
19889
19890        self.ime_transaction = self.ime_transaction.or(transaction);
19891        if let Some(transaction) = self.ime_transaction {
19892            self.buffer.update(cx, |buffer, cx| {
19893                buffer.group_until_transaction(transaction, cx);
19894            });
19895        }
19896
19897        if self.text_highlights::<PendingInput>(cx).is_none() {
19898            self.ime_transaction.take();
19899        }
19900    }
19901
19902    pub fn register_action_renderer(
19903        &mut self,
19904        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
19905    ) -> Subscription {
19906        let id = self.next_editor_action_id.post_inc();
19907        self.editor_actions
19908            .borrow_mut()
19909            .insert(id, Box::new(listener));
19910
19911        let editor_actions = self.editor_actions.clone();
19912        Subscription::new(move || {
19913            editor_actions.borrow_mut().remove(&id);
19914        })
19915    }
19916
19917    pub fn register_action<A: Action>(
19918        &mut self,
19919        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19920    ) -> Subscription {
19921        let id = self.next_editor_action_id.post_inc();
19922        let listener = Arc::new(listener);
19923        self.editor_actions.borrow_mut().insert(
19924            id,
19925            Box::new(move |_, window, _| {
19926                let listener = listener.clone();
19927                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19928                    let action = action.downcast_ref().unwrap();
19929                    if phase == DispatchPhase::Bubble {
19930                        listener(action, window, cx)
19931                    }
19932                })
19933            }),
19934        );
19935
19936        let editor_actions = self.editor_actions.clone();
19937        Subscription::new(move || {
19938            editor_actions.borrow_mut().remove(&id);
19939        })
19940    }
19941
19942    pub fn file_header_size(&self) -> u32 {
19943        FILE_HEADER_HEIGHT
19944    }
19945
19946    pub fn restore(
19947        &mut self,
19948        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19949        window: &mut Window,
19950        cx: &mut Context<Self>,
19951    ) {
19952        let workspace = self.workspace();
19953        let project = self.project.as_ref();
19954        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19955            let mut tasks = Vec::new();
19956            for (buffer_id, changes) in revert_changes {
19957                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19958                    buffer.update(cx, |buffer, cx| {
19959                        buffer.edit(
19960                            changes
19961                                .into_iter()
19962                                .map(|(range, text)| (range, text.to_string())),
19963                            None,
19964                            cx,
19965                        );
19966                    });
19967
19968                    if let Some(project) =
19969                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19970                    {
19971                        project.update(cx, |project, cx| {
19972                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19973                        })
19974                    }
19975                }
19976            }
19977            tasks
19978        });
19979        cx.spawn_in(window, async move |_, cx| {
19980            for (buffer, task) in save_tasks {
19981                let result = task.await;
19982                if result.is_err() {
19983                    let Some(path) = buffer
19984                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19985                        .ok()
19986                    else {
19987                        continue;
19988                    };
19989                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19990                        let Some(task) = cx
19991                            .update_window_entity(&workspace, |workspace, window, cx| {
19992                                workspace
19993                                    .open_path_preview(path, None, false, false, false, window, cx)
19994                            })
19995                            .ok()
19996                        else {
19997                            continue;
19998                        };
19999                        task.await.log_err();
20000                    }
20001                }
20002            }
20003        })
20004        .detach();
20005        self.change_selections(None, window, cx, |selections| selections.refresh());
20006    }
20007
20008    pub fn to_pixel_point(
20009        &self,
20010        source: multi_buffer::Anchor,
20011        editor_snapshot: &EditorSnapshot,
20012        window: &mut Window,
20013    ) -> Option<gpui::Point<Pixels>> {
20014        let source_point = source.to_display_point(editor_snapshot);
20015        self.display_to_pixel_point(source_point, editor_snapshot, window)
20016    }
20017
20018    pub fn display_to_pixel_point(
20019        &self,
20020        source: DisplayPoint,
20021        editor_snapshot: &EditorSnapshot,
20022        window: &mut Window,
20023    ) -> Option<gpui::Point<Pixels>> {
20024        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20025        let text_layout_details = self.text_layout_details(window);
20026        let scroll_top = text_layout_details
20027            .scroll_anchor
20028            .scroll_position(editor_snapshot)
20029            .y;
20030
20031        if source.row().as_f32() < scroll_top.floor() {
20032            return None;
20033        }
20034        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20035        let source_y = line_height * (source.row().as_f32() - scroll_top);
20036        Some(gpui::Point::new(source_x, source_y))
20037    }
20038
20039    pub fn has_visible_completions_menu(&self) -> bool {
20040        !self.edit_prediction_preview_is_active()
20041            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20042                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20043            })
20044    }
20045
20046    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20047        if self.mode.is_minimap() {
20048            return;
20049        }
20050        self.addons
20051            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20052    }
20053
20054    pub fn unregister_addon<T: Addon>(&mut self) {
20055        self.addons.remove(&std::any::TypeId::of::<T>());
20056    }
20057
20058    pub fn addon<T: Addon>(&self) -> Option<&T> {
20059        let type_id = std::any::TypeId::of::<T>();
20060        self.addons
20061            .get(&type_id)
20062            .and_then(|item| item.to_any().downcast_ref::<T>())
20063    }
20064
20065    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20066        let type_id = std::any::TypeId::of::<T>();
20067        self.addons
20068            .get_mut(&type_id)
20069            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20070    }
20071
20072    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20073        let text_layout_details = self.text_layout_details(window);
20074        let style = &text_layout_details.editor_style;
20075        let font_id = window.text_system().resolve_font(&style.text.font());
20076        let font_size = style.text.font_size.to_pixels(window.rem_size());
20077        let line_height = style.text.line_height_in_pixels(window.rem_size());
20078        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20079
20080        gpui::Size::new(em_width, line_height)
20081    }
20082
20083    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20084        self.load_diff_task.clone()
20085    }
20086
20087    fn read_metadata_from_db(
20088        &mut self,
20089        item_id: u64,
20090        workspace_id: WorkspaceId,
20091        window: &mut Window,
20092        cx: &mut Context<Editor>,
20093    ) {
20094        if self.is_singleton(cx)
20095            && !self.mode.is_minimap()
20096            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20097        {
20098            let buffer_snapshot = OnceCell::new();
20099
20100            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20101                if !folds.is_empty() {
20102                    let snapshot =
20103                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20104                    self.fold_ranges(
20105                        folds
20106                            .into_iter()
20107                            .map(|(start, end)| {
20108                                snapshot.clip_offset(start, Bias::Left)
20109                                    ..snapshot.clip_offset(end, Bias::Right)
20110                            })
20111                            .collect(),
20112                        false,
20113                        window,
20114                        cx,
20115                    );
20116                }
20117            }
20118
20119            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20120                if !selections.is_empty() {
20121                    let snapshot =
20122                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20123                    // skip adding the initial selection to selection history
20124                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20125                    self.change_selections(None, window, cx, |s| {
20126                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20127                            snapshot.clip_offset(start, Bias::Left)
20128                                ..snapshot.clip_offset(end, Bias::Right)
20129                        }));
20130                    });
20131                    self.selection_history.mode = SelectionHistoryMode::Normal;
20132                }
20133            };
20134        }
20135
20136        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20137    }
20138}
20139
20140fn vim_enabled(cx: &App) -> bool {
20141    cx.global::<SettingsStore>()
20142        .raw_user_settings()
20143        .get("vim_mode")
20144        == Some(&serde_json::Value::Bool(true))
20145}
20146
20147fn process_completion_for_edit(
20148    completion: &Completion,
20149    intent: CompletionIntent,
20150    buffer: &Entity<Buffer>,
20151    cursor_position: &text::Anchor,
20152    cx: &mut Context<Editor>,
20153) -> CompletionEdit {
20154    let buffer = buffer.read(cx);
20155    let buffer_snapshot = buffer.snapshot();
20156    let (snippet, new_text) = if completion.is_snippet() {
20157        // Workaround for typescript language server issues so that methods don't expand within
20158        // strings and functions with type expressions. The previous point is used because the query
20159        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20160        let mut snippet_source = completion.new_text.clone();
20161        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20162        previous_point.column = previous_point.column.saturating_sub(1);
20163        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20164            if scope.prefers_label_for_snippet_in_completion() {
20165                if let Some(label) = completion.label() {
20166                    if matches!(
20167                        completion.kind(),
20168                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20169                    ) {
20170                        snippet_source = label;
20171                    }
20172                }
20173            }
20174        }
20175        match Snippet::parse(&snippet_source).log_err() {
20176            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20177            None => (None, completion.new_text.clone()),
20178        }
20179    } else {
20180        (None, completion.new_text.clone())
20181    };
20182
20183    let mut range_to_replace = {
20184        let replace_range = &completion.replace_range;
20185        if let CompletionSource::Lsp {
20186            insert_range: Some(insert_range),
20187            ..
20188        } = &completion.source
20189        {
20190            debug_assert_eq!(
20191                insert_range.start, replace_range.start,
20192                "insert_range and replace_range should start at the same position"
20193            );
20194            debug_assert!(
20195                insert_range
20196                    .start
20197                    .cmp(&cursor_position, &buffer_snapshot)
20198                    .is_le(),
20199                "insert_range should start before or at cursor position"
20200            );
20201            debug_assert!(
20202                replace_range
20203                    .start
20204                    .cmp(&cursor_position, &buffer_snapshot)
20205                    .is_le(),
20206                "replace_range should start before or at cursor position"
20207            );
20208            debug_assert!(
20209                insert_range
20210                    .end
20211                    .cmp(&cursor_position, &buffer_snapshot)
20212                    .is_le(),
20213                "insert_range should end before or at cursor position"
20214            );
20215
20216            let should_replace = match intent {
20217                CompletionIntent::CompleteWithInsert => false,
20218                CompletionIntent::CompleteWithReplace => true,
20219                CompletionIntent::Complete | CompletionIntent::Compose => {
20220                    let insert_mode =
20221                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20222                            .completions
20223                            .lsp_insert_mode;
20224                    match insert_mode {
20225                        LspInsertMode::Insert => false,
20226                        LspInsertMode::Replace => true,
20227                        LspInsertMode::ReplaceSubsequence => {
20228                            let mut text_to_replace = buffer.chars_for_range(
20229                                buffer.anchor_before(replace_range.start)
20230                                    ..buffer.anchor_after(replace_range.end),
20231                            );
20232                            let mut current_needle = text_to_replace.next();
20233                            for haystack_ch in completion.label.text.chars() {
20234                                if let Some(needle_ch) = current_needle {
20235                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20236                                        current_needle = text_to_replace.next();
20237                                    }
20238                                }
20239                            }
20240                            current_needle.is_none()
20241                        }
20242                        LspInsertMode::ReplaceSuffix => {
20243                            if replace_range
20244                                .end
20245                                .cmp(&cursor_position, &buffer_snapshot)
20246                                .is_gt()
20247                            {
20248                                let range_after_cursor = *cursor_position..replace_range.end;
20249                                let text_after_cursor = buffer
20250                                    .text_for_range(
20251                                        buffer.anchor_before(range_after_cursor.start)
20252                                            ..buffer.anchor_after(range_after_cursor.end),
20253                                    )
20254                                    .collect::<String>()
20255                                    .to_ascii_lowercase();
20256                                completion
20257                                    .label
20258                                    .text
20259                                    .to_ascii_lowercase()
20260                                    .ends_with(&text_after_cursor)
20261                            } else {
20262                                true
20263                            }
20264                        }
20265                    }
20266                }
20267            };
20268
20269            if should_replace {
20270                replace_range.clone()
20271            } else {
20272                insert_range.clone()
20273            }
20274        } else {
20275            replace_range.clone()
20276        }
20277    };
20278
20279    if range_to_replace
20280        .end
20281        .cmp(&cursor_position, &buffer_snapshot)
20282        .is_lt()
20283    {
20284        range_to_replace.end = *cursor_position;
20285    }
20286
20287    CompletionEdit {
20288        new_text,
20289        replace_range: range_to_replace.to_offset(&buffer),
20290        snippet,
20291    }
20292}
20293
20294struct CompletionEdit {
20295    new_text: String,
20296    replace_range: Range<usize>,
20297    snippet: Option<Snippet>,
20298}
20299
20300fn insert_extra_newline_brackets(
20301    buffer: &MultiBufferSnapshot,
20302    range: Range<usize>,
20303    language: &language::LanguageScope,
20304) -> bool {
20305    let leading_whitespace_len = buffer
20306        .reversed_chars_at(range.start)
20307        .take_while(|c| c.is_whitespace() && *c != '\n')
20308        .map(|c| c.len_utf8())
20309        .sum::<usize>();
20310    let trailing_whitespace_len = buffer
20311        .chars_at(range.end)
20312        .take_while(|c| c.is_whitespace() && *c != '\n')
20313        .map(|c| c.len_utf8())
20314        .sum::<usize>();
20315    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20316
20317    language.brackets().any(|(pair, enabled)| {
20318        let pair_start = pair.start.trim_end();
20319        let pair_end = pair.end.trim_start();
20320
20321        enabled
20322            && pair.newline
20323            && buffer.contains_str_at(range.end, pair_end)
20324            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20325    })
20326}
20327
20328fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20329    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20330        [(buffer, range, _)] => (*buffer, range.clone()),
20331        _ => return false,
20332    };
20333    let pair = {
20334        let mut result: Option<BracketMatch> = None;
20335
20336        for pair in buffer
20337            .all_bracket_ranges(range.clone())
20338            .filter(move |pair| {
20339                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20340            })
20341        {
20342            let len = pair.close_range.end - pair.open_range.start;
20343
20344            if let Some(existing) = &result {
20345                let existing_len = existing.close_range.end - existing.open_range.start;
20346                if len > existing_len {
20347                    continue;
20348                }
20349            }
20350
20351            result = Some(pair);
20352        }
20353
20354        result
20355    };
20356    let Some(pair) = pair else {
20357        return false;
20358    };
20359    pair.newline_only
20360        && buffer
20361            .chars_for_range(pair.open_range.end..range.start)
20362            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20363            .all(|c| c.is_whitespace() && c != '\n')
20364}
20365
20366fn update_uncommitted_diff_for_buffer(
20367    editor: Entity<Editor>,
20368    project: &Entity<Project>,
20369    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20370    buffer: Entity<MultiBuffer>,
20371    cx: &mut App,
20372) -> Task<()> {
20373    let mut tasks = Vec::new();
20374    project.update(cx, |project, cx| {
20375        for buffer in buffers {
20376            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20377                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20378            }
20379        }
20380    });
20381    cx.spawn(async move |cx| {
20382        let diffs = future::join_all(tasks).await;
20383        if editor
20384            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20385            .unwrap_or(false)
20386        {
20387            return;
20388        }
20389
20390        buffer
20391            .update(cx, |buffer, cx| {
20392                for diff in diffs.into_iter().flatten() {
20393                    buffer.add_diff(diff, cx);
20394                }
20395            })
20396            .ok();
20397    })
20398}
20399
20400fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20401    let tab_size = tab_size.get() as usize;
20402    let mut width = offset;
20403
20404    for ch in text.chars() {
20405        width += if ch == '\t' {
20406            tab_size - (width % tab_size)
20407        } else {
20408            1
20409        };
20410    }
20411
20412    width - offset
20413}
20414
20415#[cfg(test)]
20416mod tests {
20417    use super::*;
20418
20419    #[test]
20420    fn test_string_size_with_expanded_tabs() {
20421        let nz = |val| NonZeroU32::new(val).unwrap();
20422        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20423        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20424        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20425        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20426        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20427        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20428        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20429        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20430    }
20431}
20432
20433/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20434struct WordBreakingTokenizer<'a> {
20435    input: &'a str,
20436}
20437
20438impl<'a> WordBreakingTokenizer<'a> {
20439    fn new(input: &'a str) -> Self {
20440        Self { input }
20441    }
20442}
20443
20444fn is_char_ideographic(ch: char) -> bool {
20445    use unicode_script::Script::*;
20446    use unicode_script::UnicodeScript;
20447    matches!(ch.script(), Han | Tangut | Yi)
20448}
20449
20450fn is_grapheme_ideographic(text: &str) -> bool {
20451    text.chars().any(is_char_ideographic)
20452}
20453
20454fn is_grapheme_whitespace(text: &str) -> bool {
20455    text.chars().any(|x| x.is_whitespace())
20456}
20457
20458fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20459    text.chars().next().map_or(false, |ch| {
20460        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20461    })
20462}
20463
20464#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20465enum WordBreakToken<'a> {
20466    Word { token: &'a str, grapheme_len: usize },
20467    InlineWhitespace { token: &'a str, grapheme_len: usize },
20468    Newline,
20469}
20470
20471impl<'a> Iterator for WordBreakingTokenizer<'a> {
20472    /// Yields a span, the count of graphemes in the token, and whether it was
20473    /// whitespace. Note that it also breaks at word boundaries.
20474    type Item = WordBreakToken<'a>;
20475
20476    fn next(&mut self) -> Option<Self::Item> {
20477        use unicode_segmentation::UnicodeSegmentation;
20478        if self.input.is_empty() {
20479            return None;
20480        }
20481
20482        let mut iter = self.input.graphemes(true).peekable();
20483        let mut offset = 0;
20484        let mut grapheme_len = 0;
20485        if let Some(first_grapheme) = iter.next() {
20486            let is_newline = first_grapheme == "\n";
20487            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20488            offset += first_grapheme.len();
20489            grapheme_len += 1;
20490            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20491                if let Some(grapheme) = iter.peek().copied() {
20492                    if should_stay_with_preceding_ideograph(grapheme) {
20493                        offset += grapheme.len();
20494                        grapheme_len += 1;
20495                    }
20496                }
20497            } else {
20498                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20499                let mut next_word_bound = words.peek().copied();
20500                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20501                    next_word_bound = words.next();
20502                }
20503                while let Some(grapheme) = iter.peek().copied() {
20504                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20505                        break;
20506                    };
20507                    if is_grapheme_whitespace(grapheme) != is_whitespace
20508                        || (grapheme == "\n") != is_newline
20509                    {
20510                        break;
20511                    };
20512                    offset += grapheme.len();
20513                    grapheme_len += 1;
20514                    iter.next();
20515                }
20516            }
20517            let token = &self.input[..offset];
20518            self.input = &self.input[offset..];
20519            if token == "\n" {
20520                Some(WordBreakToken::Newline)
20521            } else if is_whitespace {
20522                Some(WordBreakToken::InlineWhitespace {
20523                    token,
20524                    grapheme_len,
20525                })
20526            } else {
20527                Some(WordBreakToken::Word {
20528                    token,
20529                    grapheme_len,
20530                })
20531            }
20532        } else {
20533            None
20534        }
20535    }
20536}
20537
20538#[test]
20539fn test_word_breaking_tokenizer() {
20540    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20541        ("", &[]),
20542        ("  ", &[whitespace("  ", 2)]),
20543        ("Ʒ", &[word("Ʒ", 1)]),
20544        ("Ǽ", &[word("Ǽ", 1)]),
20545        ("", &[word("", 1)]),
20546        ("⋑⋑", &[word("⋑⋑", 2)]),
20547        (
20548            "原理,进而",
20549            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20550        ),
20551        (
20552            "hello world",
20553            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20554        ),
20555        (
20556            "hello, world",
20557            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20558        ),
20559        (
20560            "  hello world",
20561            &[
20562                whitespace("  ", 2),
20563                word("hello", 5),
20564                whitespace(" ", 1),
20565                word("world", 5),
20566            ],
20567        ),
20568        (
20569            "这是什么 \n 钢笔",
20570            &[
20571                word("", 1),
20572                word("", 1),
20573                word("", 1),
20574                word("", 1),
20575                whitespace(" ", 1),
20576                newline(),
20577                whitespace(" ", 1),
20578                word("", 1),
20579                word("", 1),
20580            ],
20581        ),
20582        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20583    ];
20584
20585    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20586        WordBreakToken::Word {
20587            token,
20588            grapheme_len,
20589        }
20590    }
20591
20592    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20593        WordBreakToken::InlineWhitespace {
20594            token,
20595            grapheme_len,
20596        }
20597    }
20598
20599    fn newline() -> WordBreakToken<'static> {
20600        WordBreakToken::Newline
20601    }
20602
20603    for (input, result) in tests {
20604        assert_eq!(
20605            WordBreakingTokenizer::new(input)
20606                .collect::<Vec<_>>()
20607                .as_slice(),
20608            *result,
20609        );
20610    }
20611}
20612
20613fn wrap_with_prefix(
20614    line_prefix: String,
20615    unwrapped_text: String,
20616    wrap_column: usize,
20617    tab_size: NonZeroU32,
20618    preserve_existing_whitespace: bool,
20619) -> String {
20620    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20621    let mut wrapped_text = String::new();
20622    let mut current_line = line_prefix.clone();
20623
20624    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20625    let mut current_line_len = line_prefix_len;
20626    let mut in_whitespace = false;
20627    for token in tokenizer {
20628        let have_preceding_whitespace = in_whitespace;
20629        match token {
20630            WordBreakToken::Word {
20631                token,
20632                grapheme_len,
20633            } => {
20634                in_whitespace = false;
20635                if current_line_len + grapheme_len > wrap_column
20636                    && current_line_len != line_prefix_len
20637                {
20638                    wrapped_text.push_str(current_line.trim_end());
20639                    wrapped_text.push('\n');
20640                    current_line.truncate(line_prefix.len());
20641                    current_line_len = line_prefix_len;
20642                }
20643                current_line.push_str(token);
20644                current_line_len += grapheme_len;
20645            }
20646            WordBreakToken::InlineWhitespace {
20647                mut token,
20648                mut grapheme_len,
20649            } => {
20650                in_whitespace = true;
20651                if have_preceding_whitespace && !preserve_existing_whitespace {
20652                    continue;
20653                }
20654                if !preserve_existing_whitespace {
20655                    token = " ";
20656                    grapheme_len = 1;
20657                }
20658                if current_line_len + grapheme_len > wrap_column {
20659                    wrapped_text.push_str(current_line.trim_end());
20660                    wrapped_text.push('\n');
20661                    current_line.truncate(line_prefix.len());
20662                    current_line_len = line_prefix_len;
20663                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20664                    current_line.push_str(token);
20665                    current_line_len += grapheme_len;
20666                }
20667            }
20668            WordBreakToken::Newline => {
20669                in_whitespace = true;
20670                if preserve_existing_whitespace {
20671                    wrapped_text.push_str(current_line.trim_end());
20672                    wrapped_text.push('\n');
20673                    current_line.truncate(line_prefix.len());
20674                    current_line_len = line_prefix_len;
20675                } else if have_preceding_whitespace {
20676                    continue;
20677                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20678                {
20679                    wrapped_text.push_str(current_line.trim_end());
20680                    wrapped_text.push('\n');
20681                    current_line.truncate(line_prefix.len());
20682                    current_line_len = line_prefix_len;
20683                } else if current_line_len != line_prefix_len {
20684                    current_line.push(' ');
20685                    current_line_len += 1;
20686                }
20687            }
20688        }
20689    }
20690
20691    if !current_line.is_empty() {
20692        wrapped_text.push_str(&current_line);
20693    }
20694    wrapped_text
20695}
20696
20697#[test]
20698fn test_wrap_with_prefix() {
20699    assert_eq!(
20700        wrap_with_prefix(
20701            "# ".to_string(),
20702            "abcdefg".to_string(),
20703            4,
20704            NonZeroU32::new(4).unwrap(),
20705            false,
20706        ),
20707        "# abcdefg"
20708    );
20709    assert_eq!(
20710        wrap_with_prefix(
20711            "".to_string(),
20712            "\thello world".to_string(),
20713            8,
20714            NonZeroU32::new(4).unwrap(),
20715            false,
20716        ),
20717        "hello\nworld"
20718    );
20719    assert_eq!(
20720        wrap_with_prefix(
20721            "// ".to_string(),
20722            "xx \nyy zz aa bb cc".to_string(),
20723            12,
20724            NonZeroU32::new(4).unwrap(),
20725            false,
20726        ),
20727        "// xx yy zz\n// aa bb cc"
20728    );
20729    assert_eq!(
20730        wrap_with_prefix(
20731            String::new(),
20732            "这是什么 \n 钢笔".to_string(),
20733            3,
20734            NonZeroU32::new(4).unwrap(),
20735            false,
20736        ),
20737        "这是什\n么 钢\n"
20738    );
20739}
20740
20741pub trait CollaborationHub {
20742    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20743    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20744    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20745}
20746
20747impl CollaborationHub for Entity<Project> {
20748    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20749        self.read(cx).collaborators()
20750    }
20751
20752    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20753        self.read(cx).user_store().read(cx).participant_indices()
20754    }
20755
20756    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20757        let this = self.read(cx);
20758        let user_ids = this.collaborators().values().map(|c| c.user_id);
20759        this.user_store().read(cx).participant_names(user_ids, cx)
20760    }
20761}
20762
20763pub trait SemanticsProvider {
20764    fn hover(
20765        &self,
20766        buffer: &Entity<Buffer>,
20767        position: text::Anchor,
20768        cx: &mut App,
20769    ) -> Option<Task<Vec<project::Hover>>>;
20770
20771    fn inline_values(
20772        &self,
20773        buffer_handle: Entity<Buffer>,
20774        range: Range<text::Anchor>,
20775        cx: &mut App,
20776    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20777
20778    fn inlay_hints(
20779        &self,
20780        buffer_handle: Entity<Buffer>,
20781        range: Range<text::Anchor>,
20782        cx: &mut App,
20783    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20784
20785    fn resolve_inlay_hint(
20786        &self,
20787        hint: InlayHint,
20788        buffer_handle: Entity<Buffer>,
20789        server_id: LanguageServerId,
20790        cx: &mut App,
20791    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20792
20793    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20794
20795    fn document_highlights(
20796        &self,
20797        buffer: &Entity<Buffer>,
20798        position: text::Anchor,
20799        cx: &mut App,
20800    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20801
20802    fn definitions(
20803        &self,
20804        buffer: &Entity<Buffer>,
20805        position: text::Anchor,
20806        kind: GotoDefinitionKind,
20807        cx: &mut App,
20808    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20809
20810    fn range_for_rename(
20811        &self,
20812        buffer: &Entity<Buffer>,
20813        position: text::Anchor,
20814        cx: &mut App,
20815    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20816
20817    fn perform_rename(
20818        &self,
20819        buffer: &Entity<Buffer>,
20820        position: text::Anchor,
20821        new_name: String,
20822        cx: &mut App,
20823    ) -> Option<Task<Result<ProjectTransaction>>>;
20824
20825    fn pull_diagnostics_for_buffer(
20826        &self,
20827        buffer: Entity<Buffer>,
20828        cx: &mut App,
20829    ) -> Task<anyhow::Result<()>>;
20830}
20831
20832pub trait CompletionProvider {
20833    fn completions(
20834        &self,
20835        excerpt_id: ExcerptId,
20836        buffer: &Entity<Buffer>,
20837        buffer_position: text::Anchor,
20838        trigger: CompletionContext,
20839        window: &mut Window,
20840        cx: &mut Context<Editor>,
20841    ) -> Task<Result<Vec<CompletionResponse>>>;
20842
20843    fn resolve_completions(
20844        &self,
20845        _buffer: Entity<Buffer>,
20846        _completion_indices: Vec<usize>,
20847        _completions: Rc<RefCell<Box<[Completion]>>>,
20848        _cx: &mut Context<Editor>,
20849    ) -> Task<Result<bool>> {
20850        Task::ready(Ok(false))
20851    }
20852
20853    fn apply_additional_edits_for_completion(
20854        &self,
20855        _buffer: Entity<Buffer>,
20856        _completions: Rc<RefCell<Box<[Completion]>>>,
20857        _completion_index: usize,
20858        _push_to_history: bool,
20859        _cx: &mut Context<Editor>,
20860    ) -> Task<Result<Option<language::Transaction>>> {
20861        Task::ready(Ok(None))
20862    }
20863
20864    fn is_completion_trigger(
20865        &self,
20866        buffer: &Entity<Buffer>,
20867        position: language::Anchor,
20868        text: &str,
20869        trigger_in_words: bool,
20870        menu_is_open: bool,
20871        cx: &mut Context<Editor>,
20872    ) -> bool;
20873
20874    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20875
20876    fn sort_completions(&self) -> bool {
20877        true
20878    }
20879
20880    fn filter_completions(&self) -> bool {
20881        true
20882    }
20883}
20884
20885pub trait CodeActionProvider {
20886    fn id(&self) -> Arc<str>;
20887
20888    fn code_actions(
20889        &self,
20890        buffer: &Entity<Buffer>,
20891        range: Range<text::Anchor>,
20892        window: &mut Window,
20893        cx: &mut App,
20894    ) -> Task<Result<Vec<CodeAction>>>;
20895
20896    fn apply_code_action(
20897        &self,
20898        buffer_handle: Entity<Buffer>,
20899        action: CodeAction,
20900        excerpt_id: ExcerptId,
20901        push_to_history: bool,
20902        window: &mut Window,
20903        cx: &mut App,
20904    ) -> Task<Result<ProjectTransaction>>;
20905}
20906
20907impl CodeActionProvider for Entity<Project> {
20908    fn id(&self) -> Arc<str> {
20909        "project".into()
20910    }
20911
20912    fn code_actions(
20913        &self,
20914        buffer: &Entity<Buffer>,
20915        range: Range<text::Anchor>,
20916        _window: &mut Window,
20917        cx: &mut App,
20918    ) -> Task<Result<Vec<CodeAction>>> {
20919        self.update(cx, |project, cx| {
20920            let code_lens = project.code_lens(buffer, range.clone(), cx);
20921            let code_actions = project.code_actions(buffer, range, None, cx);
20922            cx.background_spawn(async move {
20923                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20924                Ok(code_lens
20925                    .context("code lens fetch")?
20926                    .into_iter()
20927                    .chain(code_actions.context("code action fetch")?)
20928                    .collect())
20929            })
20930        })
20931    }
20932
20933    fn apply_code_action(
20934        &self,
20935        buffer_handle: Entity<Buffer>,
20936        action: CodeAction,
20937        _excerpt_id: ExcerptId,
20938        push_to_history: bool,
20939        _window: &mut Window,
20940        cx: &mut App,
20941    ) -> Task<Result<ProjectTransaction>> {
20942        self.update(cx, |project, cx| {
20943            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20944        })
20945    }
20946}
20947
20948fn snippet_completions(
20949    project: &Project,
20950    buffer: &Entity<Buffer>,
20951    buffer_position: text::Anchor,
20952    cx: &mut App,
20953) -> Task<Result<CompletionResponse>> {
20954    let languages = buffer.read(cx).languages_at(buffer_position);
20955    let snippet_store = project.snippets().read(cx);
20956
20957    let scopes: Vec<_> = languages
20958        .iter()
20959        .filter_map(|language| {
20960            let language_name = language.lsp_id();
20961            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20962
20963            if snippets.is_empty() {
20964                None
20965            } else {
20966                Some((language.default_scope(), snippets))
20967            }
20968        })
20969        .collect();
20970
20971    if scopes.is_empty() {
20972        return Task::ready(Ok(CompletionResponse {
20973            completions: vec![],
20974            is_incomplete: false,
20975        }));
20976    }
20977
20978    let snapshot = buffer.read(cx).text_snapshot();
20979    let chars: String = snapshot
20980        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20981        .collect();
20982    let executor = cx.background_executor().clone();
20983
20984    cx.background_spawn(async move {
20985        let mut is_incomplete = false;
20986        let mut completions: Vec<Completion> = Vec::new();
20987        for (scope, snippets) in scopes.into_iter() {
20988            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20989            let mut last_word = chars
20990                .chars()
20991                .take_while(|c| classifier.is_word(*c))
20992                .collect::<String>();
20993            last_word = last_word.chars().rev().collect();
20994
20995            if last_word.is_empty() {
20996                return Ok(CompletionResponse {
20997                    completions: vec![],
20998                    is_incomplete: true,
20999                });
21000            }
21001
21002            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21003            let to_lsp = |point: &text::Anchor| {
21004                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21005                point_to_lsp(end)
21006            };
21007            let lsp_end = to_lsp(&buffer_position);
21008
21009            let candidates = snippets
21010                .iter()
21011                .enumerate()
21012                .flat_map(|(ix, snippet)| {
21013                    snippet
21014                        .prefix
21015                        .iter()
21016                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21017                })
21018                .collect::<Vec<StringMatchCandidate>>();
21019
21020            const MAX_RESULTS: usize = 100;
21021            let mut matches = fuzzy::match_strings(
21022                &candidates,
21023                &last_word,
21024                last_word.chars().any(|c| c.is_uppercase()),
21025                MAX_RESULTS,
21026                &Default::default(),
21027                executor.clone(),
21028            )
21029            .await;
21030
21031            if matches.len() >= MAX_RESULTS {
21032                is_incomplete = true;
21033            }
21034
21035            // Remove all candidates where the query's start does not match the start of any word in the candidate
21036            if let Some(query_start) = last_word.chars().next() {
21037                matches.retain(|string_match| {
21038                    split_words(&string_match.string).any(|word| {
21039                        // Check that the first codepoint of the word as lowercase matches the first
21040                        // codepoint of the query as lowercase
21041                        word.chars()
21042                            .flat_map(|codepoint| codepoint.to_lowercase())
21043                            .zip(query_start.to_lowercase())
21044                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21045                    })
21046                });
21047            }
21048
21049            let matched_strings = matches
21050                .into_iter()
21051                .map(|m| m.string)
21052                .collect::<HashSet<_>>();
21053
21054            completions.extend(snippets.iter().filter_map(|snippet| {
21055                let matching_prefix = snippet
21056                    .prefix
21057                    .iter()
21058                    .find(|prefix| matched_strings.contains(*prefix))?;
21059                let start = as_offset - last_word.len();
21060                let start = snapshot.anchor_before(start);
21061                let range = start..buffer_position;
21062                let lsp_start = to_lsp(&start);
21063                let lsp_range = lsp::Range {
21064                    start: lsp_start,
21065                    end: lsp_end,
21066                };
21067                Some(Completion {
21068                    replace_range: range,
21069                    new_text: snippet.body.clone(),
21070                    source: CompletionSource::Lsp {
21071                        insert_range: None,
21072                        server_id: LanguageServerId(usize::MAX),
21073                        resolved: true,
21074                        lsp_completion: Box::new(lsp::CompletionItem {
21075                            label: snippet.prefix.first().unwrap().clone(),
21076                            kind: Some(CompletionItemKind::SNIPPET),
21077                            label_details: snippet.description.as_ref().map(|description| {
21078                                lsp::CompletionItemLabelDetails {
21079                                    detail: Some(description.clone()),
21080                                    description: None,
21081                                }
21082                            }),
21083                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21084                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21085                                lsp::InsertReplaceEdit {
21086                                    new_text: snippet.body.clone(),
21087                                    insert: lsp_range,
21088                                    replace: lsp_range,
21089                                },
21090                            )),
21091                            filter_text: Some(snippet.body.clone()),
21092                            sort_text: Some(char::MAX.to_string()),
21093                            ..lsp::CompletionItem::default()
21094                        }),
21095                        lsp_defaults: None,
21096                    },
21097                    label: CodeLabel {
21098                        text: matching_prefix.clone(),
21099                        runs: Vec::new(),
21100                        filter_range: 0..matching_prefix.len(),
21101                    },
21102                    icon_path: None,
21103                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21104                        single_line: snippet.name.clone().into(),
21105                        plain_text: snippet
21106                            .description
21107                            .clone()
21108                            .map(|description| description.into()),
21109                    }),
21110                    insert_text_mode: None,
21111                    confirm: None,
21112                })
21113            }))
21114        }
21115
21116        Ok(CompletionResponse {
21117            completions,
21118            is_incomplete,
21119        })
21120    })
21121}
21122
21123impl CompletionProvider for Entity<Project> {
21124    fn completions(
21125        &self,
21126        _excerpt_id: ExcerptId,
21127        buffer: &Entity<Buffer>,
21128        buffer_position: text::Anchor,
21129        options: CompletionContext,
21130        _window: &mut Window,
21131        cx: &mut Context<Editor>,
21132    ) -> Task<Result<Vec<CompletionResponse>>> {
21133        self.update(cx, |project, cx| {
21134            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21135            let project_completions = project.completions(buffer, buffer_position, options, cx);
21136            cx.background_spawn(async move {
21137                let mut responses = project_completions.await?;
21138                let snippets = snippets.await?;
21139                if !snippets.completions.is_empty() {
21140                    responses.push(snippets);
21141                }
21142                Ok(responses)
21143            })
21144        })
21145    }
21146
21147    fn resolve_completions(
21148        &self,
21149        buffer: Entity<Buffer>,
21150        completion_indices: Vec<usize>,
21151        completions: Rc<RefCell<Box<[Completion]>>>,
21152        cx: &mut Context<Editor>,
21153    ) -> Task<Result<bool>> {
21154        self.update(cx, |project, cx| {
21155            project.lsp_store().update(cx, |lsp_store, cx| {
21156                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21157            })
21158        })
21159    }
21160
21161    fn apply_additional_edits_for_completion(
21162        &self,
21163        buffer: Entity<Buffer>,
21164        completions: Rc<RefCell<Box<[Completion]>>>,
21165        completion_index: usize,
21166        push_to_history: bool,
21167        cx: &mut Context<Editor>,
21168    ) -> Task<Result<Option<language::Transaction>>> {
21169        self.update(cx, |project, cx| {
21170            project.lsp_store().update(cx, |lsp_store, cx| {
21171                lsp_store.apply_additional_edits_for_completion(
21172                    buffer,
21173                    completions,
21174                    completion_index,
21175                    push_to_history,
21176                    cx,
21177                )
21178            })
21179        })
21180    }
21181
21182    fn is_completion_trigger(
21183        &self,
21184        buffer: &Entity<Buffer>,
21185        position: language::Anchor,
21186        text: &str,
21187        trigger_in_words: bool,
21188        menu_is_open: bool,
21189        cx: &mut Context<Editor>,
21190    ) -> bool {
21191        let mut chars = text.chars();
21192        let char = if let Some(char) = chars.next() {
21193            char
21194        } else {
21195            return false;
21196        };
21197        if chars.next().is_some() {
21198            return false;
21199        }
21200
21201        let buffer = buffer.read(cx);
21202        let snapshot = buffer.snapshot();
21203        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21204            return false;
21205        }
21206        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21207        if trigger_in_words && classifier.is_word(char) {
21208            return true;
21209        }
21210
21211        buffer.completion_triggers().contains(text)
21212    }
21213}
21214
21215impl SemanticsProvider for Entity<Project> {
21216    fn hover(
21217        &self,
21218        buffer: &Entity<Buffer>,
21219        position: text::Anchor,
21220        cx: &mut App,
21221    ) -> Option<Task<Vec<project::Hover>>> {
21222        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21223    }
21224
21225    fn document_highlights(
21226        &self,
21227        buffer: &Entity<Buffer>,
21228        position: text::Anchor,
21229        cx: &mut App,
21230    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21231        Some(self.update(cx, |project, cx| {
21232            project.document_highlights(buffer, position, cx)
21233        }))
21234    }
21235
21236    fn definitions(
21237        &self,
21238        buffer: &Entity<Buffer>,
21239        position: text::Anchor,
21240        kind: GotoDefinitionKind,
21241        cx: &mut App,
21242    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21243        Some(self.update(cx, |project, cx| match kind {
21244            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21245            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21246            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21247            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21248        }))
21249    }
21250
21251    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21252        // TODO: make this work for remote projects
21253        self.update(cx, |project, cx| {
21254            if project
21255                .active_debug_session(cx)
21256                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21257            {
21258                return true;
21259            }
21260
21261            buffer.update(cx, |buffer, cx| {
21262                project.any_language_server_supports_inlay_hints(buffer, cx)
21263            })
21264        })
21265    }
21266
21267    fn inline_values(
21268        &self,
21269        buffer_handle: Entity<Buffer>,
21270
21271        range: Range<text::Anchor>,
21272        cx: &mut App,
21273    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21274        self.update(cx, |project, cx| {
21275            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21276
21277            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21278        })
21279    }
21280
21281    fn inlay_hints(
21282        &self,
21283        buffer_handle: Entity<Buffer>,
21284        range: Range<text::Anchor>,
21285        cx: &mut App,
21286    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21287        Some(self.update(cx, |project, cx| {
21288            project.inlay_hints(buffer_handle, range, cx)
21289        }))
21290    }
21291
21292    fn resolve_inlay_hint(
21293        &self,
21294        hint: InlayHint,
21295        buffer_handle: Entity<Buffer>,
21296        server_id: LanguageServerId,
21297        cx: &mut App,
21298    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21299        Some(self.update(cx, |project, cx| {
21300            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21301        }))
21302    }
21303
21304    fn range_for_rename(
21305        &self,
21306        buffer: &Entity<Buffer>,
21307        position: text::Anchor,
21308        cx: &mut App,
21309    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21310        Some(self.update(cx, |project, cx| {
21311            let buffer = buffer.clone();
21312            let task = project.prepare_rename(buffer.clone(), position, cx);
21313            cx.spawn(async move |_, cx| {
21314                Ok(match task.await? {
21315                    PrepareRenameResponse::Success(range) => Some(range),
21316                    PrepareRenameResponse::InvalidPosition => None,
21317                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21318                        // Fallback on using TreeSitter info to determine identifier range
21319                        buffer.read_with(cx, |buffer, _| {
21320                            let snapshot = buffer.snapshot();
21321                            let (range, kind) = snapshot.surrounding_word(position);
21322                            if kind != Some(CharKind::Word) {
21323                                return None;
21324                            }
21325                            Some(
21326                                snapshot.anchor_before(range.start)
21327                                    ..snapshot.anchor_after(range.end),
21328                            )
21329                        })?
21330                    }
21331                })
21332            })
21333        }))
21334    }
21335
21336    fn perform_rename(
21337        &self,
21338        buffer: &Entity<Buffer>,
21339        position: text::Anchor,
21340        new_name: String,
21341        cx: &mut App,
21342    ) -> Option<Task<Result<ProjectTransaction>>> {
21343        Some(self.update(cx, |project, cx| {
21344            project.perform_rename(buffer.clone(), position, new_name, cx)
21345        }))
21346    }
21347
21348    fn pull_diagnostics_for_buffer(
21349        &self,
21350        buffer: Entity<Buffer>,
21351        cx: &mut App,
21352    ) -> Task<anyhow::Result<()>> {
21353        let diagnostics = self.update(cx, |project, cx| {
21354            project
21355                .lsp_store()
21356                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21357        });
21358        let project = self.clone();
21359        cx.spawn(async move |cx| {
21360            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21361            project.update(cx, |project, cx| {
21362                project.lsp_store().update(cx, |lsp_store, cx| {
21363                    for diagnostics_set in diagnostics {
21364                        let LspPullDiagnostics::Response {
21365                            server_id,
21366                            uri,
21367                            diagnostics,
21368                        } = diagnostics_set
21369                        else {
21370                            continue;
21371                        };
21372
21373                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21374                        let disk_based_sources = adapter
21375                            .as_ref()
21376                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21377                            .unwrap_or(&[]);
21378                        match diagnostics {
21379                            PulledDiagnostics::Unchanged { result_id } => {
21380                                lsp_store
21381                                    .merge_diagnostics(
21382                                        server_id,
21383                                        lsp::PublishDiagnosticsParams {
21384                                            uri: uri.clone(),
21385                                            diagnostics: Vec::new(),
21386                                            version: None,
21387                                        },
21388                                        Some(result_id),
21389                                        DiagnosticSourceKind::Pulled,
21390                                        disk_based_sources,
21391                                        |_, _| true,
21392                                        cx,
21393                                    )
21394                                    .log_err();
21395                            }
21396                            PulledDiagnostics::Changed {
21397                                diagnostics,
21398                                result_id,
21399                            } => {
21400                                lsp_store
21401                                    .merge_diagnostics(
21402                                        server_id,
21403                                        lsp::PublishDiagnosticsParams {
21404                                            uri: uri.clone(),
21405                                            diagnostics,
21406                                            version: None,
21407                                        },
21408                                        result_id,
21409                                        DiagnosticSourceKind::Pulled,
21410                                        disk_based_sources,
21411                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21412                                            DiagnosticSourceKind::Pulled => false,
21413                                            DiagnosticSourceKind::Other
21414                                            | DiagnosticSourceKind::Pushed => true,
21415                                        },
21416                                        cx,
21417                                    )
21418                                    .log_err();
21419                            }
21420                        }
21421                    }
21422                })
21423            })
21424        })
21425    }
21426}
21427
21428fn inlay_hint_settings(
21429    location: Anchor,
21430    snapshot: &MultiBufferSnapshot,
21431    cx: &mut Context<Editor>,
21432) -> InlayHintSettings {
21433    let file = snapshot.file_at(location);
21434    let language = snapshot.language_at(location).map(|l| l.name());
21435    language_settings(language, file, cx).inlay_hints
21436}
21437
21438fn consume_contiguous_rows(
21439    contiguous_row_selections: &mut Vec<Selection<Point>>,
21440    selection: &Selection<Point>,
21441    display_map: &DisplaySnapshot,
21442    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21443) -> (MultiBufferRow, MultiBufferRow) {
21444    contiguous_row_selections.push(selection.clone());
21445    let start_row = MultiBufferRow(selection.start.row);
21446    let mut end_row = ending_row(selection, display_map);
21447
21448    while let Some(next_selection) = selections.peek() {
21449        if next_selection.start.row <= end_row.0 {
21450            end_row = ending_row(next_selection, display_map);
21451            contiguous_row_selections.push(selections.next().unwrap().clone());
21452        } else {
21453            break;
21454        }
21455    }
21456    (start_row, end_row)
21457}
21458
21459fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21460    if next_selection.end.column > 0 || next_selection.is_empty() {
21461        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21462    } else {
21463        MultiBufferRow(next_selection.end.row)
21464    }
21465}
21466
21467impl EditorSnapshot {
21468    pub fn remote_selections_in_range<'a>(
21469        &'a self,
21470        range: &'a Range<Anchor>,
21471        collaboration_hub: &dyn CollaborationHub,
21472        cx: &'a App,
21473    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21474        let participant_names = collaboration_hub.user_names(cx);
21475        let participant_indices = collaboration_hub.user_participant_indices(cx);
21476        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21477        let collaborators_by_replica_id = collaborators_by_peer_id
21478            .values()
21479            .map(|collaborator| (collaborator.replica_id, collaborator))
21480            .collect::<HashMap<_, _>>();
21481        self.buffer_snapshot
21482            .selections_in_range(range, false)
21483            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21484                if replica_id == AGENT_REPLICA_ID {
21485                    Some(RemoteSelection {
21486                        replica_id,
21487                        selection,
21488                        cursor_shape,
21489                        line_mode,
21490                        collaborator_id: CollaboratorId::Agent,
21491                        user_name: Some("Agent".into()),
21492                        color: cx.theme().players().agent(),
21493                    })
21494                } else {
21495                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21496                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21497                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21498                    Some(RemoteSelection {
21499                        replica_id,
21500                        selection,
21501                        cursor_shape,
21502                        line_mode,
21503                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21504                        user_name,
21505                        color: if let Some(index) = participant_index {
21506                            cx.theme().players().color_for_participant(index.0)
21507                        } else {
21508                            cx.theme().players().absent()
21509                        },
21510                    })
21511                }
21512            })
21513    }
21514
21515    pub fn hunks_for_ranges(
21516        &self,
21517        ranges: impl IntoIterator<Item = Range<Point>>,
21518    ) -> Vec<MultiBufferDiffHunk> {
21519        let mut hunks = Vec::new();
21520        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21521            HashMap::default();
21522        for query_range in ranges {
21523            let query_rows =
21524                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21525            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21526                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21527            ) {
21528                // Include deleted hunks that are adjacent to the query range, because
21529                // otherwise they would be missed.
21530                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21531                if hunk.status().is_deleted() {
21532                    intersects_range |= hunk.row_range.start == query_rows.end;
21533                    intersects_range |= hunk.row_range.end == query_rows.start;
21534                }
21535                if intersects_range {
21536                    if !processed_buffer_rows
21537                        .entry(hunk.buffer_id)
21538                        .or_default()
21539                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21540                    {
21541                        continue;
21542                    }
21543                    hunks.push(hunk);
21544                }
21545            }
21546        }
21547
21548        hunks
21549    }
21550
21551    fn display_diff_hunks_for_rows<'a>(
21552        &'a self,
21553        display_rows: Range<DisplayRow>,
21554        folded_buffers: &'a HashSet<BufferId>,
21555    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21556        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21557        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21558
21559        self.buffer_snapshot
21560            .diff_hunks_in_range(buffer_start..buffer_end)
21561            .filter_map(|hunk| {
21562                if folded_buffers.contains(&hunk.buffer_id) {
21563                    return None;
21564                }
21565
21566                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21567                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21568
21569                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21570                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21571
21572                let display_hunk = if hunk_display_start.column() != 0 {
21573                    DisplayDiffHunk::Folded {
21574                        display_row: hunk_display_start.row(),
21575                    }
21576                } else {
21577                    let mut end_row = hunk_display_end.row();
21578                    if hunk_display_end.column() > 0 {
21579                        end_row.0 += 1;
21580                    }
21581                    let is_created_file = hunk.is_created_file();
21582                    DisplayDiffHunk::Unfolded {
21583                        status: hunk.status(),
21584                        diff_base_byte_range: hunk.diff_base_byte_range,
21585                        display_row_range: hunk_display_start.row()..end_row,
21586                        multi_buffer_range: Anchor::range_in_buffer(
21587                            hunk.excerpt_id,
21588                            hunk.buffer_id,
21589                            hunk.buffer_range,
21590                        ),
21591                        is_created_file,
21592                    }
21593                };
21594
21595                Some(display_hunk)
21596            })
21597    }
21598
21599    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21600        self.display_snapshot.buffer_snapshot.language_at(position)
21601    }
21602
21603    pub fn is_focused(&self) -> bool {
21604        self.is_focused
21605    }
21606
21607    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21608        self.placeholder_text.as_ref()
21609    }
21610
21611    pub fn scroll_position(&self) -> gpui::Point<f32> {
21612        self.scroll_anchor.scroll_position(&self.display_snapshot)
21613    }
21614
21615    fn gutter_dimensions(
21616        &self,
21617        font_id: FontId,
21618        font_size: Pixels,
21619        max_line_number_width: Pixels,
21620        cx: &App,
21621    ) -> Option<GutterDimensions> {
21622        if !self.show_gutter {
21623            return None;
21624        }
21625
21626        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
21627        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
21628
21629        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21630            matches!(
21631                ProjectSettings::get_global(cx).git.git_gutter,
21632                Some(GitGutterSetting::TrackedFiles)
21633            )
21634        });
21635        let gutter_settings = EditorSettings::get_global(cx).gutter;
21636        let show_line_numbers = self
21637            .show_line_numbers
21638            .unwrap_or(gutter_settings.line_numbers);
21639        let line_gutter_width = if show_line_numbers {
21640            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
21641            let min_width_for_number_on_gutter =
21642                em_advance * gutter_settings.min_line_number_digits as f32;
21643            max_line_number_width.max(min_width_for_number_on_gutter)
21644        } else {
21645            0.0.into()
21646        };
21647
21648        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21649        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21650
21651        let git_blame_entries_width =
21652            self.git_blame_gutter_max_author_length
21653                .map(|max_author_length| {
21654                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21655                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21656
21657                    /// The number of characters to dedicate to gaps and margins.
21658                    const SPACING_WIDTH: usize = 4;
21659
21660                    let max_char_count = max_author_length.min(renderer.max_author_length())
21661                        + ::git::SHORT_SHA_LENGTH
21662                        + MAX_RELATIVE_TIMESTAMP.len()
21663                        + SPACING_WIDTH;
21664
21665                    em_advance * max_char_count
21666                });
21667
21668        let is_singleton = self.buffer_snapshot.is_singleton();
21669
21670        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21671        left_padding += if !is_singleton {
21672            em_width * 4.0
21673        } else if show_runnables || show_breakpoints {
21674            em_width * 3.0
21675        } else if show_git_gutter && show_line_numbers {
21676            em_width * 2.0
21677        } else if show_git_gutter || show_line_numbers {
21678            em_width
21679        } else {
21680            px(0.)
21681        };
21682
21683        let shows_folds = is_singleton && gutter_settings.folds;
21684
21685        let right_padding = if shows_folds && show_line_numbers {
21686            em_width * 4.0
21687        } else if shows_folds || (!is_singleton && show_line_numbers) {
21688            em_width * 3.0
21689        } else if show_line_numbers {
21690            em_width
21691        } else {
21692            px(0.)
21693        };
21694
21695        Some(GutterDimensions {
21696            left_padding,
21697            right_padding,
21698            width: line_gutter_width + left_padding + right_padding,
21699            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21700            git_blame_entries_width,
21701        })
21702    }
21703
21704    pub fn render_crease_toggle(
21705        &self,
21706        buffer_row: MultiBufferRow,
21707        row_contains_cursor: bool,
21708        editor: Entity<Editor>,
21709        window: &mut Window,
21710        cx: &mut App,
21711    ) -> Option<AnyElement> {
21712        let folded = self.is_line_folded(buffer_row);
21713        let mut is_foldable = false;
21714
21715        if let Some(crease) = self
21716            .crease_snapshot
21717            .query_row(buffer_row, &self.buffer_snapshot)
21718        {
21719            is_foldable = true;
21720            match crease {
21721                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21722                    if let Some(render_toggle) = render_toggle {
21723                        let toggle_callback =
21724                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21725                                if folded {
21726                                    editor.update(cx, |editor, cx| {
21727                                        editor.fold_at(buffer_row, window, cx)
21728                                    });
21729                                } else {
21730                                    editor.update(cx, |editor, cx| {
21731                                        editor.unfold_at(buffer_row, window, cx)
21732                                    });
21733                                }
21734                            });
21735                        return Some((render_toggle)(
21736                            buffer_row,
21737                            folded,
21738                            toggle_callback,
21739                            window,
21740                            cx,
21741                        ));
21742                    }
21743                }
21744            }
21745        }
21746
21747        is_foldable |= self.starts_indent(buffer_row);
21748
21749        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21750            Some(
21751                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21752                    .toggle_state(folded)
21753                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21754                        if folded {
21755                            this.unfold_at(buffer_row, window, cx);
21756                        } else {
21757                            this.fold_at(buffer_row, window, cx);
21758                        }
21759                    }))
21760                    .into_any_element(),
21761            )
21762        } else {
21763            None
21764        }
21765    }
21766
21767    pub fn render_crease_trailer(
21768        &self,
21769        buffer_row: MultiBufferRow,
21770        window: &mut Window,
21771        cx: &mut App,
21772    ) -> Option<AnyElement> {
21773        let folded = self.is_line_folded(buffer_row);
21774        if let Crease::Inline { render_trailer, .. } = self
21775            .crease_snapshot
21776            .query_row(buffer_row, &self.buffer_snapshot)?
21777        {
21778            let render_trailer = render_trailer.as_ref()?;
21779            Some(render_trailer(buffer_row, folded, window, cx))
21780        } else {
21781            None
21782        }
21783    }
21784}
21785
21786impl Deref for EditorSnapshot {
21787    type Target = DisplaySnapshot;
21788
21789    fn deref(&self) -> &Self::Target {
21790        &self.display_snapshot
21791    }
21792}
21793
21794#[derive(Clone, Debug, PartialEq, Eq)]
21795pub enum EditorEvent {
21796    InputIgnored {
21797        text: Arc<str>,
21798    },
21799    InputHandled {
21800        utf16_range_to_replace: Option<Range<isize>>,
21801        text: Arc<str>,
21802    },
21803    ExcerptsAdded {
21804        buffer: Entity<Buffer>,
21805        predecessor: ExcerptId,
21806        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21807    },
21808    ExcerptsRemoved {
21809        ids: Vec<ExcerptId>,
21810        removed_buffer_ids: Vec<BufferId>,
21811    },
21812    BufferFoldToggled {
21813        ids: Vec<ExcerptId>,
21814        folded: bool,
21815    },
21816    ExcerptsEdited {
21817        ids: Vec<ExcerptId>,
21818    },
21819    ExcerptsExpanded {
21820        ids: Vec<ExcerptId>,
21821    },
21822    BufferEdited,
21823    Edited {
21824        transaction_id: clock::Lamport,
21825    },
21826    Reparsed(BufferId),
21827    Focused,
21828    FocusedIn,
21829    Blurred,
21830    DirtyChanged,
21831    Saved,
21832    TitleChanged,
21833    DiffBaseChanged,
21834    SelectionsChanged {
21835        local: bool,
21836    },
21837    ScrollPositionChanged {
21838        local: bool,
21839        autoscroll: bool,
21840    },
21841    Closed,
21842    TransactionUndone {
21843        transaction_id: clock::Lamport,
21844    },
21845    TransactionBegun {
21846        transaction_id: clock::Lamport,
21847    },
21848    Reloaded,
21849    CursorShapeChanged,
21850    PushedToNavHistory {
21851        anchor: Anchor,
21852        is_deactivate: bool,
21853    },
21854}
21855
21856impl EventEmitter<EditorEvent> for Editor {}
21857
21858impl Focusable for Editor {
21859    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21860        self.focus_handle.clone()
21861    }
21862}
21863
21864impl Render for Editor {
21865    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21866        let settings = ThemeSettings::get_global(cx);
21867
21868        let mut text_style = match self.mode {
21869            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21870                color: cx.theme().colors().editor_foreground,
21871                font_family: settings.ui_font.family.clone(),
21872                font_features: settings.ui_font.features.clone(),
21873                font_fallbacks: settings.ui_font.fallbacks.clone(),
21874                font_size: rems(0.875).into(),
21875                font_weight: settings.ui_font.weight,
21876                line_height: relative(settings.buffer_line_height.value()),
21877                ..Default::default()
21878            },
21879            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21880                color: cx.theme().colors().editor_foreground,
21881                font_family: settings.buffer_font.family.clone(),
21882                font_features: settings.buffer_font.features.clone(),
21883                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21884                font_size: settings.buffer_font_size(cx).into(),
21885                font_weight: settings.buffer_font.weight,
21886                line_height: relative(settings.buffer_line_height.value()),
21887                ..Default::default()
21888            },
21889        };
21890        if let Some(text_style_refinement) = &self.text_style_refinement {
21891            text_style.refine(text_style_refinement)
21892        }
21893
21894        let background = match self.mode {
21895            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21896            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21897            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21898            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21899        };
21900
21901        EditorElement::new(
21902            &cx.entity(),
21903            EditorStyle {
21904                background,
21905                local_player: cx.theme().players().local(),
21906                text: text_style,
21907                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21908                syntax: cx.theme().syntax().clone(),
21909                status: cx.theme().status().clone(),
21910                inlay_hints_style: make_inlay_hints_style(cx),
21911                inline_completion_styles: make_suggestion_styles(cx),
21912                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21913                show_underlines: !self.mode.is_minimap(),
21914            },
21915        )
21916    }
21917}
21918
21919impl EntityInputHandler for Editor {
21920    fn text_for_range(
21921        &mut self,
21922        range_utf16: Range<usize>,
21923        adjusted_range: &mut Option<Range<usize>>,
21924        _: &mut Window,
21925        cx: &mut Context<Self>,
21926    ) -> Option<String> {
21927        let snapshot = self.buffer.read(cx).read(cx);
21928        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21929        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21930        if (start.0..end.0) != range_utf16 {
21931            adjusted_range.replace(start.0..end.0);
21932        }
21933        Some(snapshot.text_for_range(start..end).collect())
21934    }
21935
21936    fn selected_text_range(
21937        &mut self,
21938        ignore_disabled_input: bool,
21939        _: &mut Window,
21940        cx: &mut Context<Self>,
21941    ) -> Option<UTF16Selection> {
21942        // Prevent the IME menu from appearing when holding down an alphabetic key
21943        // while input is disabled.
21944        if !ignore_disabled_input && !self.input_enabled {
21945            return None;
21946        }
21947
21948        let selection = self.selections.newest::<OffsetUtf16>(cx);
21949        let range = selection.range();
21950
21951        Some(UTF16Selection {
21952            range: range.start.0..range.end.0,
21953            reversed: selection.reversed,
21954        })
21955    }
21956
21957    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21958        let snapshot = self.buffer.read(cx).read(cx);
21959        let (range, _) = self.text_highlights::<InputComposition>(cx)?.first()?;
21960        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21961    }
21962
21963    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21964        self.clear_highlights::<InputComposition>(cx);
21965        self.ime_transaction.take();
21966    }
21967
21968    fn replace_text_in_range(
21969        &mut self,
21970        range_utf16: Option<Range<usize>>,
21971        text: &str,
21972        window: &mut Window,
21973        cx: &mut Context<Self>,
21974    ) {
21975        if !self.input_enabled {
21976            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21977            return;
21978        }
21979
21980        self.transact(window, cx, |this, window, cx| {
21981            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21982                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21983                Some(this.selection_replacement_ranges(range_utf16, cx))
21984            } else {
21985                this.marked_text_ranges(cx)
21986            };
21987
21988            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21989                let newest_selection_id = this.selections.newest_anchor().id;
21990                this.selections
21991                    .all::<OffsetUtf16>(cx)
21992                    .iter()
21993                    .zip(ranges_to_replace.iter())
21994                    .find_map(|(selection, range)| {
21995                        if selection.id == newest_selection_id {
21996                            Some(
21997                                (range.start.0 as isize - selection.head().0 as isize)
21998                                    ..(range.end.0 as isize - selection.head().0 as isize),
21999                            )
22000                        } else {
22001                            None
22002                        }
22003                    })
22004            });
22005
22006            cx.emit(EditorEvent::InputHandled {
22007                utf16_range_to_replace: range_to_replace,
22008                text: text.into(),
22009            });
22010
22011            if let Some(new_selected_ranges) = new_selected_ranges {
22012                this.change_selections(None, window, cx, |selections| {
22013                    selections.select_ranges(new_selected_ranges)
22014                });
22015                this.backspace(&Default::default(), window, cx);
22016            }
22017
22018            this.handle_input(text, window, cx);
22019        });
22020
22021        if let Some(transaction) = self.ime_transaction {
22022            self.buffer.update(cx, |buffer, cx| {
22023                buffer.group_until_transaction(transaction, cx);
22024            });
22025        }
22026
22027        self.unmark_text(window, cx);
22028    }
22029
22030    fn replace_and_mark_text_in_range(
22031        &mut self,
22032        range_utf16: Option<Range<usize>>,
22033        text: &str,
22034        new_selected_range_utf16: Option<Range<usize>>,
22035        window: &mut Window,
22036        cx: &mut Context<Self>,
22037    ) {
22038        if !self.input_enabled {
22039            return;
22040        }
22041
22042        let transaction = self.transact(window, cx, |this, window, cx| {
22043            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22044                let snapshot = this.buffer.read(cx).read(cx);
22045                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22046                    for marked_range in &mut marked_ranges {
22047                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22048                        marked_range.start.0 += relative_range_utf16.start;
22049                        marked_range.start =
22050                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22051                        marked_range.end =
22052                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22053                    }
22054                }
22055                Some(marked_ranges)
22056            } else if let Some(range_utf16) = range_utf16 {
22057                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22058                Some(this.selection_replacement_ranges(range_utf16, cx))
22059            } else {
22060                None
22061            };
22062
22063            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22064                let newest_selection_id = this.selections.newest_anchor().id;
22065                this.selections
22066                    .all::<OffsetUtf16>(cx)
22067                    .iter()
22068                    .zip(ranges_to_replace.iter())
22069                    .find_map(|(selection, range)| {
22070                        if selection.id == newest_selection_id {
22071                            Some(
22072                                (range.start.0 as isize - selection.head().0 as isize)
22073                                    ..(range.end.0 as isize - selection.head().0 as isize),
22074                            )
22075                        } else {
22076                            None
22077                        }
22078                    })
22079            });
22080
22081            cx.emit(EditorEvent::InputHandled {
22082                utf16_range_to_replace: range_to_replace,
22083                text: text.into(),
22084            });
22085
22086            if let Some(ranges) = ranges_to_replace {
22087                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22088            }
22089
22090            let marked_ranges = {
22091                let snapshot = this.buffer.read(cx).read(cx);
22092                this.selections
22093                    .disjoint_anchors()
22094                    .iter()
22095                    .map(|selection| {
22096                        (
22097                            selection.start.bias_left(&snapshot)
22098                                ..selection.end.bias_right(&snapshot),
22099                            HighlightStyle {
22100                                underline: Some(UnderlineStyle {
22101                                    thickness: px(1.),
22102                                    color: None,
22103                                    wavy: false,
22104                                }),
22105                                ..Default::default()
22106                            },
22107                        )
22108                    })
22109                    .collect::<Vec<_>>()
22110            };
22111
22112            if text.is_empty() {
22113                this.unmark_text(window, cx);
22114            } else {
22115                this.highlight_text::<InputComposition>(marked_ranges.clone(), cx);
22116            }
22117
22118            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22119            let use_autoclose = this.use_autoclose;
22120            let use_auto_surround = this.use_auto_surround;
22121            this.set_use_autoclose(false);
22122            this.set_use_auto_surround(false);
22123            this.handle_input(text, window, cx);
22124            this.set_use_autoclose(use_autoclose);
22125            this.set_use_auto_surround(use_auto_surround);
22126
22127            if let Some(new_selected_range) = new_selected_range_utf16 {
22128                let snapshot = this.buffer.read(cx).read(cx);
22129                let new_selected_ranges = marked_ranges
22130                    .into_iter()
22131                    .map(|(marked_range, _)| {
22132                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22133                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22134                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22135                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22136                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22137                    })
22138                    .collect::<Vec<_>>();
22139
22140                drop(snapshot);
22141                this.change_selections(None, window, cx, |selections| {
22142                    selections.select_ranges(new_selected_ranges)
22143                });
22144            }
22145        });
22146
22147        self.ime_transaction = self.ime_transaction.or(transaction);
22148        if let Some(transaction) = self.ime_transaction {
22149            self.buffer.update(cx, |buffer, cx| {
22150                buffer.group_until_transaction(transaction, cx);
22151            });
22152        }
22153
22154        if self.text_highlights::<InputComposition>(cx).is_none() {
22155            self.ime_transaction.take();
22156        }
22157    }
22158
22159    fn bounds_for_range(
22160        &mut self,
22161        range_utf16: Range<usize>,
22162        element_bounds: gpui::Bounds<Pixels>,
22163        window: &mut Window,
22164        cx: &mut Context<Self>,
22165    ) -> Option<gpui::Bounds<Pixels>> {
22166        let text_layout_details = self.text_layout_details(window);
22167        let gpui::Size {
22168            width: em_width,
22169            height: line_height,
22170        } = self.character_size(window);
22171
22172        let snapshot = self.snapshot(window, cx);
22173        let scroll_position = snapshot.scroll_position();
22174        let scroll_left = scroll_position.x * em_width;
22175
22176        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22177        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22178            + self.gutter_dimensions.width
22179            + self.gutter_dimensions.margin;
22180        let y = line_height * (start.row().as_f32() - scroll_position.y);
22181
22182        Some(Bounds {
22183            origin: element_bounds.origin + point(x, y),
22184            size: size(em_width, line_height),
22185        })
22186    }
22187
22188    fn character_index_for_point(
22189        &mut self,
22190        point: gpui::Point<Pixels>,
22191        _window: &mut Window,
22192        _cx: &mut Context<Self>,
22193    ) -> Option<usize> {
22194        let position_map = self.last_position_map.as_ref()?;
22195        if !position_map.text_hitbox.contains(&point) {
22196            return None;
22197        }
22198        let display_point = position_map.point_for_position(point).previous_valid;
22199        let anchor = position_map
22200            .snapshot
22201            .display_point_to_anchor(display_point, Bias::Left);
22202        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22203        Some(utf16_offset.0)
22204    }
22205}
22206
22207trait SelectionExt {
22208    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22209    fn spanned_rows(
22210        &self,
22211        include_end_if_at_line_start: bool,
22212        map: &DisplaySnapshot,
22213    ) -> Range<MultiBufferRow>;
22214}
22215
22216impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22217    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22218        let start = self
22219            .start
22220            .to_point(&map.buffer_snapshot)
22221            .to_display_point(map);
22222        let end = self
22223            .end
22224            .to_point(&map.buffer_snapshot)
22225            .to_display_point(map);
22226        if self.reversed {
22227            end..start
22228        } else {
22229            start..end
22230        }
22231    }
22232
22233    fn spanned_rows(
22234        &self,
22235        include_end_if_at_line_start: bool,
22236        map: &DisplaySnapshot,
22237    ) -> Range<MultiBufferRow> {
22238        let start = self.start.to_point(&map.buffer_snapshot);
22239        let mut end = self.end.to_point(&map.buffer_snapshot);
22240        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22241            end.row -= 1;
22242        }
22243
22244        let buffer_start = map.prev_line_boundary(start).0;
22245        let buffer_end = map.next_line_boundary(end).0;
22246        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22247    }
22248}
22249
22250impl<T: InvalidationRegion> InvalidationStack<T> {
22251    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22252    where
22253        S: Clone + ToOffset,
22254    {
22255        while let Some(region) = self.last() {
22256            let all_selections_inside_invalidation_ranges =
22257                if selections.len() == region.ranges().len() {
22258                    selections
22259                        .iter()
22260                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22261                        .all(|(selection, invalidation_range)| {
22262                            let head = selection.head().to_offset(buffer);
22263                            invalidation_range.start <= head && invalidation_range.end >= head
22264                        })
22265                } else {
22266                    false
22267                };
22268
22269            if all_selections_inside_invalidation_ranges {
22270                break;
22271            } else {
22272                self.pop();
22273            }
22274        }
22275    }
22276}
22277
22278impl<T> Default for InvalidationStack<T> {
22279    fn default() -> Self {
22280        Self(Default::default())
22281    }
22282}
22283
22284impl<T> Deref for InvalidationStack<T> {
22285    type Target = Vec<T>;
22286
22287    fn deref(&self) -> &Self::Target {
22288        &self.0
22289    }
22290}
22291
22292impl<T> DerefMut for InvalidationStack<T> {
22293    fn deref_mut(&mut self) -> &mut Self::Target {
22294        &mut self.0
22295    }
22296}
22297
22298impl InvalidationRegion for SnippetState {
22299    fn ranges(&self) -> &[Range<Anchor>] {
22300        &self.ranges[self.active_index]
22301    }
22302}
22303
22304fn inline_completion_edit_text(
22305    current_snapshot: &BufferSnapshot,
22306    edits: &[(Range<Anchor>, String)],
22307    edit_preview: &EditPreview,
22308    include_deletions: bool,
22309    cx: &App,
22310) -> HighlightedText {
22311    let edits = edits
22312        .iter()
22313        .map(|(anchor, text)| {
22314            (
22315                anchor.start.text_anchor..anchor.end.text_anchor,
22316                text.clone(),
22317            )
22318        })
22319        .collect::<Vec<_>>();
22320
22321    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22322}
22323
22324pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22325    match severity {
22326        lsp::DiagnosticSeverity::ERROR => colors.error,
22327        lsp::DiagnosticSeverity::WARNING => colors.warning,
22328        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22329        lsp::DiagnosticSeverity::HINT => colors.info,
22330        _ => colors.ignored,
22331    }
22332}
22333
22334pub fn styled_runs_for_code_label<'a>(
22335    label: &'a CodeLabel,
22336    syntax_theme: &'a theme::SyntaxTheme,
22337) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22338    let fade_out = HighlightStyle {
22339        fade_out: Some(0.35),
22340        ..Default::default()
22341    };
22342
22343    let mut prev_end = label.filter_range.end;
22344    label
22345        .runs
22346        .iter()
22347        .enumerate()
22348        .flat_map(move |(ix, (range, highlight_id))| {
22349            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22350                style
22351            } else {
22352                return Default::default();
22353            };
22354            let mut muted_style = style;
22355            muted_style.highlight(fade_out);
22356
22357            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22358            if range.start >= label.filter_range.end {
22359                if range.start > prev_end {
22360                    runs.push((prev_end..range.start, fade_out));
22361                }
22362                runs.push((range.clone(), muted_style));
22363            } else if range.end <= label.filter_range.end {
22364                runs.push((range.clone(), style));
22365            } else {
22366                runs.push((range.start..label.filter_range.end, style));
22367                runs.push((label.filter_range.end..range.end, muted_style));
22368            }
22369            prev_end = cmp::max(prev_end, range.end);
22370
22371            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22372                runs.push((prev_end..label.text.len(), fade_out));
22373            }
22374
22375            runs
22376        })
22377}
22378
22379pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22380    let mut prev_index = 0;
22381    let mut prev_codepoint: Option<char> = None;
22382    text.char_indices()
22383        .chain([(text.len(), '\0')])
22384        .filter_map(move |(index, codepoint)| {
22385            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22386            let is_boundary = index == text.len()
22387                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22388                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22389            if is_boundary {
22390                let chunk = &text[prev_index..index];
22391                prev_index = index;
22392                Some(chunk)
22393            } else {
22394                None
22395            }
22396        })
22397}
22398
22399pub trait RangeToAnchorExt: Sized {
22400    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22401
22402    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22403        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22404        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22405    }
22406}
22407
22408impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22409    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22410        let start_offset = self.start.to_offset(snapshot);
22411        let end_offset = self.end.to_offset(snapshot);
22412        if start_offset == end_offset {
22413            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22414        } else {
22415            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22416        }
22417    }
22418}
22419
22420pub trait RowExt {
22421    fn as_f32(&self) -> f32;
22422
22423    fn next_row(&self) -> Self;
22424
22425    fn previous_row(&self) -> Self;
22426
22427    fn minus(&self, other: Self) -> u32;
22428}
22429
22430impl RowExt for DisplayRow {
22431    fn as_f32(&self) -> f32 {
22432        self.0 as f32
22433    }
22434
22435    fn next_row(&self) -> Self {
22436        Self(self.0 + 1)
22437    }
22438
22439    fn previous_row(&self) -> Self {
22440        Self(self.0.saturating_sub(1))
22441    }
22442
22443    fn minus(&self, other: Self) -> u32 {
22444        self.0 - other.0
22445    }
22446}
22447
22448impl RowExt for MultiBufferRow {
22449    fn as_f32(&self) -> f32 {
22450        self.0 as f32
22451    }
22452
22453    fn next_row(&self) -> Self {
22454        Self(self.0 + 1)
22455    }
22456
22457    fn previous_row(&self) -> Self {
22458        Self(self.0.saturating_sub(1))
22459    }
22460
22461    fn minus(&self, other: Self) -> u32 {
22462        self.0 - other.0
22463    }
22464}
22465
22466trait RowRangeExt {
22467    type Row;
22468
22469    fn len(&self) -> usize;
22470
22471    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22472}
22473
22474impl RowRangeExt for Range<MultiBufferRow> {
22475    type Row = MultiBufferRow;
22476
22477    fn len(&self) -> usize {
22478        (self.end.0 - self.start.0) as usize
22479    }
22480
22481    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22482        (self.start.0..self.end.0).map(MultiBufferRow)
22483    }
22484}
22485
22486impl RowRangeExt for Range<DisplayRow> {
22487    type Row = DisplayRow;
22488
22489    fn len(&self) -> usize {
22490        (self.end.0 - self.start.0) as usize
22491    }
22492
22493    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22494        (self.start.0..self.end.0).map(DisplayRow)
22495    }
22496}
22497
22498/// If select range has more than one line, we
22499/// just point the cursor to range.start.
22500fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22501    if range.start.row == range.end.row {
22502        range
22503    } else {
22504        range.start..range.start
22505    }
22506}
22507pub struct KillRing(ClipboardItem);
22508impl Global for KillRing {}
22509
22510const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22511
22512enum BreakpointPromptEditAction {
22513    Log,
22514    Condition,
22515    HitCondition,
22516}
22517
22518struct BreakpointPromptEditor {
22519    pub(crate) prompt: Entity<Editor>,
22520    editor: WeakEntity<Editor>,
22521    breakpoint_anchor: Anchor,
22522    breakpoint: Breakpoint,
22523    edit_action: BreakpointPromptEditAction,
22524    block_ids: HashSet<CustomBlockId>,
22525    editor_margins: Arc<Mutex<EditorMargins>>,
22526    _subscriptions: Vec<Subscription>,
22527}
22528
22529impl BreakpointPromptEditor {
22530    const MAX_LINES: u8 = 4;
22531
22532    fn new(
22533        editor: WeakEntity<Editor>,
22534        breakpoint_anchor: Anchor,
22535        breakpoint: Breakpoint,
22536        edit_action: BreakpointPromptEditAction,
22537        window: &mut Window,
22538        cx: &mut Context<Self>,
22539    ) -> Self {
22540        let base_text = match edit_action {
22541            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22542            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22543            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22544        }
22545        .map(|msg| msg.to_string())
22546        .unwrap_or_default();
22547
22548        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22549        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22550
22551        let prompt = cx.new(|cx| {
22552            let mut prompt = Editor::new(
22553                EditorMode::AutoHeight {
22554                    max_lines: Self::MAX_LINES as usize,
22555                },
22556                buffer,
22557                None,
22558                window,
22559                cx,
22560            );
22561            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22562            prompt.set_show_cursor_when_unfocused(false, cx);
22563            prompt.set_placeholder_text(
22564                match edit_action {
22565                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22566                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22567                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22568                },
22569                cx,
22570            );
22571
22572            prompt
22573        });
22574
22575        Self {
22576            prompt,
22577            editor,
22578            breakpoint_anchor,
22579            breakpoint,
22580            edit_action,
22581            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22582            block_ids: Default::default(),
22583            _subscriptions: vec![],
22584        }
22585    }
22586
22587    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22588        self.block_ids.extend(block_ids)
22589    }
22590
22591    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22592        if let Some(editor) = self.editor.upgrade() {
22593            let message = self
22594                .prompt
22595                .read(cx)
22596                .buffer
22597                .read(cx)
22598                .as_singleton()
22599                .expect("A multi buffer in breakpoint prompt isn't possible")
22600                .read(cx)
22601                .as_rope()
22602                .to_string();
22603
22604            editor.update(cx, |editor, cx| {
22605                editor.edit_breakpoint_at_anchor(
22606                    self.breakpoint_anchor,
22607                    self.breakpoint.clone(),
22608                    match self.edit_action {
22609                        BreakpointPromptEditAction::Log => {
22610                            BreakpointEditAction::EditLogMessage(message.into())
22611                        }
22612                        BreakpointPromptEditAction::Condition => {
22613                            BreakpointEditAction::EditCondition(message.into())
22614                        }
22615                        BreakpointPromptEditAction::HitCondition => {
22616                            BreakpointEditAction::EditHitCondition(message.into())
22617                        }
22618                    },
22619                    cx,
22620                );
22621
22622                editor.remove_blocks(self.block_ids.clone(), None, cx);
22623                cx.focus_self(window);
22624            });
22625        }
22626    }
22627
22628    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22629        self.editor
22630            .update(cx, |editor, cx| {
22631                editor.remove_blocks(self.block_ids.clone(), None, cx);
22632                window.focus(&editor.focus_handle);
22633            })
22634            .log_err();
22635    }
22636
22637    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22638        let settings = ThemeSettings::get_global(cx);
22639        let text_style = TextStyle {
22640            color: if self.prompt.read(cx).read_only(cx) {
22641                cx.theme().colors().text_disabled
22642            } else {
22643                cx.theme().colors().text
22644            },
22645            font_family: settings.buffer_font.family.clone(),
22646            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22647            font_size: settings.buffer_font_size(cx).into(),
22648            font_weight: settings.buffer_font.weight,
22649            line_height: relative(settings.buffer_line_height.value()),
22650            ..Default::default()
22651        };
22652        EditorElement::new(
22653            &self.prompt,
22654            EditorStyle {
22655                background: cx.theme().colors().editor_background,
22656                local_player: cx.theme().players().local(),
22657                text: text_style,
22658                ..Default::default()
22659            },
22660        )
22661    }
22662}
22663
22664impl Render for BreakpointPromptEditor {
22665    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22666        let editor_margins = *self.editor_margins.lock();
22667        let gutter_dimensions = editor_margins.gutter;
22668        h_flex()
22669            .key_context("Editor")
22670            .bg(cx.theme().colors().editor_background)
22671            .border_y_1()
22672            .border_color(cx.theme().status().info_border)
22673            .size_full()
22674            .py(window.line_height() / 2.5)
22675            .on_action(cx.listener(Self::confirm))
22676            .on_action(cx.listener(Self::cancel))
22677            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22678            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22679    }
22680}
22681
22682impl Focusable for BreakpointPromptEditor {
22683    fn focus_handle(&self, cx: &App) -> FocusHandle {
22684        self.prompt.focus_handle(cx)
22685    }
22686}
22687
22688fn all_edits_insertions_or_deletions(
22689    edits: &Vec<(Range<Anchor>, String)>,
22690    snapshot: &MultiBufferSnapshot,
22691) -> bool {
22692    let mut all_insertions = true;
22693    let mut all_deletions = true;
22694
22695    for (range, new_text) in edits.iter() {
22696        let range_is_empty = range.to_offset(&snapshot).is_empty();
22697        let text_is_empty = new_text.is_empty();
22698
22699        if range_is_empty != text_is_empty {
22700            if range_is_empty {
22701                all_deletions = false;
22702            } else {
22703                all_insertions = false;
22704            }
22705        } else {
22706            return false;
22707        }
22708
22709        if !all_insertions && !all_deletions {
22710            return false;
22711        }
22712    }
22713    all_insertions || all_deletions
22714}
22715
22716struct MissingEditPredictionKeybindingTooltip;
22717
22718impl Render for MissingEditPredictionKeybindingTooltip {
22719    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22720        ui::tooltip_container(window, cx, |container, _, cx| {
22721            container
22722                .flex_shrink_0()
22723                .max_w_80()
22724                .min_h(rems_from_px(124.))
22725                .justify_between()
22726                .child(
22727                    v_flex()
22728                        .flex_1()
22729                        .text_ui_sm(cx)
22730                        .child(Label::new("Conflict with Accept Keybinding"))
22731                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22732                )
22733                .child(
22734                    h_flex()
22735                        .pb_1()
22736                        .gap_1()
22737                        .items_end()
22738                        .w_full()
22739                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22740                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22741                        }))
22742                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22743                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22744                        })),
22745                )
22746        })
22747    }
22748}
22749
22750#[derive(Debug, Clone, Copy, PartialEq)]
22751pub struct LineHighlight {
22752    pub background: Background,
22753    pub border: Option<gpui::Hsla>,
22754    pub include_gutter: bool,
22755    pub type_id: Option<TypeId>,
22756}
22757
22758fn render_diff_hunk_controls(
22759    row: u32,
22760    status: &DiffHunkStatus,
22761    hunk_range: Range<Anchor>,
22762    is_created_file: bool,
22763    line_height: Pixels,
22764    editor: &Entity<Editor>,
22765    _window: &mut Window,
22766    cx: &mut App,
22767) -> AnyElement {
22768    h_flex()
22769        .h(line_height)
22770        .mr_1()
22771        .gap_1()
22772        .px_0p5()
22773        .pb_1()
22774        .border_x_1()
22775        .border_b_1()
22776        .border_color(cx.theme().colors().border_variant)
22777        .rounded_b_lg()
22778        .bg(cx.theme().colors().editor_background)
22779        .gap_1()
22780        .block_mouse_except_scroll()
22781        .shadow_md()
22782        .child(if status.has_secondary_hunk() {
22783            Button::new(("stage", row as u64), "Stage")
22784                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22785                .tooltip({
22786                    let focus_handle = editor.focus_handle(cx);
22787                    move |window, cx| {
22788                        Tooltip::for_action_in(
22789                            "Stage Hunk",
22790                            &::git::ToggleStaged,
22791                            &focus_handle,
22792                            window,
22793                            cx,
22794                        )
22795                    }
22796                })
22797                .on_click({
22798                    let editor = editor.clone();
22799                    move |_event, _window, cx| {
22800                        editor.update(cx, |editor, cx| {
22801                            editor.stage_or_unstage_diff_hunks(
22802                                true,
22803                                vec![hunk_range.start..hunk_range.start],
22804                                cx,
22805                            );
22806                        });
22807                    }
22808                })
22809        } else {
22810            Button::new(("unstage", row as u64), "Unstage")
22811                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22812                .tooltip({
22813                    let focus_handle = editor.focus_handle(cx);
22814                    move |window, cx| {
22815                        Tooltip::for_action_in(
22816                            "Unstage Hunk",
22817                            &::git::ToggleStaged,
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                            editor.stage_or_unstage_diff_hunks(
22829                                false,
22830                                vec![hunk_range.start..hunk_range.start],
22831                                cx,
22832                            );
22833                        });
22834                    }
22835                })
22836        })
22837        .child(
22838            Button::new(("restore", row as u64), "Restore")
22839                .tooltip({
22840                    let focus_handle = editor.focus_handle(cx);
22841                    move |window, cx| {
22842                        Tooltip::for_action_in(
22843                            "Restore Hunk",
22844                            &::git::Restore,
22845                            &focus_handle,
22846                            window,
22847                            cx,
22848                        )
22849                    }
22850                })
22851                .on_click({
22852                    let editor = editor.clone();
22853                    move |_event, window, cx| {
22854                        editor.update(cx, |editor, cx| {
22855                            let snapshot = editor.snapshot(window, cx);
22856                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22857                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22858                        });
22859                    }
22860                })
22861                .disabled(is_created_file),
22862        )
22863        .when(
22864            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22865            |el| {
22866                el.child(
22867                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22868                        .shape(IconButtonShape::Square)
22869                        .icon_size(IconSize::Small)
22870                        // .disabled(!has_multiple_hunks)
22871                        .tooltip({
22872                            let focus_handle = editor.focus_handle(cx);
22873                            move |window, cx| {
22874                                Tooltip::for_action_in(
22875                                    "Next Hunk",
22876                                    &GoToHunk,
22877                                    &focus_handle,
22878                                    window,
22879                                    cx,
22880                                )
22881                            }
22882                        })
22883                        .on_click({
22884                            let editor = editor.clone();
22885                            move |_event, window, cx| {
22886                                editor.update(cx, |editor, cx| {
22887                                    let snapshot = editor.snapshot(window, cx);
22888                                    let position =
22889                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22890                                    editor.go_to_hunk_before_or_after_position(
22891                                        &snapshot,
22892                                        position,
22893                                        Direction::Next,
22894                                        window,
22895                                        cx,
22896                                    );
22897                                    editor.expand_selected_diff_hunks(cx);
22898                                });
22899                            }
22900                        }),
22901                )
22902                .child(
22903                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22904                        .shape(IconButtonShape::Square)
22905                        .icon_size(IconSize::Small)
22906                        // .disabled(!has_multiple_hunks)
22907                        .tooltip({
22908                            let focus_handle = editor.focus_handle(cx);
22909                            move |window, cx| {
22910                                Tooltip::for_action_in(
22911                                    "Previous Hunk",
22912                                    &GoToPreviousHunk,
22913                                    &focus_handle,
22914                                    window,
22915                                    cx,
22916                                )
22917                            }
22918                        })
22919                        .on_click({
22920                            let editor = editor.clone();
22921                            move |_event, window, cx| {
22922                                editor.update(cx, |editor, cx| {
22923                                    let snapshot = editor.snapshot(window, cx);
22924                                    let point =
22925                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22926                                    editor.go_to_hunk_before_or_after_position(
22927                                        &snapshot,
22928                                        point,
22929                                        Direction::Prev,
22930                                        window,
22931                                        cx,
22932                                    );
22933                                    editor.expand_selected_diff_hunks(cx);
22934                                });
22935                            }
22936                        }),
22937                )
22938            },
22939        )
22940        .into_any_element()
22941}