editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes,
   67    SearchSettings, ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82
   83use ::git::blame::BlameEntry;
   84use ::git::{Restore, blame::ParsedCommitMessage};
   85use code_context_menus::{
   86    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   87    CompletionsMenu, ContextMenuOrigin,
   88};
   89use git::blame::{GitBlame, GlobalBlameRenderer};
   90use gpui::{
   91    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   92    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   93    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   94    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   95    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   96    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   97    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   98    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   99};
  100use highlight_matching_bracket::refresh_matching_bracket_highlights;
  101use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  102pub use hover_popover::hover_markdown_style;
  103use hover_popover::{HoverState, hide_hover};
  104use indent_guides::ActiveIndentGuidesState;
  105use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  106pub use inline_completion::Direction;
  107use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  108pub use items::MAX_TAB_TITLE_LEN;
  109use itertools::Itertools;
  110use language::{
  111    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  112    CursorShape, DiagnosticEntry, DiagnosticSourceKind, DiffOptions, DocumentationConfig,
  113    EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize, Language,
  114    OffsetRangeExt, Point, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
  115    WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, LspPullDiagnostics, ProjectPath, PulledDiagnostics,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    project_settings::DiagnosticSeverity,
  137};
  138
  139pub use git::blame::BlameRenderer;
  140pub use proposed_changes_editor::{
  141    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  142};
  143use std::{cell::OnceCell, iter::Peekable, ops::Not};
  144use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  145
  146pub use lsp::CompletionContext;
  147use lsp::{
  148    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  149    LanguageServerId, LanguageServerName,
  150};
  151
  152use language::BufferSnapshot;
  153pub use lsp_ext::lsp_tasks;
  154use movement::TextLayoutDetails;
  155pub use multi_buffer::{
  156    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  157    RowInfo, ToOffset, ToPoint,
  158};
  159use multi_buffer::{
  160    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  161    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  162};
  163use parking_lot::Mutex;
  164use project::{
  165    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  166    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  167    TaskSourceKind,
  168    debugger::breakpoint_store::Breakpoint,
  169    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  170    project_settings::{GitGutterSetting, ProjectSettings},
  171};
  172use rand::prelude::*;
  173use rpc::{ErrorExt, proto::*};
  174use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  175use selections_collection::{
  176    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  177};
  178use serde::{Deserialize, Serialize};
  179use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  180use smallvec::{SmallVec, smallvec};
  181use snippet::Snippet;
  182use std::sync::Arc;
  183use std::{
  184    any::TypeId,
  185    borrow::Cow,
  186    cell::RefCell,
  187    cmp::{self, Ordering, Reverse},
  188    mem,
  189    num::NonZeroU32,
  190    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  191    path::{Path, PathBuf},
  192    rc::Rc,
  193    time::{Duration, Instant},
  194};
  195pub use sum_tree::Bias;
  196use sum_tree::TreeMap;
  197use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  198use theme::{
  199    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  200    observe_buffer_font_size_adjustment,
  201};
  202use ui::{
  203    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  204    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  205};
  206use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  207use workspace::{
  208    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  209    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  210    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  211    item::{ItemHandle, PreviewTabsSettings},
  212    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  213    searchable::SearchEvent,
  214};
  215
  216use crate::{
  217    code_context_menus::CompletionsMenuSource,
  218    hover_links::{find_url, find_url_from_range},
  219};
  220use crate::{
  221    editor_settings::MultiCursorModifier,
  222    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  223};
  224
  225pub const FILE_HEADER_HEIGHT: u32 = 2;
  226pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  227pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  228const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  229const MAX_LINE_LEN: usize = 1024;
  230const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  231const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  232pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  233#[doc(hidden)]
  234pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  235const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  236
  237pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  238pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  240
  241pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  242pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  243pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  244
  245pub type RenderDiffHunkControlsFn = Arc<
  246    dyn Fn(
  247        u32,
  248        &DiffHunkStatus,
  249        Range<Anchor>,
  250        bool,
  251        Pixels,
  252        &Entity<Editor>,
  253        &mut Window,
  254        &mut App,
  255    ) -> AnyElement,
  256>;
  257
  258struct InlineValueCache {
  259    enabled: bool,
  260    inlays: Vec<InlayId>,
  261    refresh_task: Task<Option<()>>,
  262}
  263
  264impl InlineValueCache {
  265    fn new(enabled: bool) -> Self {
  266        Self {
  267            enabled,
  268            inlays: Vec::new(),
  269            refresh_task: Task::ready(None),
  270        }
  271    }
  272}
  273
  274#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  275pub enum InlayId {
  276    InlineCompletion(usize),
  277    Hint(usize),
  278    DebuggerValue(usize),
  279}
  280
  281impl InlayId {
  282    fn id(&self) -> usize {
  283        match self {
  284            Self::InlineCompletion(id) => *id,
  285            Self::Hint(id) => *id,
  286            Self::DebuggerValue(id) => *id,
  287        }
  288    }
  289}
  290
  291pub enum ActiveDebugLine {}
  292pub enum DebugStackFrameLine {}
  293enum DocumentHighlightRead {}
  294enum DocumentHighlightWrite {}
  295enum InputComposition {}
  296pub enum PendingInput {}
  297enum SelectedTextHighlight {}
  298
  299pub enum ConflictsOuter {}
  300pub enum ConflictsOurs {}
  301pub enum ConflictsTheirs {}
  302pub enum ConflictsOursMarker {}
  303pub enum ConflictsTheirsMarker {}
  304
  305#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  306pub enum Navigated {
  307    Yes,
  308    No,
  309}
  310
  311impl Navigated {
  312    pub fn from_bool(yes: bool) -> Navigated {
  313        if yes { Navigated::Yes } else { Navigated::No }
  314    }
  315}
  316
  317#[derive(Debug, Clone, PartialEq, Eq)]
  318enum DisplayDiffHunk {
  319    Folded {
  320        display_row: DisplayRow,
  321    },
  322    Unfolded {
  323        is_created_file: bool,
  324        diff_base_byte_range: Range<usize>,
  325        display_row_range: Range<DisplayRow>,
  326        multi_buffer_range: Range<Anchor>,
  327        status: DiffHunkStatus,
  328    },
  329}
  330
  331pub enum HideMouseCursorOrigin {
  332    TypingAction,
  333    MovementAction,
  334}
  335
  336pub fn init_settings(cx: &mut App) {
  337    EditorSettings::register(cx);
  338}
  339
  340pub fn init(cx: &mut App) {
  341    init_settings(cx);
  342
  343    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  344
  345    workspace::register_project_item::<Editor>(cx);
  346    workspace::FollowableViewRegistry::register::<Editor>(cx);
  347    workspace::register_serializable_item::<Editor>(cx);
  348
  349    cx.observe_new(
  350        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  351            workspace.register_action(Editor::new_file);
  352            workspace.register_action(Editor::new_file_vertical);
  353            workspace.register_action(Editor::new_file_horizontal);
  354            workspace.register_action(Editor::cancel_language_server_work);
  355        },
  356    )
  357    .detach();
  358
  359    cx.on_action(move |_: &workspace::NewFile, cx| {
  360        let app_state = workspace::AppState::global(cx);
  361        if let Some(app_state) = app_state.upgrade() {
  362            workspace::open_new(
  363                Default::default(),
  364                app_state,
  365                cx,
  366                |workspace, window, cx| {
  367                    Editor::new_file(workspace, &Default::default(), window, cx)
  368                },
  369            )
  370            .detach();
  371        }
  372    });
  373    cx.on_action(move |_: &workspace::NewWindow, cx| {
  374        let app_state = workspace::AppState::global(cx);
  375        if let Some(app_state) = app_state.upgrade() {
  376            workspace::open_new(
  377                Default::default(),
  378                app_state,
  379                cx,
  380                |workspace, window, cx| {
  381                    cx.activate(true);
  382                    Editor::new_file(workspace, &Default::default(), window, cx)
  383                },
  384            )
  385            .detach();
  386        }
  387    });
  388}
  389
  390pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  391    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  392}
  393
  394pub trait DiagnosticRenderer {
  395    fn render_group(
  396        &self,
  397        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  398        buffer_id: BufferId,
  399        snapshot: EditorSnapshot,
  400        editor: WeakEntity<Editor>,
  401        cx: &mut App,
  402    ) -> Vec<BlockProperties<Anchor>>;
  403
  404    fn render_hover(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  407        range: Range<Point>,
  408        buffer_id: BufferId,
  409        cx: &mut App,
  410    ) -> Option<Entity<markdown::Markdown>>;
  411
  412    fn open_link(
  413        &self,
  414        editor: &mut Editor,
  415        link: SharedString,
  416        window: &mut Window,
  417        cx: &mut Context<Editor>,
  418    );
  419}
  420
  421pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  422
  423impl GlobalDiagnosticRenderer {
  424    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  425        cx.try_global::<Self>().map(|g| g.0.clone())
  426    }
  427}
  428
  429impl gpui::Global for GlobalDiagnosticRenderer {}
  430pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  431    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  432}
  433
  434pub struct SearchWithinRange;
  435
  436trait InvalidationRegion {
  437    fn ranges(&self) -> &[Range<Anchor>];
  438}
  439
  440#[derive(Clone, Debug, PartialEq)]
  441pub enum SelectPhase {
  442    Begin {
  443        position: DisplayPoint,
  444        add: bool,
  445        click_count: usize,
  446    },
  447    BeginColumnar {
  448        position: DisplayPoint,
  449        reset: bool,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug)]
  465pub enum SelectMode {
  466    Character,
  467    Word(Range<Anchor>),
  468    Line(Range<Anchor>),
  469    All,
  470}
  471
  472#[derive(Clone, PartialEq, Eq, Debug)]
  473pub enum EditorMode {
  474    SingleLine {
  475        auto_width: bool,
  476    },
  477    AutoHeight {
  478        max_lines: usize,
  479    },
  480    Full {
  481        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  482        scale_ui_elements_with_buffer_font_size: bool,
  483        /// When set to `true`, the editor will render a background for the active line.
  484        show_active_line_background: bool,
  485        /// When set to `true`, the editor's height will be determined by its content.
  486        sized_by_content: bool,
  487    },
  488    Minimap {
  489        parent: WeakEntity<Editor>,
  490    },
  491}
  492
  493impl EditorMode {
  494    pub fn full() -> Self {
  495        Self::Full {
  496            scale_ui_elements_with_buffer_font_size: true,
  497            show_active_line_background: true,
  498            sized_by_content: false,
  499        }
  500    }
  501
  502    pub fn is_full(&self) -> bool {
  503        matches!(self, Self::Full { .. })
  504    }
  505
  506    fn is_minimap(&self) -> bool {
  507        matches!(self, Self::Minimap { .. })
  508    }
  509}
  510
  511#[derive(Copy, Clone, Debug)]
  512pub enum SoftWrap {
  513    /// Prefer not to wrap at all.
  514    ///
  515    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  516    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  517    GitDiff,
  518    /// Prefer a single line generally, unless an overly long line is encountered.
  519    None,
  520    /// Soft wrap lines that exceed the editor width.
  521    EditorWidth,
  522    /// Soft wrap lines at the preferred line length.
  523    Column(u32),
  524    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  525    Bounded(u32),
  526}
  527
  528#[derive(Clone)]
  529pub struct EditorStyle {
  530    pub background: Hsla,
  531    pub local_player: PlayerColor,
  532    pub text: TextStyle,
  533    pub scrollbar_width: Pixels,
  534    pub syntax: Arc<SyntaxTheme>,
  535    pub status: StatusColors,
  536    pub inlay_hints_style: HighlightStyle,
  537    pub inline_completion_styles: InlineCompletionStyles,
  538    pub unnecessary_code_fade: f32,
  539    pub show_underlines: bool,
  540}
  541
  542impl Default for EditorStyle {
  543    fn default() -> Self {
  544        Self {
  545            background: Hsla::default(),
  546            local_player: PlayerColor::default(),
  547            text: TextStyle::default(),
  548            scrollbar_width: Pixels::default(),
  549            syntax: Default::default(),
  550            // HACK: Status colors don't have a real default.
  551            // We should look into removing the status colors from the editor
  552            // style and retrieve them directly from the theme.
  553            status: StatusColors::dark(),
  554            inlay_hints_style: HighlightStyle::default(),
  555            inline_completion_styles: InlineCompletionStyles {
  556                insertion: HighlightStyle::default(),
  557                whitespace: HighlightStyle::default(),
  558            },
  559            unnecessary_code_fade: Default::default(),
  560            show_underlines: true,
  561        }
  562    }
  563}
  564
  565pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  566    let show_background = language_settings::language_settings(None, None, cx)
  567        .inlay_hints
  568        .show_background;
  569
  570    HighlightStyle {
  571        color: Some(cx.theme().status().hint),
  572        background_color: show_background.then(|| cx.theme().status().hint_background),
  573        ..HighlightStyle::default()
  574    }
  575}
  576
  577pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  578    InlineCompletionStyles {
  579        insertion: HighlightStyle {
  580            color: Some(cx.theme().status().predictive),
  581            ..HighlightStyle::default()
  582        },
  583        whitespace: HighlightStyle {
  584            background_color: Some(cx.theme().status().created_background),
  585            ..HighlightStyle::default()
  586        },
  587    }
  588}
  589
  590type CompletionId = usize;
  591
  592pub(crate) enum EditDisplayMode {
  593    TabAccept,
  594    DiffPopover,
  595    Inline,
  596}
  597
  598enum InlineCompletion {
  599    Edit {
  600        edits: Vec<(Range<Anchor>, String)>,
  601        edit_preview: Option<EditPreview>,
  602        display_mode: EditDisplayMode,
  603        snapshot: BufferSnapshot,
  604    },
  605    Move {
  606        target: Anchor,
  607        snapshot: BufferSnapshot,
  608    },
  609}
  610
  611struct InlineCompletionState {
  612    inlay_ids: Vec<InlayId>,
  613    completion: InlineCompletion,
  614    completion_id: Option<SharedString>,
  615    invalidation_range: Range<Anchor>,
  616}
  617
  618enum EditPredictionSettings {
  619    Disabled,
  620    Enabled {
  621        show_in_menu: bool,
  622        preview_requires_modifier: bool,
  623    },
  624}
  625
  626enum InlineCompletionHighlight {}
  627
  628#[derive(Debug, Clone)]
  629struct InlineDiagnostic {
  630    message: SharedString,
  631    group_id: usize,
  632    is_primary: bool,
  633    start: Point,
  634    severity: lsp::DiagnosticSeverity,
  635}
  636
  637pub enum MenuInlineCompletionsPolicy {
  638    Never,
  639    ByProvider,
  640}
  641
  642pub enum EditPredictionPreview {
  643    /// Modifier is not pressed
  644    Inactive { released_too_fast: bool },
  645    /// Modifier pressed
  646    Active {
  647        since: Instant,
  648        previous_scroll_position: Option<ScrollAnchor>,
  649    },
  650}
  651
  652impl EditPredictionPreview {
  653    pub fn released_too_fast(&self) -> bool {
  654        match self {
  655            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  656            EditPredictionPreview::Active { .. } => false,
  657        }
  658    }
  659
  660    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  661        if let EditPredictionPreview::Active {
  662            previous_scroll_position,
  663            ..
  664        } = self
  665        {
  666            *previous_scroll_position = scroll_position;
  667        }
  668    }
  669}
  670
  671pub struct ContextMenuOptions {
  672    pub min_entries_visible: usize,
  673    pub max_entries_visible: usize,
  674    pub placement: Option<ContextMenuPlacement>,
  675}
  676
  677#[derive(Debug, Clone, PartialEq, Eq)]
  678pub enum ContextMenuPlacement {
  679    Above,
  680    Below,
  681}
  682
  683#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  684struct EditorActionId(usize);
  685
  686impl EditorActionId {
  687    pub fn post_inc(&mut self) -> Self {
  688        let answer = self.0;
  689
  690        *self = Self(answer + 1);
  691
  692        Self(answer)
  693    }
  694}
  695
  696// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  697// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  698
  699type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  700type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  701
  702#[derive(Default)]
  703struct ScrollbarMarkerState {
  704    scrollbar_size: Size<Pixels>,
  705    dirty: bool,
  706    markers: Arc<[PaintQuad]>,
  707    pending_refresh: Option<Task<Result<()>>>,
  708}
  709
  710impl ScrollbarMarkerState {
  711    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  712        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  713    }
  714}
  715
  716#[derive(Clone, Copy, PartialEq, Eq)]
  717pub enum MinimapVisibility {
  718    Disabled,
  719    Enabled {
  720        /// The configuration currently present in the users settings.
  721        setting_configuration: bool,
  722        /// Whether to override the currently set visibility from the users setting.
  723        toggle_override: bool,
  724    },
  725}
  726
  727impl MinimapVisibility {
  728    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  729        if mode.is_full() {
  730            Self::Enabled {
  731                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  732                toggle_override: false,
  733            }
  734        } else {
  735            Self::Disabled
  736        }
  737    }
  738
  739    fn hidden(&self) -> Self {
  740        match *self {
  741            Self::Enabled {
  742                setting_configuration,
  743                ..
  744            } => Self::Enabled {
  745                setting_configuration,
  746                toggle_override: setting_configuration,
  747            },
  748            Self::Disabled => Self::Disabled,
  749        }
  750    }
  751
  752    fn disabled(&self) -> bool {
  753        match *self {
  754            Self::Disabled => true,
  755            _ => false,
  756        }
  757    }
  758
  759    fn settings_visibility(&self) -> bool {
  760        match *self {
  761            Self::Enabled {
  762                setting_configuration,
  763                ..
  764            } => setting_configuration,
  765            _ => false,
  766        }
  767    }
  768
  769    fn visible(&self) -> bool {
  770        match *self {
  771            Self::Enabled {
  772                setting_configuration,
  773                toggle_override,
  774            } => setting_configuration ^ toggle_override,
  775            _ => false,
  776        }
  777    }
  778
  779    fn toggle_visibility(&self) -> Self {
  780        match *self {
  781            Self::Enabled {
  782                toggle_override,
  783                setting_configuration,
  784            } => Self::Enabled {
  785                setting_configuration,
  786                toggle_override: !toggle_override,
  787            },
  788            Self::Disabled => Self::Disabled,
  789        }
  790    }
  791}
  792
  793#[derive(Clone, Debug)]
  794struct RunnableTasks {
  795    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  796    offset: multi_buffer::Anchor,
  797    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  798    column: u32,
  799    // Values of all named captures, including those starting with '_'
  800    extra_variables: HashMap<String, String>,
  801    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  802    context_range: Range<BufferOffset>,
  803}
  804
  805impl RunnableTasks {
  806    fn resolve<'a>(
  807        &'a self,
  808        cx: &'a task::TaskContext,
  809    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  810        self.templates.iter().filter_map(|(kind, template)| {
  811            template
  812                .resolve_task(&kind.to_id_base(), cx)
  813                .map(|task| (kind.clone(), task))
  814        })
  815    }
  816}
  817
  818#[derive(Clone)]
  819pub struct ResolvedTasks {
  820    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  821    position: Anchor,
  822}
  823
  824#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  825struct BufferOffset(usize);
  826
  827// Addons allow storing per-editor state in other crates (e.g. Vim)
  828pub trait Addon: 'static {
  829    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  830
  831    fn render_buffer_header_controls(
  832        &self,
  833        _: &ExcerptInfo,
  834        _: &Window,
  835        _: &App,
  836    ) -> Option<AnyElement> {
  837        None
  838    }
  839
  840    fn to_any(&self) -> &dyn std::any::Any;
  841
  842    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  843        None
  844    }
  845}
  846
  847/// A set of caret positions, registered when the editor was edited.
  848pub struct ChangeList {
  849    changes: Vec<Vec<Anchor>>,
  850    /// Currently "selected" change.
  851    position: Option<usize>,
  852}
  853
  854impl ChangeList {
  855    pub fn new() -> Self {
  856        Self {
  857            changes: Vec::new(),
  858            position: None,
  859        }
  860    }
  861
  862    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  863    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  864    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  865        if self.changes.is_empty() {
  866            return None;
  867        }
  868
  869        let prev = self.position.unwrap_or(self.changes.len());
  870        let next = if direction == Direction::Prev {
  871            prev.saturating_sub(count)
  872        } else {
  873            (prev + count).min(self.changes.len() - 1)
  874        };
  875        self.position = Some(next);
  876        self.changes.get(next).map(|anchors| anchors.as_slice())
  877    }
  878
  879    /// Adds a new change to the list, resetting the change list position.
  880    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  881        self.position.take();
  882        if pop_state {
  883            self.changes.pop();
  884        }
  885        self.changes.push(new_positions.clone());
  886    }
  887
  888    pub fn last(&self) -> Option<&[Anchor]> {
  889        self.changes.last().map(|anchors| anchors.as_slice())
  890    }
  891}
  892
  893#[derive(Clone)]
  894struct InlineBlamePopoverState {
  895    scroll_handle: ScrollHandle,
  896    commit_message: Option<ParsedCommitMessage>,
  897    markdown: Entity<Markdown>,
  898}
  899
  900struct InlineBlamePopover {
  901    position: gpui::Point<Pixels>,
  902    show_task: Option<Task<()>>,
  903    hide_task: Option<Task<()>>,
  904    popover_bounds: Option<Bounds<Pixels>>,
  905    popover_state: InlineBlamePopoverState,
  906}
  907
  908enum SelectionDragState {
  909    /// State when no drag related activity is detected.
  910    None,
  911    /// State when the mouse is down on a selection that is about to be dragged.
  912    ReadyToDrag {
  913        selection: Selection<Anchor>,
  914        click_position: gpui::Point<Pixels>,
  915    },
  916    /// State when the mouse is dragging the selection in the editor.
  917    Dragging {
  918        selection: Selection<Anchor>,
  919        drop_cursor: Selection<Anchor>,
  920        hide_drop_cursor: bool,
  921    },
  922}
  923
  924/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  925/// a breakpoint on them.
  926#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  927struct PhantomBreakpointIndicator {
  928    display_row: DisplayRow,
  929    /// There's a small debounce between hovering over the line and showing the indicator.
  930    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  931    is_active: bool,
  932    collides_with_existing_breakpoint: bool,
  933}
  934
  935/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  936///
  937/// See the [module level documentation](self) for more information.
  938pub struct Editor {
  939    focus_handle: FocusHandle,
  940    last_focused_descendant: Option<WeakFocusHandle>,
  941    /// The text buffer being edited
  942    buffer: Entity<MultiBuffer>,
  943    /// Map of how text in the buffer should be displayed.
  944    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  945    pub display_map: Entity<DisplayMap>,
  946    pub selections: SelectionsCollection,
  947    pub scroll_manager: ScrollManager,
  948    /// When inline assist editors are linked, they all render cursors because
  949    /// typing enters text into each of them, even the ones that aren't focused.
  950    pub(crate) show_cursor_when_unfocused: bool,
  951    columnar_selection_tail: Option<Anchor>,
  952    columnar_display_point: Option<DisplayPoint>,
  953    add_selections_state: Option<AddSelectionsState>,
  954    select_next_state: Option<SelectNextState>,
  955    select_prev_state: Option<SelectNextState>,
  956    selection_history: SelectionHistory,
  957    defer_selection_effects: bool,
  958    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  959    autoclose_regions: Vec<AutocloseRegion>,
  960    snippet_stack: InvalidationStack<SnippetState>,
  961    select_syntax_node_history: SelectSyntaxNodeHistory,
  962    ime_transaction: Option<TransactionId>,
  963    pub diagnostics_max_severity: DiagnosticSeverity,
  964    active_diagnostics: ActiveDiagnostic,
  965    show_inline_diagnostics: bool,
  966    inline_diagnostics_update: Task<()>,
  967    inline_diagnostics_enabled: bool,
  968    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  969    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  970    hard_wrap: Option<usize>,
  971
  972    // TODO: make this a access method
  973    pub project: Option<Entity<Project>>,
  974    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  975    completion_provider: Option<Rc<dyn CompletionProvider>>,
  976    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  977    blink_manager: Entity<BlinkManager>,
  978    show_cursor_names: bool,
  979    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  980    pub show_local_selections: bool,
  981    mode: EditorMode,
  982    show_breadcrumbs: bool,
  983    show_gutter: bool,
  984    show_scrollbars: ScrollbarAxes,
  985    minimap_visibility: MinimapVisibility,
  986    offset_content: bool,
  987    disable_expand_excerpt_buttons: bool,
  988    show_line_numbers: Option<bool>,
  989    use_relative_line_numbers: Option<bool>,
  990    show_git_diff_gutter: Option<bool>,
  991    show_code_actions: Option<bool>,
  992    show_runnables: Option<bool>,
  993    show_breakpoints: Option<bool>,
  994    show_wrap_guides: Option<bool>,
  995    show_indent_guides: Option<bool>,
  996    placeholder_text: Option<Arc<str>>,
  997    highlight_order: usize,
  998    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  999    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
 1000    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1001    scrollbar_marker_state: ScrollbarMarkerState,
 1002    active_indent_guides_state: ActiveIndentGuidesState,
 1003    nav_history: Option<ItemNavHistory>,
 1004    context_menu: RefCell<Option<CodeContextMenu>>,
 1005    context_menu_options: Option<ContextMenuOptions>,
 1006    mouse_context_menu: Option<MouseContextMenu>,
 1007    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1008    inline_blame_popover: Option<InlineBlamePopover>,
 1009    signature_help_state: SignatureHelpState,
 1010    auto_signature_help: Option<bool>,
 1011    find_all_references_task_sources: Vec<Anchor>,
 1012    next_completion_id: CompletionId,
 1013    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1014    code_actions_task: Option<Task<Result<()>>>,
 1015    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1016    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1017    document_highlights_task: Option<Task<()>>,
 1018    linked_editing_range_task: Option<Task<Option<()>>>,
 1019    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1020    pending_rename: Option<RenameState>,
 1021    searchable: bool,
 1022    cursor_shape: CursorShape,
 1023    current_line_highlight: Option<CurrentLineHighlight>,
 1024    collapse_matches: bool,
 1025    autoindent_mode: Option<AutoindentMode>,
 1026    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1027    input_enabled: bool,
 1028    use_modal_editing: bool,
 1029    read_only: bool,
 1030    leader_id: Option<CollaboratorId>,
 1031    remote_id: Option<ViewId>,
 1032    pub hover_state: HoverState,
 1033    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1034    gutter_hovered: bool,
 1035    hovered_link_state: Option<HoveredLinkState>,
 1036    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1037    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1038    active_inline_completion: Option<InlineCompletionState>,
 1039    /// Used to prevent flickering as the user types while the menu is open
 1040    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1041    edit_prediction_settings: EditPredictionSettings,
 1042    inline_completions_hidden_for_vim_mode: bool,
 1043    show_inline_completions_override: Option<bool>,
 1044    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1045    edit_prediction_preview: EditPredictionPreview,
 1046    edit_prediction_indent_conflict: bool,
 1047    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1048    inlay_hint_cache: InlayHintCache,
 1049    next_inlay_id: usize,
 1050    _subscriptions: Vec<Subscription>,
 1051    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1052    gutter_dimensions: GutterDimensions,
 1053    style: Option<EditorStyle>,
 1054    text_style_refinement: Option<TextStyleRefinement>,
 1055    next_editor_action_id: EditorActionId,
 1056    editor_actions: Rc<
 1057        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1058    >,
 1059    use_autoclose: bool,
 1060    use_auto_surround: bool,
 1061    auto_replace_emoji_shortcode: bool,
 1062    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1063    show_git_blame_gutter: bool,
 1064    show_git_blame_inline: bool,
 1065    show_git_blame_inline_delay_task: Option<Task<()>>,
 1066    git_blame_inline_enabled: bool,
 1067    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1068    serialize_dirty_buffers: bool,
 1069    show_selection_menu: Option<bool>,
 1070    blame: Option<Entity<GitBlame>>,
 1071    blame_subscription: Option<Subscription>,
 1072    custom_context_menu: Option<
 1073        Box<
 1074            dyn 'static
 1075                + Fn(
 1076                    &mut Self,
 1077                    DisplayPoint,
 1078                    &mut Window,
 1079                    &mut Context<Self>,
 1080                ) -> Option<Entity<ui::ContextMenu>>,
 1081        >,
 1082    >,
 1083    last_bounds: Option<Bounds<Pixels>>,
 1084    last_position_map: Option<Rc<PositionMap>>,
 1085    expect_bounds_change: Option<Bounds<Pixels>>,
 1086    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1087    tasks_update_task: Option<Task<()>>,
 1088    breakpoint_store: Option<Entity<BreakpointStore>>,
 1089    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1090    pull_diagnostics_task: Task<()>,
 1091    in_project_search: bool,
 1092    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1093    breadcrumb_header: Option<String>,
 1094    focused_block: Option<FocusedBlock>,
 1095    next_scroll_position: NextScrollCursorCenterTopBottom,
 1096    addons: HashMap<TypeId, Box<dyn Addon>>,
 1097    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1098    load_diff_task: Option<Shared<Task<()>>>,
 1099    /// Whether we are temporarily displaying a diff other than git's
 1100    temporary_diff_override: bool,
 1101    selection_mark_mode: bool,
 1102    toggle_fold_multiple_buffers: Task<()>,
 1103    _scroll_cursor_center_top_bottom_task: Task<()>,
 1104    serialize_selections: Task<()>,
 1105    serialize_folds: Task<()>,
 1106    mouse_cursor_hidden: bool,
 1107    minimap: Option<Entity<Self>>,
 1108    hide_mouse_mode: HideMouseMode,
 1109    pub change_list: ChangeList,
 1110    inline_value_cache: InlineValueCache,
 1111    selection_drag_state: SelectionDragState,
 1112    drag_and_drop_selection_enabled: bool,
 1113}
 1114
 1115#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1116enum NextScrollCursorCenterTopBottom {
 1117    #[default]
 1118    Center,
 1119    Top,
 1120    Bottom,
 1121}
 1122
 1123impl NextScrollCursorCenterTopBottom {
 1124    fn next(&self) -> Self {
 1125        match self {
 1126            Self::Center => Self::Top,
 1127            Self::Top => Self::Bottom,
 1128            Self::Bottom => Self::Center,
 1129        }
 1130    }
 1131}
 1132
 1133#[derive(Clone)]
 1134pub struct EditorSnapshot {
 1135    pub mode: EditorMode,
 1136    show_gutter: bool,
 1137    show_line_numbers: Option<bool>,
 1138    show_git_diff_gutter: Option<bool>,
 1139    show_code_actions: Option<bool>,
 1140    show_runnables: Option<bool>,
 1141    show_breakpoints: Option<bool>,
 1142    git_blame_gutter_max_author_length: Option<usize>,
 1143    pub display_snapshot: DisplaySnapshot,
 1144    pub placeholder_text: Option<Arc<str>>,
 1145    is_focused: bool,
 1146    scroll_anchor: ScrollAnchor,
 1147    ongoing_scroll: OngoingScroll,
 1148    current_line_highlight: CurrentLineHighlight,
 1149    gutter_hovered: bool,
 1150}
 1151
 1152#[derive(Default, Debug, Clone, Copy)]
 1153pub struct GutterDimensions {
 1154    pub left_padding: Pixels,
 1155    pub right_padding: Pixels,
 1156    pub width: Pixels,
 1157    pub margin: Pixels,
 1158    pub git_blame_entries_width: Option<Pixels>,
 1159}
 1160
 1161impl GutterDimensions {
 1162    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1163        Self {
 1164            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1165            ..Default::default()
 1166        }
 1167    }
 1168
 1169    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1170        -cx.text_system().descent(font_id, font_size)
 1171    }
 1172    /// The full width of the space taken up by the gutter.
 1173    pub fn full_width(&self) -> Pixels {
 1174        self.margin + self.width
 1175    }
 1176
 1177    /// The width of the space reserved for the fold indicators,
 1178    /// use alongside 'justify_end' and `gutter_width` to
 1179    /// right align content with the line numbers
 1180    pub fn fold_area_width(&self) -> Pixels {
 1181        self.margin + self.right_padding
 1182    }
 1183}
 1184
 1185#[derive(Debug)]
 1186pub struct RemoteSelection {
 1187    pub replica_id: ReplicaId,
 1188    pub selection: Selection<Anchor>,
 1189    pub cursor_shape: CursorShape,
 1190    pub collaborator_id: CollaboratorId,
 1191    pub line_mode: bool,
 1192    pub user_name: Option<SharedString>,
 1193    pub color: PlayerColor,
 1194}
 1195
 1196#[derive(Clone, Debug)]
 1197struct SelectionHistoryEntry {
 1198    selections: Arc<[Selection<Anchor>]>,
 1199    select_next_state: Option<SelectNextState>,
 1200    select_prev_state: Option<SelectNextState>,
 1201    add_selections_state: Option<AddSelectionsState>,
 1202}
 1203
 1204#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1205enum SelectionHistoryMode {
 1206    Normal,
 1207    Undoing,
 1208    Redoing,
 1209    Skipping,
 1210}
 1211
 1212#[derive(Clone, PartialEq, Eq, Hash)]
 1213struct HoveredCursor {
 1214    replica_id: u16,
 1215    selection_id: usize,
 1216}
 1217
 1218impl Default for SelectionHistoryMode {
 1219    fn default() -> Self {
 1220        Self::Normal
 1221    }
 1222}
 1223
 1224struct DeferredSelectionEffectsState {
 1225    changed: bool,
 1226    should_update_completions: bool,
 1227    autoscroll: Option<Autoscroll>,
 1228    old_cursor_position: Anchor,
 1229    history_entry: SelectionHistoryEntry,
 1230}
 1231
 1232#[derive(Default)]
 1233struct SelectionHistory {
 1234    #[allow(clippy::type_complexity)]
 1235    selections_by_transaction:
 1236        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1237    mode: SelectionHistoryMode,
 1238    undo_stack: VecDeque<SelectionHistoryEntry>,
 1239    redo_stack: VecDeque<SelectionHistoryEntry>,
 1240}
 1241
 1242impl SelectionHistory {
 1243    #[track_caller]
 1244    fn insert_transaction(
 1245        &mut self,
 1246        transaction_id: TransactionId,
 1247        selections: Arc<[Selection<Anchor>]>,
 1248    ) {
 1249        if selections.is_empty() {
 1250            log::error!(
 1251                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1252                std::panic::Location::caller()
 1253            );
 1254            return;
 1255        }
 1256        self.selections_by_transaction
 1257            .insert(transaction_id, (selections, None));
 1258    }
 1259
 1260    #[allow(clippy::type_complexity)]
 1261    fn transaction(
 1262        &self,
 1263        transaction_id: TransactionId,
 1264    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1265        self.selections_by_transaction.get(&transaction_id)
 1266    }
 1267
 1268    #[allow(clippy::type_complexity)]
 1269    fn transaction_mut(
 1270        &mut self,
 1271        transaction_id: TransactionId,
 1272    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1273        self.selections_by_transaction.get_mut(&transaction_id)
 1274    }
 1275
 1276    fn push(&mut self, entry: SelectionHistoryEntry) {
 1277        if !entry.selections.is_empty() {
 1278            match self.mode {
 1279                SelectionHistoryMode::Normal => {
 1280                    self.push_undo(entry);
 1281                    self.redo_stack.clear();
 1282                }
 1283                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1284                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1285                SelectionHistoryMode::Skipping => {}
 1286            }
 1287        }
 1288    }
 1289
 1290    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1291        if self
 1292            .undo_stack
 1293            .back()
 1294            .map_or(true, |e| e.selections != entry.selections)
 1295        {
 1296            self.undo_stack.push_back(entry);
 1297            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1298                self.undo_stack.pop_front();
 1299            }
 1300        }
 1301    }
 1302
 1303    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1304        if self
 1305            .redo_stack
 1306            .back()
 1307            .map_or(true, |e| e.selections != entry.selections)
 1308        {
 1309            self.redo_stack.push_back(entry);
 1310            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1311                self.redo_stack.pop_front();
 1312            }
 1313        }
 1314    }
 1315}
 1316
 1317#[derive(Clone, Copy)]
 1318pub struct RowHighlightOptions {
 1319    pub autoscroll: bool,
 1320    pub include_gutter: bool,
 1321}
 1322
 1323impl Default for RowHighlightOptions {
 1324    fn default() -> Self {
 1325        Self {
 1326            autoscroll: Default::default(),
 1327            include_gutter: true,
 1328        }
 1329    }
 1330}
 1331
 1332struct RowHighlight {
 1333    index: usize,
 1334    range: Range<Anchor>,
 1335    color: Hsla,
 1336    options: RowHighlightOptions,
 1337    type_id: TypeId,
 1338}
 1339
 1340#[derive(Clone, Debug)]
 1341struct AddSelectionsState {
 1342    groups: Vec<AddSelectionsGroup>,
 1343}
 1344
 1345#[derive(Clone, Debug)]
 1346struct AddSelectionsGroup {
 1347    above: bool,
 1348    stack: Vec<usize>,
 1349}
 1350
 1351#[derive(Clone)]
 1352struct SelectNextState {
 1353    query: AhoCorasick,
 1354    wordwise: bool,
 1355    done: bool,
 1356}
 1357
 1358impl std::fmt::Debug for SelectNextState {
 1359    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1360        f.debug_struct(std::any::type_name::<Self>())
 1361            .field("wordwise", &self.wordwise)
 1362            .field("done", &self.done)
 1363            .finish()
 1364    }
 1365}
 1366
 1367#[derive(Debug)]
 1368struct AutocloseRegion {
 1369    selection_id: usize,
 1370    range: Range<Anchor>,
 1371    pair: BracketPair,
 1372}
 1373
 1374#[derive(Debug)]
 1375struct SnippetState {
 1376    ranges: Vec<Vec<Range<Anchor>>>,
 1377    active_index: usize,
 1378    choices: Vec<Option<Vec<String>>>,
 1379}
 1380
 1381#[doc(hidden)]
 1382pub struct RenameState {
 1383    pub range: Range<Anchor>,
 1384    pub old_name: Arc<str>,
 1385    pub editor: Entity<Editor>,
 1386    block_id: CustomBlockId,
 1387}
 1388
 1389struct InvalidationStack<T>(Vec<T>);
 1390
 1391struct RegisteredInlineCompletionProvider {
 1392    provider: Arc<dyn InlineCompletionProviderHandle>,
 1393    _subscription: Subscription,
 1394}
 1395
 1396#[derive(Debug, PartialEq, Eq)]
 1397pub struct ActiveDiagnosticGroup {
 1398    pub active_range: Range<Anchor>,
 1399    pub active_message: String,
 1400    pub group_id: usize,
 1401    pub blocks: HashSet<CustomBlockId>,
 1402}
 1403
 1404#[derive(Debug, PartialEq, Eq)]
 1405
 1406pub(crate) enum ActiveDiagnostic {
 1407    None,
 1408    All,
 1409    Group(ActiveDiagnosticGroup),
 1410}
 1411
 1412#[derive(Serialize, Deserialize, Clone, Debug)]
 1413pub struct ClipboardSelection {
 1414    /// The number of bytes in this selection.
 1415    pub len: usize,
 1416    /// Whether this was a full-line selection.
 1417    pub is_entire_line: bool,
 1418    /// The indentation of the first line when this content was originally copied.
 1419    pub first_line_indent: u32,
 1420}
 1421
 1422// selections, scroll behavior, was newest selection reversed
 1423type SelectSyntaxNodeHistoryState = (
 1424    Box<[Selection<usize>]>,
 1425    SelectSyntaxNodeScrollBehavior,
 1426    bool,
 1427);
 1428
 1429#[derive(Default)]
 1430struct SelectSyntaxNodeHistory {
 1431    stack: Vec<SelectSyntaxNodeHistoryState>,
 1432    // disable temporarily to allow changing selections without losing the stack
 1433    pub disable_clearing: bool,
 1434}
 1435
 1436impl SelectSyntaxNodeHistory {
 1437    pub fn try_clear(&mut self) {
 1438        if !self.disable_clearing {
 1439            self.stack.clear();
 1440        }
 1441    }
 1442
 1443    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1444        self.stack.push(selection);
 1445    }
 1446
 1447    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1448        self.stack.pop()
 1449    }
 1450}
 1451
 1452enum SelectSyntaxNodeScrollBehavior {
 1453    CursorTop,
 1454    FitSelection,
 1455    CursorBottom,
 1456}
 1457
 1458#[derive(Debug)]
 1459pub(crate) struct NavigationData {
 1460    cursor_anchor: Anchor,
 1461    cursor_position: Point,
 1462    scroll_anchor: ScrollAnchor,
 1463    scroll_top_row: u32,
 1464}
 1465
 1466#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1467pub enum GotoDefinitionKind {
 1468    Symbol,
 1469    Declaration,
 1470    Type,
 1471    Implementation,
 1472}
 1473
 1474#[derive(Debug, Clone)]
 1475enum InlayHintRefreshReason {
 1476    ModifiersChanged(bool),
 1477    Toggle(bool),
 1478    SettingsChange(InlayHintSettings),
 1479    NewLinesShown,
 1480    BufferEdited(HashSet<Arc<Language>>),
 1481    RefreshRequested,
 1482    ExcerptsRemoved(Vec<ExcerptId>),
 1483}
 1484
 1485impl InlayHintRefreshReason {
 1486    fn description(&self) -> &'static str {
 1487        match self {
 1488            Self::ModifiersChanged(_) => "modifiers changed",
 1489            Self::Toggle(_) => "toggle",
 1490            Self::SettingsChange(_) => "settings change",
 1491            Self::NewLinesShown => "new lines shown",
 1492            Self::BufferEdited(_) => "buffer edited",
 1493            Self::RefreshRequested => "refresh requested",
 1494            Self::ExcerptsRemoved(_) => "excerpts removed",
 1495        }
 1496    }
 1497}
 1498
 1499pub enum FormatTarget {
 1500    Buffers,
 1501    Ranges(Vec<Range<MultiBufferPoint>>),
 1502}
 1503
 1504pub(crate) struct FocusedBlock {
 1505    id: BlockId,
 1506    focus_handle: WeakFocusHandle,
 1507}
 1508
 1509#[derive(Clone)]
 1510enum JumpData {
 1511    MultiBufferRow {
 1512        row: MultiBufferRow,
 1513        line_offset_from_top: u32,
 1514    },
 1515    MultiBufferPoint {
 1516        excerpt_id: ExcerptId,
 1517        position: Point,
 1518        anchor: text::Anchor,
 1519        line_offset_from_top: u32,
 1520    },
 1521}
 1522
 1523pub enum MultibufferSelectionMode {
 1524    First,
 1525    All,
 1526}
 1527
 1528#[derive(Clone, Copy, Debug, Default)]
 1529pub struct RewrapOptions {
 1530    pub override_language_settings: bool,
 1531    pub preserve_existing_whitespace: bool,
 1532}
 1533
 1534impl Editor {
 1535    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1536        let buffer = cx.new(|cx| Buffer::local("", cx));
 1537        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1538        Self::new(
 1539            EditorMode::SingleLine { auto_width: false },
 1540            buffer,
 1541            None,
 1542            window,
 1543            cx,
 1544        )
 1545    }
 1546
 1547    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1548        let buffer = cx.new(|cx| Buffer::local("", cx));
 1549        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1550        Self::new(EditorMode::full(), buffer, None, window, cx)
 1551    }
 1552
 1553    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1554        let buffer = cx.new(|cx| Buffer::local("", cx));
 1555        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1556        Self::new(
 1557            EditorMode::SingleLine { auto_width: true },
 1558            buffer,
 1559            None,
 1560            window,
 1561            cx,
 1562        )
 1563    }
 1564
 1565    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1566        let buffer = cx.new(|cx| Buffer::local("", cx));
 1567        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1568        Self::new(
 1569            EditorMode::AutoHeight { max_lines },
 1570            buffer,
 1571            None,
 1572            window,
 1573            cx,
 1574        )
 1575    }
 1576
 1577    pub fn for_buffer(
 1578        buffer: Entity<Buffer>,
 1579        project: Option<Entity<Project>>,
 1580        window: &mut Window,
 1581        cx: &mut Context<Self>,
 1582    ) -> Self {
 1583        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1584        Self::new(EditorMode::full(), buffer, project, window, cx)
 1585    }
 1586
 1587    pub fn for_multibuffer(
 1588        buffer: Entity<MultiBuffer>,
 1589        project: Option<Entity<Project>>,
 1590        window: &mut Window,
 1591        cx: &mut Context<Self>,
 1592    ) -> Self {
 1593        Self::new(EditorMode::full(), buffer, project, window, cx)
 1594    }
 1595
 1596    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1597        let mut clone = Self::new(
 1598            self.mode.clone(),
 1599            self.buffer.clone(),
 1600            self.project.clone(),
 1601            window,
 1602            cx,
 1603        );
 1604        self.display_map.update(cx, |display_map, cx| {
 1605            let snapshot = display_map.snapshot(cx);
 1606            clone.display_map.update(cx, |display_map, cx| {
 1607                display_map.set_state(&snapshot, cx);
 1608            });
 1609        });
 1610        clone.folds_did_change(cx);
 1611        clone.selections.clone_state(&self.selections);
 1612        clone.scroll_manager.clone_state(&self.scroll_manager);
 1613        clone.searchable = self.searchable;
 1614        clone.read_only = self.read_only;
 1615        clone
 1616    }
 1617
 1618    pub fn new(
 1619        mode: EditorMode,
 1620        buffer: Entity<MultiBuffer>,
 1621        project: Option<Entity<Project>>,
 1622        window: &mut Window,
 1623        cx: &mut Context<Self>,
 1624    ) -> Self {
 1625        Editor::new_internal(mode, buffer, project, None, window, cx)
 1626    }
 1627
 1628    fn new_internal(
 1629        mode: EditorMode,
 1630        buffer: Entity<MultiBuffer>,
 1631        project: Option<Entity<Project>>,
 1632        display_map: Option<Entity<DisplayMap>>,
 1633        window: &mut Window,
 1634        cx: &mut Context<Self>,
 1635    ) -> Self {
 1636        debug_assert!(
 1637            display_map.is_none() || mode.is_minimap(),
 1638            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1639        );
 1640
 1641        let full_mode = mode.is_full();
 1642        let diagnostics_max_severity = if full_mode {
 1643            EditorSettings::get_global(cx)
 1644                .diagnostics_max_severity
 1645                .unwrap_or(DiagnosticSeverity::Hint)
 1646        } else {
 1647            DiagnosticSeverity::Off
 1648        };
 1649        let style = window.text_style();
 1650        let font_size = style.font_size.to_pixels(window.rem_size());
 1651        let editor = cx.entity().downgrade();
 1652        let fold_placeholder = FoldPlaceholder {
 1653            constrain_width: true,
 1654            render: Arc::new(move |fold_id, fold_range, cx| {
 1655                let editor = editor.clone();
 1656                div()
 1657                    .id(fold_id)
 1658                    .bg(cx.theme().colors().ghost_element_background)
 1659                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1660                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1661                    .rounded_xs()
 1662                    .size_full()
 1663                    .cursor_pointer()
 1664                    .child("")
 1665                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1666                    .on_click(move |_, _window, cx| {
 1667                        editor
 1668                            .update(cx, |editor, cx| {
 1669                                editor.unfold_ranges(
 1670                                    &[fold_range.start..fold_range.end],
 1671                                    true,
 1672                                    false,
 1673                                    cx,
 1674                                );
 1675                                cx.stop_propagation();
 1676                            })
 1677                            .ok();
 1678                    })
 1679                    .into_any()
 1680            }),
 1681            merge_adjacent: true,
 1682            ..FoldPlaceholder::default()
 1683        };
 1684        let display_map = display_map.unwrap_or_else(|| {
 1685            cx.new(|cx| {
 1686                DisplayMap::new(
 1687                    buffer.clone(),
 1688                    style.font(),
 1689                    font_size,
 1690                    None,
 1691                    FILE_HEADER_HEIGHT,
 1692                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1693                    fold_placeholder,
 1694                    diagnostics_max_severity,
 1695                    cx,
 1696                )
 1697            })
 1698        });
 1699
 1700        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1701
 1702        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1703
 1704        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1705            .then(|| language_settings::SoftWrap::None);
 1706
 1707        let mut project_subscriptions = Vec::new();
 1708        if mode.is_full() {
 1709            if let Some(project) = project.as_ref() {
 1710                project_subscriptions.push(cx.subscribe_in(
 1711                    project,
 1712                    window,
 1713                    |editor, _, event, window, cx| match event {
 1714                        project::Event::RefreshCodeLens => {
 1715                            // we always query lens with actions, without storing them, always refreshing them
 1716                        }
 1717                        project::Event::RefreshInlayHints => {
 1718                            editor
 1719                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1720                        }
 1721                        project::Event::LanguageServerAdded(..)
 1722                        | project::Event::LanguageServerRemoved(..) => {
 1723                            if editor.tasks_update_task.is_none() {
 1724                                editor.tasks_update_task =
 1725                                    Some(editor.refresh_runnables(window, cx));
 1726                            }
 1727                            editor.pull_diagnostics(None, window, cx);
 1728                        }
 1729                        project::Event::SnippetEdit(id, snippet_edits) => {
 1730                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1731                                let focus_handle = editor.focus_handle(cx);
 1732                                if focus_handle.is_focused(window) {
 1733                                    let snapshot = buffer.read(cx).snapshot();
 1734                                    for (range, snippet) in snippet_edits {
 1735                                        let editor_range =
 1736                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1737                                        editor
 1738                                            .insert_snippet(
 1739                                                &[editor_range],
 1740                                                snippet.clone(),
 1741                                                window,
 1742                                                cx,
 1743                                            )
 1744                                            .ok();
 1745                                    }
 1746                                }
 1747                            }
 1748                        }
 1749                        _ => {}
 1750                    },
 1751                ));
 1752                if let Some(task_inventory) = project
 1753                    .read(cx)
 1754                    .task_store()
 1755                    .read(cx)
 1756                    .task_inventory()
 1757                    .cloned()
 1758                {
 1759                    project_subscriptions.push(cx.observe_in(
 1760                        &task_inventory,
 1761                        window,
 1762                        |editor, _, window, cx| {
 1763                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1764                        },
 1765                    ));
 1766                };
 1767
 1768                project_subscriptions.push(cx.subscribe_in(
 1769                    &project.read(cx).breakpoint_store(),
 1770                    window,
 1771                    |editor, _, event, window, cx| match event {
 1772                        BreakpointStoreEvent::ClearDebugLines => {
 1773                            editor.clear_row_highlights::<ActiveDebugLine>();
 1774                            editor.refresh_inline_values(cx);
 1775                        }
 1776                        BreakpointStoreEvent::SetDebugLine => {
 1777                            if editor.go_to_active_debug_line(window, cx) {
 1778                                cx.stop_propagation();
 1779                            }
 1780
 1781                            editor.refresh_inline_values(cx);
 1782                        }
 1783                        _ => {}
 1784                    },
 1785                ));
 1786            }
 1787        }
 1788
 1789        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1790
 1791        let inlay_hint_settings =
 1792            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1793        let focus_handle = cx.focus_handle();
 1794        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1795            .detach();
 1796        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1797            .detach();
 1798        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1799            .detach();
 1800        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1801            .detach();
 1802        cx.observe_pending_input(window, Self::observe_pending_input)
 1803            .detach();
 1804
 1805        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1806            Some(false)
 1807        } else {
 1808            None
 1809        };
 1810
 1811        let breakpoint_store = match (&mode, project.as_ref()) {
 1812            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1813            _ => None,
 1814        };
 1815
 1816        let mut code_action_providers = Vec::new();
 1817        let mut load_uncommitted_diff = None;
 1818        if let Some(project) = project.clone() {
 1819            load_uncommitted_diff = Some(
 1820                update_uncommitted_diff_for_buffer(
 1821                    cx.entity(),
 1822                    &project,
 1823                    buffer.read(cx).all_buffers(),
 1824                    buffer.clone(),
 1825                    cx,
 1826                )
 1827                .shared(),
 1828            );
 1829            code_action_providers.push(Rc::new(project) as Rc<_>);
 1830        }
 1831
 1832        let mut editor = Self {
 1833            focus_handle,
 1834            show_cursor_when_unfocused: false,
 1835            last_focused_descendant: None,
 1836            buffer: buffer.clone(),
 1837            display_map: display_map.clone(),
 1838            selections,
 1839            scroll_manager: ScrollManager::new(cx),
 1840            columnar_selection_tail: None,
 1841            columnar_display_point: None,
 1842            add_selections_state: None,
 1843            select_next_state: None,
 1844            select_prev_state: None,
 1845            selection_history: SelectionHistory::default(),
 1846            defer_selection_effects: false,
 1847            deferred_selection_effects_state: None,
 1848            autoclose_regions: Vec::new(),
 1849            snippet_stack: InvalidationStack::default(),
 1850            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1851            ime_transaction: None,
 1852            active_diagnostics: ActiveDiagnostic::None,
 1853            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1854            inline_diagnostics_update: Task::ready(()),
 1855            inline_diagnostics: Vec::new(),
 1856            soft_wrap_mode_override,
 1857            diagnostics_max_severity,
 1858            hard_wrap: None,
 1859            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1860            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1861            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1862            project,
 1863            blink_manager: blink_manager.clone(),
 1864            show_local_selections: true,
 1865            show_scrollbars: ScrollbarAxes {
 1866                horizontal: full_mode,
 1867                vertical: full_mode,
 1868            },
 1869            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1870            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1871            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1872            show_gutter: mode.is_full(),
 1873            show_line_numbers: None,
 1874            use_relative_line_numbers: None,
 1875            disable_expand_excerpt_buttons: false,
 1876            show_git_diff_gutter: None,
 1877            show_code_actions: None,
 1878            show_runnables: None,
 1879            show_breakpoints: None,
 1880            show_wrap_guides: None,
 1881            show_indent_guides,
 1882            placeholder_text: None,
 1883            highlight_order: 0,
 1884            highlighted_rows: HashMap::default(),
 1885            background_highlights: TreeMap::default(),
 1886            gutter_highlights: TreeMap::default(),
 1887            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1888            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1889            nav_history: None,
 1890            context_menu: RefCell::new(None),
 1891            context_menu_options: None,
 1892            mouse_context_menu: None,
 1893            completion_tasks: Vec::new(),
 1894            inline_blame_popover: None,
 1895            signature_help_state: SignatureHelpState::default(),
 1896            auto_signature_help: None,
 1897            find_all_references_task_sources: Vec::new(),
 1898            next_completion_id: 0,
 1899            next_inlay_id: 0,
 1900            code_action_providers,
 1901            available_code_actions: None,
 1902            code_actions_task: None,
 1903            quick_selection_highlight_task: None,
 1904            debounced_selection_highlight_task: None,
 1905            document_highlights_task: None,
 1906            linked_editing_range_task: None,
 1907            pending_rename: None,
 1908            searchable: true,
 1909            cursor_shape: EditorSettings::get_global(cx)
 1910                .cursor_shape
 1911                .unwrap_or_default(),
 1912            current_line_highlight: None,
 1913            autoindent_mode: Some(AutoindentMode::EachLine),
 1914            collapse_matches: false,
 1915            workspace: None,
 1916            input_enabled: true,
 1917            use_modal_editing: mode.is_full(),
 1918            read_only: mode.is_minimap(),
 1919            use_autoclose: true,
 1920            use_auto_surround: true,
 1921            auto_replace_emoji_shortcode: false,
 1922            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1923            leader_id: None,
 1924            remote_id: None,
 1925            hover_state: HoverState::default(),
 1926            pending_mouse_down: None,
 1927            hovered_link_state: None,
 1928            edit_prediction_provider: None,
 1929            active_inline_completion: None,
 1930            stale_inline_completion_in_menu: None,
 1931            edit_prediction_preview: EditPredictionPreview::Inactive {
 1932                released_too_fast: false,
 1933            },
 1934            inline_diagnostics_enabled: mode.is_full(),
 1935            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1936            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1937
 1938            gutter_hovered: false,
 1939            pixel_position_of_newest_cursor: None,
 1940            last_bounds: None,
 1941            last_position_map: None,
 1942            expect_bounds_change: None,
 1943            gutter_dimensions: GutterDimensions::default(),
 1944            style: None,
 1945            show_cursor_names: false,
 1946            hovered_cursors: HashMap::default(),
 1947            next_editor_action_id: EditorActionId::default(),
 1948            editor_actions: Rc::default(),
 1949            inline_completions_hidden_for_vim_mode: false,
 1950            show_inline_completions_override: None,
 1951            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1952            edit_prediction_settings: EditPredictionSettings::Disabled,
 1953            edit_prediction_indent_conflict: false,
 1954            edit_prediction_requires_modifier_in_indent_conflict: true,
 1955            custom_context_menu: None,
 1956            show_git_blame_gutter: false,
 1957            show_git_blame_inline: false,
 1958            show_selection_menu: None,
 1959            show_git_blame_inline_delay_task: None,
 1960            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1961            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1962            serialize_dirty_buffers: !mode.is_minimap()
 1963                && ProjectSettings::get_global(cx)
 1964                    .session
 1965                    .restore_unsaved_buffers,
 1966            blame: None,
 1967            blame_subscription: None,
 1968            tasks: BTreeMap::default(),
 1969
 1970            breakpoint_store,
 1971            gutter_breakpoint_indicator: (None, None),
 1972            _subscriptions: vec![
 1973                cx.observe(&buffer, Self::on_buffer_changed),
 1974                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1975                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1976                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1977                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1978                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1979                cx.observe_window_activation(window, |editor, window, cx| {
 1980                    let active = window.is_window_active();
 1981                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1982                        if active {
 1983                            blink_manager.enable(cx);
 1984                        } else {
 1985                            blink_manager.disable(cx);
 1986                        }
 1987                    });
 1988                    if active {
 1989                        editor.show_mouse_cursor();
 1990                    }
 1991                }),
 1992            ],
 1993            tasks_update_task: None,
 1994            pull_diagnostics_task: Task::ready(()),
 1995            linked_edit_ranges: Default::default(),
 1996            in_project_search: false,
 1997            previous_search_ranges: None,
 1998            breadcrumb_header: None,
 1999            focused_block: None,
 2000            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2001            addons: HashMap::default(),
 2002            registered_buffers: HashMap::default(),
 2003            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2004            selection_mark_mode: false,
 2005            toggle_fold_multiple_buffers: Task::ready(()),
 2006            serialize_selections: Task::ready(()),
 2007            serialize_folds: Task::ready(()),
 2008            text_style_refinement: None,
 2009            load_diff_task: load_uncommitted_diff,
 2010            temporary_diff_override: false,
 2011            mouse_cursor_hidden: false,
 2012            minimap: None,
 2013            hide_mouse_mode: EditorSettings::get_global(cx)
 2014                .hide_mouse
 2015                .unwrap_or_default(),
 2016            change_list: ChangeList::new(),
 2017            mode,
 2018            selection_drag_state: SelectionDragState::None,
 2019            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2020        };
 2021        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2022            editor
 2023                ._subscriptions
 2024                .push(cx.observe(breakpoints, |_, _, cx| {
 2025                    cx.notify();
 2026                }));
 2027        }
 2028        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2029        editor._subscriptions.extend(project_subscriptions);
 2030
 2031        editor._subscriptions.push(cx.subscribe_in(
 2032            &cx.entity(),
 2033            window,
 2034            |editor, _, e: &EditorEvent, window, cx| match e {
 2035                EditorEvent::ScrollPositionChanged { local, .. } => {
 2036                    if *local {
 2037                        let new_anchor = editor.scroll_manager.anchor();
 2038                        let snapshot = editor.snapshot(window, cx);
 2039                        editor.update_restoration_data(cx, move |data| {
 2040                            data.scroll_position = (
 2041                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2042                                new_anchor.offset,
 2043                            );
 2044                        });
 2045                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2046                        editor.inline_blame_popover.take();
 2047                    }
 2048                }
 2049                EditorEvent::Edited { .. } => {
 2050                    if !vim_enabled(cx) {
 2051                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2052                        let pop_state = editor
 2053                            .change_list
 2054                            .last()
 2055                            .map(|previous| {
 2056                                previous.len() == selections.len()
 2057                                    && previous.iter().enumerate().all(|(ix, p)| {
 2058                                        p.to_display_point(&map).row()
 2059                                            == selections[ix].head().row()
 2060                                    })
 2061                            })
 2062                            .unwrap_or(false);
 2063                        let new_positions = selections
 2064                            .into_iter()
 2065                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2066                            .collect();
 2067                        editor
 2068                            .change_list
 2069                            .push_to_change_list(pop_state, new_positions);
 2070                    }
 2071                }
 2072                _ => (),
 2073            },
 2074        ));
 2075
 2076        if let Some(dap_store) = editor
 2077            .project
 2078            .as_ref()
 2079            .map(|project| project.read(cx).dap_store())
 2080        {
 2081            let weak_editor = cx.weak_entity();
 2082
 2083            editor
 2084                ._subscriptions
 2085                .push(
 2086                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2087                        let session_entity = cx.entity();
 2088                        weak_editor
 2089                            .update(cx, |editor, cx| {
 2090                                editor._subscriptions.push(
 2091                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2092                                );
 2093                            })
 2094                            .ok();
 2095                    }),
 2096                );
 2097
 2098            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2099                editor
 2100                    ._subscriptions
 2101                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2102            }
 2103        }
 2104
 2105        // skip adding the initial selection to selection history
 2106        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2107        editor.end_selection(window, cx);
 2108        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2109
 2110        editor.scroll_manager.show_scrollbars(window, cx);
 2111        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2112
 2113        if full_mode {
 2114            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2115            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2116
 2117            if editor.git_blame_inline_enabled {
 2118                editor.start_git_blame_inline(false, window, cx);
 2119            }
 2120
 2121            editor.go_to_active_debug_line(window, cx);
 2122
 2123            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2124                if let Some(project) = editor.project.as_ref() {
 2125                    let handle = project.update(cx, |project, cx| {
 2126                        project.register_buffer_with_language_servers(&buffer, cx)
 2127                    });
 2128                    editor
 2129                        .registered_buffers
 2130                        .insert(buffer.read(cx).remote_id(), handle);
 2131                }
 2132            }
 2133
 2134            editor.minimap =
 2135                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2136            editor.pull_diagnostics(None, window, cx);
 2137        }
 2138
 2139        editor.report_editor_event("Editor Opened", None, cx);
 2140        editor
 2141    }
 2142
 2143    pub fn deploy_mouse_context_menu(
 2144        &mut self,
 2145        position: gpui::Point<Pixels>,
 2146        context_menu: Entity<ContextMenu>,
 2147        window: &mut Window,
 2148        cx: &mut Context<Self>,
 2149    ) {
 2150        self.mouse_context_menu = Some(MouseContextMenu::new(
 2151            self,
 2152            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2153            context_menu,
 2154            window,
 2155            cx,
 2156        ));
 2157    }
 2158
 2159    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2160        self.mouse_context_menu
 2161            .as_ref()
 2162            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2163    }
 2164
 2165    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2166        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2167    }
 2168
 2169    fn key_context_internal(
 2170        &self,
 2171        has_active_edit_prediction: bool,
 2172        window: &Window,
 2173        cx: &App,
 2174    ) -> KeyContext {
 2175        let mut key_context = KeyContext::new_with_defaults();
 2176        key_context.add("Editor");
 2177        let mode = match self.mode {
 2178            EditorMode::SingleLine { .. } => "single_line",
 2179            EditorMode::AutoHeight { .. } => "auto_height",
 2180            EditorMode::Minimap { .. } => "minimap",
 2181            EditorMode::Full { .. } => "full",
 2182        };
 2183
 2184        if EditorSettings::jupyter_enabled(cx) {
 2185            key_context.add("jupyter");
 2186        }
 2187
 2188        key_context.set("mode", mode);
 2189        if self.pending_rename.is_some() {
 2190            key_context.add("renaming");
 2191        }
 2192
 2193        match self.context_menu.borrow().as_ref() {
 2194            Some(CodeContextMenu::Completions(_)) => {
 2195                key_context.add("menu");
 2196                key_context.add("showing_completions");
 2197            }
 2198            Some(CodeContextMenu::CodeActions(_)) => {
 2199                key_context.add("menu");
 2200                key_context.add("showing_code_actions")
 2201            }
 2202            None => {}
 2203        }
 2204
 2205        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2206        if !self.focus_handle(cx).contains_focused(window, cx)
 2207            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2208        {
 2209            for addon in self.addons.values() {
 2210                addon.extend_key_context(&mut key_context, cx)
 2211            }
 2212        }
 2213
 2214        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2215            if let Some(extension) = singleton_buffer
 2216                .read(cx)
 2217                .file()
 2218                .and_then(|file| file.path().extension()?.to_str())
 2219            {
 2220                key_context.set("extension", extension.to_string());
 2221            }
 2222        } else {
 2223            key_context.add("multibuffer");
 2224        }
 2225
 2226        if has_active_edit_prediction {
 2227            if self.edit_prediction_in_conflict() {
 2228                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2229            } else {
 2230                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2231                key_context.add("copilot_suggestion");
 2232            }
 2233        }
 2234
 2235        if self.selection_mark_mode {
 2236            key_context.add("selection_mode");
 2237        }
 2238
 2239        key_context
 2240    }
 2241
 2242    fn show_mouse_cursor(&mut self) {
 2243        self.mouse_cursor_hidden = false;
 2244    }
 2245
 2246    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2247        self.mouse_cursor_hidden = match origin {
 2248            HideMouseCursorOrigin::TypingAction => {
 2249                matches!(
 2250                    self.hide_mouse_mode,
 2251                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2252                )
 2253            }
 2254            HideMouseCursorOrigin::MovementAction => {
 2255                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2256            }
 2257        };
 2258    }
 2259
 2260    pub fn edit_prediction_in_conflict(&self) -> bool {
 2261        if !self.show_edit_predictions_in_menu() {
 2262            return false;
 2263        }
 2264
 2265        let showing_completions = self
 2266            .context_menu
 2267            .borrow()
 2268            .as_ref()
 2269            .map_or(false, |context| {
 2270                matches!(context, CodeContextMenu::Completions(_))
 2271            });
 2272
 2273        showing_completions
 2274            || self.edit_prediction_requires_modifier()
 2275            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2276            // bindings to insert tab characters.
 2277            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2278    }
 2279
 2280    pub fn accept_edit_prediction_keybind(
 2281        &self,
 2282        accept_partial: bool,
 2283        window: &Window,
 2284        cx: &App,
 2285    ) -> AcceptEditPredictionBinding {
 2286        let key_context = self.key_context_internal(true, window, cx);
 2287        let in_conflict = self.edit_prediction_in_conflict();
 2288
 2289        let bindings = if accept_partial {
 2290            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2291        } else {
 2292            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2293        };
 2294
 2295        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2296        // just the first one.
 2297        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2298            !in_conflict
 2299                || binding
 2300                    .keystrokes()
 2301                    .first()
 2302                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2303        }))
 2304    }
 2305
 2306    pub fn new_file(
 2307        workspace: &mut Workspace,
 2308        _: &workspace::NewFile,
 2309        window: &mut Window,
 2310        cx: &mut Context<Workspace>,
 2311    ) {
 2312        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2313            "Failed to create buffer",
 2314            window,
 2315            cx,
 2316            |e, _, _| match e.error_code() {
 2317                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2318                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2319                e.error_tag("required").unwrap_or("the latest version")
 2320            )),
 2321                _ => None,
 2322            },
 2323        );
 2324    }
 2325
 2326    pub fn new_in_workspace(
 2327        workspace: &mut Workspace,
 2328        window: &mut Window,
 2329        cx: &mut Context<Workspace>,
 2330    ) -> Task<Result<Entity<Editor>>> {
 2331        let project = workspace.project().clone();
 2332        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2333
 2334        cx.spawn_in(window, async move |workspace, cx| {
 2335            let buffer = create.await?;
 2336            workspace.update_in(cx, |workspace, window, cx| {
 2337                let editor =
 2338                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2339                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2340                editor
 2341            })
 2342        })
 2343    }
 2344
 2345    fn new_file_vertical(
 2346        workspace: &mut Workspace,
 2347        _: &workspace::NewFileSplitVertical,
 2348        window: &mut Window,
 2349        cx: &mut Context<Workspace>,
 2350    ) {
 2351        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2352    }
 2353
 2354    fn new_file_horizontal(
 2355        workspace: &mut Workspace,
 2356        _: &workspace::NewFileSplitHorizontal,
 2357        window: &mut Window,
 2358        cx: &mut Context<Workspace>,
 2359    ) {
 2360        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2361    }
 2362
 2363    fn new_file_in_direction(
 2364        workspace: &mut Workspace,
 2365        direction: SplitDirection,
 2366        window: &mut Window,
 2367        cx: &mut Context<Workspace>,
 2368    ) {
 2369        let project = workspace.project().clone();
 2370        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2371
 2372        cx.spawn_in(window, async move |workspace, cx| {
 2373            let buffer = create.await?;
 2374            workspace.update_in(cx, move |workspace, window, cx| {
 2375                workspace.split_item(
 2376                    direction,
 2377                    Box::new(
 2378                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2379                    ),
 2380                    window,
 2381                    cx,
 2382                )
 2383            })?;
 2384            anyhow::Ok(())
 2385        })
 2386        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2387            match e.error_code() {
 2388                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2389                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2390                e.error_tag("required").unwrap_or("the latest version")
 2391            )),
 2392                _ => None,
 2393            }
 2394        });
 2395    }
 2396
 2397    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2398        self.leader_id
 2399    }
 2400
 2401    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2402        &self.buffer
 2403    }
 2404
 2405    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2406        self.workspace.as_ref()?.0.upgrade()
 2407    }
 2408
 2409    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2410        self.buffer().read(cx).title(cx)
 2411    }
 2412
 2413    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2414        let git_blame_gutter_max_author_length = self
 2415            .render_git_blame_gutter(cx)
 2416            .then(|| {
 2417                if let Some(blame) = self.blame.as_ref() {
 2418                    let max_author_length =
 2419                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2420                    Some(max_author_length)
 2421                } else {
 2422                    None
 2423                }
 2424            })
 2425            .flatten();
 2426
 2427        EditorSnapshot {
 2428            mode: self.mode.clone(),
 2429            show_gutter: self.show_gutter,
 2430            show_line_numbers: self.show_line_numbers,
 2431            show_git_diff_gutter: self.show_git_diff_gutter,
 2432            show_code_actions: self.show_code_actions,
 2433            show_runnables: self.show_runnables,
 2434            show_breakpoints: self.show_breakpoints,
 2435            git_blame_gutter_max_author_length,
 2436            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2437            scroll_anchor: self.scroll_manager.anchor(),
 2438            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2439            placeholder_text: self.placeholder_text.clone(),
 2440            is_focused: self.focus_handle.is_focused(window),
 2441            current_line_highlight: self
 2442                .current_line_highlight
 2443                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2444            gutter_hovered: self.gutter_hovered,
 2445        }
 2446    }
 2447
 2448    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2449        self.buffer.read(cx).language_at(point, cx)
 2450    }
 2451
 2452    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2453        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2454    }
 2455
 2456    pub fn active_excerpt(
 2457        &self,
 2458        cx: &App,
 2459    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2460        self.buffer
 2461            .read(cx)
 2462            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2463    }
 2464
 2465    pub fn mode(&self) -> &EditorMode {
 2466        &self.mode
 2467    }
 2468
 2469    pub fn set_mode(&mut self, mode: EditorMode) {
 2470        self.mode = mode;
 2471    }
 2472
 2473    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2474        self.collaboration_hub.as_deref()
 2475    }
 2476
 2477    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2478        self.collaboration_hub = Some(hub);
 2479    }
 2480
 2481    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2482        self.in_project_search = in_project_search;
 2483    }
 2484
 2485    pub fn set_custom_context_menu(
 2486        &mut self,
 2487        f: impl 'static
 2488        + Fn(
 2489            &mut Self,
 2490            DisplayPoint,
 2491            &mut Window,
 2492            &mut Context<Self>,
 2493        ) -> Option<Entity<ui::ContextMenu>>,
 2494    ) {
 2495        self.custom_context_menu = Some(Box::new(f))
 2496    }
 2497
 2498    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2499        self.completion_provider = provider;
 2500    }
 2501
 2502    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2503        self.semantics_provider.clone()
 2504    }
 2505
 2506    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2507        self.semantics_provider = provider;
 2508    }
 2509
 2510    pub fn set_edit_prediction_provider<T>(
 2511        &mut self,
 2512        provider: Option<Entity<T>>,
 2513        window: &mut Window,
 2514        cx: &mut Context<Self>,
 2515    ) where
 2516        T: EditPredictionProvider,
 2517    {
 2518        self.edit_prediction_provider =
 2519            provider.map(|provider| RegisteredInlineCompletionProvider {
 2520                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2521                    if this.focus_handle.is_focused(window) {
 2522                        this.update_visible_inline_completion(window, cx);
 2523                    }
 2524                }),
 2525                provider: Arc::new(provider),
 2526            });
 2527        self.update_edit_prediction_settings(cx);
 2528        self.refresh_inline_completion(false, false, window, cx);
 2529    }
 2530
 2531    pub fn placeholder_text(&self) -> Option<&str> {
 2532        self.placeholder_text.as_deref()
 2533    }
 2534
 2535    pub fn set_placeholder_text(
 2536        &mut self,
 2537        placeholder_text: impl Into<Arc<str>>,
 2538        cx: &mut Context<Self>,
 2539    ) {
 2540        let placeholder_text = Some(placeholder_text.into());
 2541        if self.placeholder_text != placeholder_text {
 2542            self.placeholder_text = placeholder_text;
 2543            cx.notify();
 2544        }
 2545    }
 2546
 2547    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2548        self.cursor_shape = cursor_shape;
 2549
 2550        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2551        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2552
 2553        cx.notify();
 2554    }
 2555
 2556    pub fn set_current_line_highlight(
 2557        &mut self,
 2558        current_line_highlight: Option<CurrentLineHighlight>,
 2559    ) {
 2560        self.current_line_highlight = current_line_highlight;
 2561    }
 2562
 2563    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2564        self.collapse_matches = collapse_matches;
 2565    }
 2566
 2567    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2568        let buffers = self.buffer.read(cx).all_buffers();
 2569        let Some(project) = self.project.as_ref() else {
 2570            return;
 2571        };
 2572        project.update(cx, |project, cx| {
 2573            for buffer in buffers {
 2574                self.registered_buffers
 2575                    .entry(buffer.read(cx).remote_id())
 2576                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2577            }
 2578        })
 2579    }
 2580
 2581    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2582        if self.collapse_matches {
 2583            return range.start..range.start;
 2584        }
 2585        range.clone()
 2586    }
 2587
 2588    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2589        if self.display_map.read(cx).clip_at_line_ends != clip {
 2590            self.display_map
 2591                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2592        }
 2593    }
 2594
 2595    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2596        self.input_enabled = input_enabled;
 2597    }
 2598
 2599    pub fn set_inline_completions_hidden_for_vim_mode(
 2600        &mut self,
 2601        hidden: bool,
 2602        window: &mut Window,
 2603        cx: &mut Context<Self>,
 2604    ) {
 2605        if hidden != self.inline_completions_hidden_for_vim_mode {
 2606            self.inline_completions_hidden_for_vim_mode = hidden;
 2607            if hidden {
 2608                self.update_visible_inline_completion(window, cx);
 2609            } else {
 2610                self.refresh_inline_completion(true, false, window, cx);
 2611            }
 2612        }
 2613    }
 2614
 2615    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2616        self.menu_inline_completions_policy = value;
 2617    }
 2618
 2619    pub fn set_autoindent(&mut self, autoindent: bool) {
 2620        if autoindent {
 2621            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2622        } else {
 2623            self.autoindent_mode = None;
 2624        }
 2625    }
 2626
 2627    pub fn read_only(&self, cx: &App) -> bool {
 2628        self.read_only || self.buffer.read(cx).read_only()
 2629    }
 2630
 2631    pub fn set_read_only(&mut self, read_only: bool) {
 2632        self.read_only = read_only;
 2633    }
 2634
 2635    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2636        self.use_autoclose = autoclose;
 2637    }
 2638
 2639    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2640        self.use_auto_surround = auto_surround;
 2641    }
 2642
 2643    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2644        self.auto_replace_emoji_shortcode = auto_replace;
 2645    }
 2646
 2647    pub fn toggle_edit_predictions(
 2648        &mut self,
 2649        _: &ToggleEditPrediction,
 2650        window: &mut Window,
 2651        cx: &mut Context<Self>,
 2652    ) {
 2653        if self.show_inline_completions_override.is_some() {
 2654            self.set_show_edit_predictions(None, window, cx);
 2655        } else {
 2656            let show_edit_predictions = !self.edit_predictions_enabled();
 2657            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2658        }
 2659    }
 2660
 2661    pub fn set_show_edit_predictions(
 2662        &mut self,
 2663        show_edit_predictions: Option<bool>,
 2664        window: &mut Window,
 2665        cx: &mut Context<Self>,
 2666    ) {
 2667        self.show_inline_completions_override = show_edit_predictions;
 2668        self.update_edit_prediction_settings(cx);
 2669
 2670        if let Some(false) = show_edit_predictions {
 2671            self.discard_inline_completion(false, cx);
 2672        } else {
 2673            self.refresh_inline_completion(false, true, window, cx);
 2674        }
 2675    }
 2676
 2677    fn inline_completions_disabled_in_scope(
 2678        &self,
 2679        buffer: &Entity<Buffer>,
 2680        buffer_position: language::Anchor,
 2681        cx: &App,
 2682    ) -> bool {
 2683        let snapshot = buffer.read(cx).snapshot();
 2684        let settings = snapshot.settings_at(buffer_position, cx);
 2685
 2686        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2687            return false;
 2688        };
 2689
 2690        scope.override_name().map_or(false, |scope_name| {
 2691            settings
 2692                .edit_predictions_disabled_in
 2693                .iter()
 2694                .any(|s| s == scope_name)
 2695        })
 2696    }
 2697
 2698    pub fn set_use_modal_editing(&mut self, to: bool) {
 2699        self.use_modal_editing = to;
 2700    }
 2701
 2702    pub fn use_modal_editing(&self) -> bool {
 2703        self.use_modal_editing
 2704    }
 2705
 2706    fn selections_did_change(
 2707        &mut self,
 2708        local: bool,
 2709        old_cursor_position: &Anchor,
 2710        should_update_completions: bool,
 2711        window: &mut Window,
 2712        cx: &mut Context<Self>,
 2713    ) {
 2714        window.invalidate_character_coordinates();
 2715
 2716        // Copy selections to primary selection buffer
 2717        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2718        if local {
 2719            let selections = self.selections.all::<usize>(cx);
 2720            let buffer_handle = self.buffer.read(cx).read(cx);
 2721
 2722            let mut text = String::new();
 2723            for (index, selection) in selections.iter().enumerate() {
 2724                let text_for_selection = buffer_handle
 2725                    .text_for_range(selection.start..selection.end)
 2726                    .collect::<String>();
 2727
 2728                text.push_str(&text_for_selection);
 2729                if index != selections.len() - 1 {
 2730                    text.push('\n');
 2731                }
 2732            }
 2733
 2734            if !text.is_empty() {
 2735                cx.write_to_primary(ClipboardItem::new_string(text));
 2736            }
 2737        }
 2738
 2739        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2740            self.buffer.update(cx, |buffer, cx| {
 2741                buffer.set_active_selections(
 2742                    &self.selections.disjoint_anchors(),
 2743                    self.selections.line_mode,
 2744                    self.cursor_shape,
 2745                    cx,
 2746                )
 2747            });
 2748        }
 2749        let display_map = self
 2750            .display_map
 2751            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2752        let buffer = &display_map.buffer_snapshot;
 2753        if self.selections.count() == 1 {
 2754            self.add_selections_state = None;
 2755        }
 2756        self.select_next_state = None;
 2757        self.select_prev_state = None;
 2758        self.select_syntax_node_history.try_clear();
 2759        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2760        self.snippet_stack
 2761            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2762        self.take_rename(false, window, cx);
 2763
 2764        let newest_selection = self.selections.newest_anchor();
 2765        let new_cursor_position = newest_selection.head();
 2766        let selection_start = newest_selection.start;
 2767
 2768        self.push_to_nav_history(
 2769            *old_cursor_position,
 2770            Some(new_cursor_position.to_point(buffer)),
 2771            false,
 2772            cx,
 2773        );
 2774
 2775        if local {
 2776            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2777                if !self.registered_buffers.contains_key(&buffer_id) {
 2778                    if let Some(project) = self.project.as_ref() {
 2779                        project.update(cx, |project, cx| {
 2780                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2781                                return;
 2782                            };
 2783                            self.registered_buffers.insert(
 2784                                buffer_id,
 2785                                project.register_buffer_with_language_servers(&buffer, cx),
 2786                            );
 2787                        })
 2788                    }
 2789                }
 2790            }
 2791
 2792            let mut context_menu = self.context_menu.borrow_mut();
 2793            let completion_menu = match context_menu.as_ref() {
 2794                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2795                Some(CodeContextMenu::CodeActions(_)) => {
 2796                    *context_menu = None;
 2797                    None
 2798                }
 2799                None => None,
 2800            };
 2801            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2802            drop(context_menu);
 2803
 2804            if should_update_completions {
 2805                if let Some(completion_position) = completion_position {
 2806                    let start_offset = selection_start.to_offset(buffer);
 2807                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2808                    let continue_showing = if position_matches {
 2809                        if self.snippet_stack.is_empty() {
 2810                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2811                        } else {
 2812                            // Snippet choices can be shown even when the cursor is in whitespace.
 2813                            // Dismissing the menu when actions like backspace
 2814                            true
 2815                        }
 2816                    } else {
 2817                        false
 2818                    };
 2819
 2820                    if continue_showing {
 2821                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2822                    } else {
 2823                        self.hide_context_menu(window, cx);
 2824                    }
 2825                }
 2826            }
 2827
 2828            hide_hover(self, cx);
 2829
 2830            if old_cursor_position.to_display_point(&display_map).row()
 2831                != new_cursor_position.to_display_point(&display_map).row()
 2832            {
 2833                self.available_code_actions.take();
 2834            }
 2835            self.refresh_code_actions(window, cx);
 2836            self.refresh_document_highlights(cx);
 2837            self.refresh_selected_text_highlights(false, window, cx);
 2838            refresh_matching_bracket_highlights(self, window, cx);
 2839            self.update_visible_inline_completion(window, cx);
 2840            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2841            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2842            self.inline_blame_popover.take();
 2843            if self.git_blame_inline_enabled {
 2844                self.start_inline_blame_timer(window, cx);
 2845            }
 2846        }
 2847
 2848        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2849        cx.emit(EditorEvent::SelectionsChanged { local });
 2850
 2851        let selections = &self.selections.disjoint;
 2852        if selections.len() == 1 {
 2853            cx.emit(SearchEvent::ActiveMatchChanged)
 2854        }
 2855        if local {
 2856            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2857                let inmemory_selections = selections
 2858                    .iter()
 2859                    .map(|s| {
 2860                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2861                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2862                    })
 2863                    .collect();
 2864                self.update_restoration_data(cx, |data| {
 2865                    data.selections = inmemory_selections;
 2866                });
 2867
 2868                if WorkspaceSettings::get(None, cx).restore_on_startup
 2869                    != RestoreOnStartupBehavior::None
 2870                {
 2871                    if let Some(workspace_id) =
 2872                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2873                    {
 2874                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2875                        let selections = selections.clone();
 2876                        let background_executor = cx.background_executor().clone();
 2877                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2878                        self.serialize_selections = cx.background_spawn(async move {
 2879                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2880                    let db_selections = selections
 2881                        .iter()
 2882                        .map(|selection| {
 2883                            (
 2884                                selection.start.to_offset(&snapshot),
 2885                                selection.end.to_offset(&snapshot),
 2886                            )
 2887                        })
 2888                        .collect();
 2889
 2890                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2891                        .await
 2892                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2893                        .log_err();
 2894                });
 2895                    }
 2896                }
 2897            }
 2898        }
 2899
 2900        cx.notify();
 2901    }
 2902
 2903    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2904        use text::ToOffset as _;
 2905        use text::ToPoint as _;
 2906
 2907        if self.mode.is_minimap()
 2908            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2909        {
 2910            return;
 2911        }
 2912
 2913        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2914            return;
 2915        };
 2916
 2917        let snapshot = singleton.read(cx).snapshot();
 2918        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2919            let display_snapshot = display_map.snapshot(cx);
 2920
 2921            display_snapshot
 2922                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2923                .map(|fold| {
 2924                    fold.range.start.text_anchor.to_point(&snapshot)
 2925                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2926                })
 2927                .collect()
 2928        });
 2929        self.update_restoration_data(cx, |data| {
 2930            data.folds = inmemory_folds;
 2931        });
 2932
 2933        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2934            return;
 2935        };
 2936        let background_executor = cx.background_executor().clone();
 2937        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2938        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2939            display_map
 2940                .snapshot(cx)
 2941                .folds_in_range(0..snapshot.len())
 2942                .map(|fold| {
 2943                    (
 2944                        fold.range.start.text_anchor.to_offset(&snapshot),
 2945                        fold.range.end.text_anchor.to_offset(&snapshot),
 2946                    )
 2947                })
 2948                .collect()
 2949        });
 2950        self.serialize_folds = cx.background_spawn(async move {
 2951            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2952            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2953                .await
 2954                .with_context(|| {
 2955                    format!(
 2956                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2957                    )
 2958                })
 2959                .log_err();
 2960        });
 2961    }
 2962
 2963    pub fn sync_selections(
 2964        &mut self,
 2965        other: Entity<Editor>,
 2966        cx: &mut Context<Self>,
 2967    ) -> gpui::Subscription {
 2968        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2969        self.selections.change_with(cx, |selections| {
 2970            selections.select_anchors(other_selections);
 2971        });
 2972
 2973        let other_subscription =
 2974            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2975                EditorEvent::SelectionsChanged { local: true } => {
 2976                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2977                    if other_selections.is_empty() {
 2978                        return;
 2979                    }
 2980                    this.selections.change_with(cx, |selections| {
 2981                        selections.select_anchors(other_selections);
 2982                    });
 2983                }
 2984                _ => {}
 2985            });
 2986
 2987        let this_subscription =
 2988            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2989                EditorEvent::SelectionsChanged { local: true } => {
 2990                    let these_selections = this.selections.disjoint.to_vec();
 2991                    if these_selections.is_empty() {
 2992                        return;
 2993                    }
 2994                    other.update(cx, |other_editor, cx| {
 2995                        other_editor.selections.change_with(cx, |selections| {
 2996                            selections.select_anchors(these_selections);
 2997                        })
 2998                    });
 2999                }
 3000                _ => {}
 3001            });
 3002
 3003        Subscription::join(other_subscription, this_subscription)
 3004    }
 3005
 3006    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3007    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3008    /// effects of selection change occur at the end of the transaction.
 3009    pub fn change_selections<R>(
 3010        &mut self,
 3011        autoscroll: Option<Autoscroll>,
 3012        window: &mut Window,
 3013        cx: &mut Context<Self>,
 3014        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3015    ) -> R {
 3016        self.change_selections_inner(true, autoscroll, window, cx, change)
 3017    }
 3018
 3019    pub(crate) fn change_selections_without_updating_completions<R>(
 3020        &mut self,
 3021        autoscroll: Option<Autoscroll>,
 3022        window: &mut Window,
 3023        cx: &mut Context<Self>,
 3024        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3025    ) -> R {
 3026        self.change_selections_inner(false, autoscroll, window, cx, change)
 3027    }
 3028
 3029    fn change_selections_inner<R>(
 3030        &mut self,
 3031        should_update_completions: bool,
 3032        autoscroll: Option<Autoscroll>,
 3033        window: &mut Window,
 3034        cx: &mut Context<Self>,
 3035        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3036    ) -> R {
 3037        if let Some(state) = &mut self.deferred_selection_effects_state {
 3038            state.autoscroll = autoscroll.or(state.autoscroll);
 3039            state.should_update_completions = should_update_completions;
 3040            let (changed, result) = self.selections.change_with(cx, change);
 3041            state.changed |= changed;
 3042            return result;
 3043        }
 3044        let mut state = DeferredSelectionEffectsState {
 3045            changed: false,
 3046            should_update_completions,
 3047            autoscroll,
 3048            old_cursor_position: self.selections.newest_anchor().head(),
 3049            history_entry: SelectionHistoryEntry {
 3050                selections: self.selections.disjoint_anchors(),
 3051                select_next_state: self.select_next_state.clone(),
 3052                select_prev_state: self.select_prev_state.clone(),
 3053                add_selections_state: self.add_selections_state.clone(),
 3054            },
 3055        };
 3056        let (changed, result) = self.selections.change_with(cx, change);
 3057        state.changed = state.changed || changed;
 3058        if self.defer_selection_effects {
 3059            self.deferred_selection_effects_state = Some(state);
 3060        } else {
 3061            self.apply_selection_effects(state, window, cx);
 3062        }
 3063        result
 3064    }
 3065
 3066    /// Defers the effects of selection change, so that the effects of multiple calls to
 3067    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3068    /// to selection history and the state of popovers based on selection position aren't
 3069    /// erroneously updated.
 3070    pub fn with_selection_effects_deferred<R>(
 3071        &mut self,
 3072        window: &mut Window,
 3073        cx: &mut Context<Self>,
 3074        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3075    ) -> R {
 3076        let already_deferred = self.defer_selection_effects;
 3077        self.defer_selection_effects = true;
 3078        let result = update(self, window, cx);
 3079        if !already_deferred {
 3080            self.defer_selection_effects = false;
 3081            if let Some(state) = self.deferred_selection_effects_state.take() {
 3082                self.apply_selection_effects(state, window, cx);
 3083            }
 3084        }
 3085        result
 3086    }
 3087
 3088    fn apply_selection_effects(
 3089        &mut self,
 3090        state: DeferredSelectionEffectsState,
 3091        window: &mut Window,
 3092        cx: &mut Context<Self>,
 3093    ) {
 3094        if state.changed {
 3095            self.selection_history.push(state.history_entry);
 3096
 3097            if let Some(autoscroll) = state.autoscroll {
 3098                self.request_autoscroll(autoscroll, cx);
 3099            }
 3100
 3101            let old_cursor_position = &state.old_cursor_position;
 3102
 3103            self.selections_did_change(
 3104                true,
 3105                &old_cursor_position,
 3106                state.should_update_completions,
 3107                window,
 3108                cx,
 3109            );
 3110
 3111            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3112                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3113            }
 3114        }
 3115    }
 3116
 3117    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3118    where
 3119        I: IntoIterator<Item = (Range<S>, T)>,
 3120        S: ToOffset,
 3121        T: Into<Arc<str>>,
 3122    {
 3123        if self.read_only(cx) {
 3124            return;
 3125        }
 3126
 3127        self.buffer
 3128            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3129    }
 3130
 3131    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3132    where
 3133        I: IntoIterator<Item = (Range<S>, T)>,
 3134        S: ToOffset,
 3135        T: Into<Arc<str>>,
 3136    {
 3137        if self.read_only(cx) {
 3138            return;
 3139        }
 3140
 3141        self.buffer.update(cx, |buffer, cx| {
 3142            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3143        });
 3144    }
 3145
 3146    pub fn edit_with_block_indent<I, S, T>(
 3147        &mut self,
 3148        edits: I,
 3149        original_indent_columns: Vec<Option<u32>>,
 3150        cx: &mut Context<Self>,
 3151    ) where
 3152        I: IntoIterator<Item = (Range<S>, T)>,
 3153        S: ToOffset,
 3154        T: Into<Arc<str>>,
 3155    {
 3156        if self.read_only(cx) {
 3157            return;
 3158        }
 3159
 3160        self.buffer.update(cx, |buffer, cx| {
 3161            buffer.edit(
 3162                edits,
 3163                Some(AutoindentMode::Block {
 3164                    original_indent_columns,
 3165                }),
 3166                cx,
 3167            )
 3168        });
 3169    }
 3170
 3171    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3172        self.hide_context_menu(window, cx);
 3173
 3174        match phase {
 3175            SelectPhase::Begin {
 3176                position,
 3177                add,
 3178                click_count,
 3179            } => self.begin_selection(position, add, click_count, window, cx),
 3180            SelectPhase::BeginColumnar {
 3181                position,
 3182                goal_column,
 3183                reset,
 3184            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3185            SelectPhase::Extend {
 3186                position,
 3187                click_count,
 3188            } => self.extend_selection(position, click_count, window, cx),
 3189            SelectPhase::Update {
 3190                position,
 3191                goal_column,
 3192                scroll_delta,
 3193            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3194            SelectPhase::End => self.end_selection(window, cx),
 3195        }
 3196    }
 3197
 3198    fn extend_selection(
 3199        &mut self,
 3200        position: DisplayPoint,
 3201        click_count: usize,
 3202        window: &mut Window,
 3203        cx: &mut Context<Self>,
 3204    ) {
 3205        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3206        let tail = self.selections.newest::<usize>(cx).tail();
 3207        self.begin_selection(position, false, click_count, window, cx);
 3208
 3209        let position = position.to_offset(&display_map, Bias::Left);
 3210        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3211
 3212        let mut pending_selection = self
 3213            .selections
 3214            .pending_anchor()
 3215            .expect("extend_selection not called with pending selection");
 3216        if position >= tail {
 3217            pending_selection.start = tail_anchor;
 3218        } else {
 3219            pending_selection.end = tail_anchor;
 3220            pending_selection.reversed = true;
 3221        }
 3222
 3223        let mut pending_mode = self.selections.pending_mode().unwrap();
 3224        match &mut pending_mode {
 3225            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3226            _ => {}
 3227        }
 3228
 3229        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3230
 3231        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3232            s.set_pending(pending_selection, pending_mode)
 3233        });
 3234    }
 3235
 3236    fn begin_selection(
 3237        &mut self,
 3238        position: DisplayPoint,
 3239        add: bool,
 3240        click_count: usize,
 3241        window: &mut Window,
 3242        cx: &mut Context<Self>,
 3243    ) {
 3244        if !self.focus_handle.is_focused(window) {
 3245            self.last_focused_descendant = None;
 3246            window.focus(&self.focus_handle);
 3247        }
 3248
 3249        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3250        let buffer = &display_map.buffer_snapshot;
 3251        let position = display_map.clip_point(position, Bias::Left);
 3252
 3253        let start;
 3254        let end;
 3255        let mode;
 3256        let mut auto_scroll;
 3257        match click_count {
 3258            1 => {
 3259                start = buffer.anchor_before(position.to_point(&display_map));
 3260                end = start;
 3261                mode = SelectMode::Character;
 3262                auto_scroll = true;
 3263            }
 3264            2 => {
 3265                let range = movement::surrounding_word(&display_map, position);
 3266                start = buffer.anchor_before(range.start.to_point(&display_map));
 3267                end = buffer.anchor_before(range.end.to_point(&display_map));
 3268                mode = SelectMode::Word(start..end);
 3269                auto_scroll = true;
 3270            }
 3271            3 => {
 3272                let position = display_map
 3273                    .clip_point(position, Bias::Left)
 3274                    .to_point(&display_map);
 3275                let line_start = display_map.prev_line_boundary(position).0;
 3276                let next_line_start = buffer.clip_point(
 3277                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3278                    Bias::Left,
 3279                );
 3280                start = buffer.anchor_before(line_start);
 3281                end = buffer.anchor_before(next_line_start);
 3282                mode = SelectMode::Line(start..end);
 3283                auto_scroll = true;
 3284            }
 3285            _ => {
 3286                start = buffer.anchor_before(0);
 3287                end = buffer.anchor_before(buffer.len());
 3288                mode = SelectMode::All;
 3289                auto_scroll = false;
 3290            }
 3291        }
 3292        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3293
 3294        let point_to_delete: Option<usize> = {
 3295            let selected_points: Vec<Selection<Point>> =
 3296                self.selections.disjoint_in_range(start..end, cx);
 3297
 3298            if !add || click_count > 1 {
 3299                None
 3300            } else if !selected_points.is_empty() {
 3301                Some(selected_points[0].id)
 3302            } else {
 3303                let clicked_point_already_selected =
 3304                    self.selections.disjoint.iter().find(|selection| {
 3305                        selection.start.to_point(buffer) == start.to_point(buffer)
 3306                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3307                    });
 3308
 3309                clicked_point_already_selected.map(|selection| selection.id)
 3310            }
 3311        };
 3312
 3313        let selections_count = self.selections.count();
 3314
 3315        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3316            if let Some(point_to_delete) = point_to_delete {
 3317                s.delete(point_to_delete);
 3318
 3319                if selections_count == 1 {
 3320                    s.set_pending_anchor_range(start..end, mode);
 3321                }
 3322            } else {
 3323                if !add {
 3324                    s.clear_disjoint();
 3325                }
 3326
 3327                s.set_pending_anchor_range(start..end, mode);
 3328            }
 3329        });
 3330    }
 3331
 3332    fn begin_columnar_selection(
 3333        &mut self,
 3334        position: DisplayPoint,
 3335        goal_column: u32,
 3336        reset: bool,
 3337        window: &mut Window,
 3338        cx: &mut Context<Self>,
 3339    ) {
 3340        if !self.focus_handle.is_focused(window) {
 3341            self.last_focused_descendant = None;
 3342            window.focus(&self.focus_handle);
 3343        }
 3344
 3345        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3346
 3347        if reset {
 3348            let pointer_position = display_map
 3349                .buffer_snapshot
 3350                .anchor_before(position.to_point(&display_map));
 3351
 3352            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3353                s.clear_disjoint();
 3354                s.set_pending_anchor_range(
 3355                    pointer_position..pointer_position,
 3356                    SelectMode::Character,
 3357                );
 3358            });
 3359            if position.column() != goal_column {
 3360                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3361            } else {
 3362                self.columnar_display_point = None;
 3363            }
 3364        }
 3365
 3366        let tail = self.selections.newest::<Point>(cx).tail();
 3367        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3368
 3369        if !reset {
 3370            self.columnar_display_point = None;
 3371            self.select_columns(
 3372                tail.to_display_point(&display_map),
 3373                position,
 3374                goal_column,
 3375                &display_map,
 3376                window,
 3377                cx,
 3378            );
 3379        }
 3380    }
 3381
 3382    fn update_selection(
 3383        &mut self,
 3384        position: DisplayPoint,
 3385        goal_column: u32,
 3386        scroll_delta: gpui::Point<f32>,
 3387        window: &mut Window,
 3388        cx: &mut Context<Self>,
 3389    ) {
 3390        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3391
 3392        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3393            let tail = self
 3394                .columnar_display_point
 3395                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3396            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3397        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3398            let buffer = self.buffer.read(cx).snapshot(cx);
 3399            let head;
 3400            let tail;
 3401            let mode = self.selections.pending_mode().unwrap();
 3402            match &mode {
 3403                SelectMode::Character => {
 3404                    head = position.to_point(&display_map);
 3405                    tail = pending.tail().to_point(&buffer);
 3406                }
 3407                SelectMode::Word(original_range) => {
 3408                    let original_display_range = original_range.start.to_display_point(&display_map)
 3409                        ..original_range.end.to_display_point(&display_map);
 3410                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3411                        ..original_display_range.end.to_point(&display_map);
 3412                    if movement::is_inside_word(&display_map, position)
 3413                        || original_display_range.contains(&position)
 3414                    {
 3415                        let word_range = movement::surrounding_word(&display_map, position);
 3416                        if word_range.start < original_display_range.start {
 3417                            head = word_range.start.to_point(&display_map);
 3418                        } else {
 3419                            head = word_range.end.to_point(&display_map);
 3420                        }
 3421                    } else {
 3422                        head = position.to_point(&display_map);
 3423                    }
 3424
 3425                    if head <= original_buffer_range.start {
 3426                        tail = original_buffer_range.end;
 3427                    } else {
 3428                        tail = original_buffer_range.start;
 3429                    }
 3430                }
 3431                SelectMode::Line(original_range) => {
 3432                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3433
 3434                    let position = display_map
 3435                        .clip_point(position, Bias::Left)
 3436                        .to_point(&display_map);
 3437                    let line_start = display_map.prev_line_boundary(position).0;
 3438                    let next_line_start = buffer.clip_point(
 3439                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3440                        Bias::Left,
 3441                    );
 3442
 3443                    if line_start < original_range.start {
 3444                        head = line_start
 3445                    } else {
 3446                        head = next_line_start
 3447                    }
 3448
 3449                    if head <= original_range.start {
 3450                        tail = original_range.end;
 3451                    } else {
 3452                        tail = original_range.start;
 3453                    }
 3454                }
 3455                SelectMode::All => {
 3456                    return;
 3457                }
 3458            };
 3459
 3460            if head < tail {
 3461                pending.start = buffer.anchor_before(head);
 3462                pending.end = buffer.anchor_before(tail);
 3463                pending.reversed = true;
 3464            } else {
 3465                pending.start = buffer.anchor_before(tail);
 3466                pending.end = buffer.anchor_before(head);
 3467                pending.reversed = false;
 3468            }
 3469
 3470            self.change_selections(None, window, cx, |s| {
 3471                s.set_pending(pending, mode);
 3472            });
 3473        } else {
 3474            log::error!("update_selection dispatched with no pending selection");
 3475            return;
 3476        }
 3477
 3478        self.apply_scroll_delta(scroll_delta, window, cx);
 3479        cx.notify();
 3480    }
 3481
 3482    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3483        self.columnar_selection_tail.take();
 3484        if self.selections.pending_anchor().is_some() {
 3485            let selections = self.selections.all::<usize>(cx);
 3486            self.change_selections(None, window, cx, |s| {
 3487                s.select(selections);
 3488                s.clear_pending();
 3489            });
 3490        }
 3491    }
 3492
 3493    fn select_columns(
 3494        &mut self,
 3495        tail: DisplayPoint,
 3496        head: DisplayPoint,
 3497        goal_column: u32,
 3498        display_map: &DisplaySnapshot,
 3499        window: &mut Window,
 3500        cx: &mut Context<Self>,
 3501    ) {
 3502        let start_row = cmp::min(tail.row(), head.row());
 3503        let end_row = cmp::max(tail.row(), head.row());
 3504        let start_column = cmp::min(tail.column(), goal_column);
 3505        let end_column = cmp::max(tail.column(), goal_column);
 3506        let reversed = start_column < tail.column();
 3507
 3508        let selection_ranges = (start_row.0..=end_row.0)
 3509            .map(DisplayRow)
 3510            .filter_map(|row| {
 3511                if !display_map.is_block_line(row) {
 3512                    let start = display_map
 3513                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3514                        .to_point(display_map);
 3515                    let end = display_map
 3516                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3517                        .to_point(display_map);
 3518                    if reversed {
 3519                        Some(end..start)
 3520                    } else {
 3521                        Some(start..end)
 3522                    }
 3523                } else {
 3524                    None
 3525                }
 3526            })
 3527            .collect::<Vec<_>>();
 3528
 3529        let mut non_empty_ranges = selection_ranges
 3530            .iter()
 3531            .filter(|selection_range| selection_range.start != selection_range.end)
 3532            .peekable();
 3533
 3534        let ranges = if non_empty_ranges.peek().is_some() {
 3535            non_empty_ranges.cloned().collect()
 3536        } else {
 3537            selection_ranges
 3538        };
 3539
 3540        self.change_selections(None, window, cx, |s| {
 3541            s.select_ranges(ranges);
 3542        });
 3543        cx.notify();
 3544    }
 3545
 3546    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3547        self.selections
 3548            .all_adjusted(cx)
 3549            .iter()
 3550            .any(|selection| !selection.is_empty())
 3551    }
 3552
 3553    pub fn has_pending_nonempty_selection(&self) -> bool {
 3554        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3555            Some(Selection { start, end, .. }) => start != end,
 3556            None => false,
 3557        };
 3558
 3559        pending_nonempty_selection
 3560            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3561    }
 3562
 3563    pub fn has_pending_selection(&self) -> bool {
 3564        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3565    }
 3566
 3567    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3568        self.selection_mark_mode = false;
 3569        self.selection_drag_state = SelectionDragState::None;
 3570
 3571        if self.clear_expanded_diff_hunks(cx) {
 3572            cx.notify();
 3573            return;
 3574        }
 3575        if self.dismiss_menus_and_popups(true, window, cx) {
 3576            return;
 3577        }
 3578
 3579        if self.mode.is_full()
 3580            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3581        {
 3582            return;
 3583        }
 3584
 3585        cx.propagate();
 3586    }
 3587
 3588    pub fn dismiss_menus_and_popups(
 3589        &mut self,
 3590        is_user_requested: bool,
 3591        window: &mut Window,
 3592        cx: &mut Context<Self>,
 3593    ) -> bool {
 3594        if self.take_rename(false, window, cx).is_some() {
 3595            return true;
 3596        }
 3597
 3598        if hide_hover(self, cx) {
 3599            return true;
 3600        }
 3601
 3602        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3603            return true;
 3604        }
 3605
 3606        if self.hide_context_menu(window, cx).is_some() {
 3607            return true;
 3608        }
 3609
 3610        if self.mouse_context_menu.take().is_some() {
 3611            return true;
 3612        }
 3613
 3614        if is_user_requested && self.discard_inline_completion(true, cx) {
 3615            return true;
 3616        }
 3617
 3618        if self.snippet_stack.pop().is_some() {
 3619            return true;
 3620        }
 3621
 3622        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3623            self.dismiss_diagnostics(cx);
 3624            return true;
 3625        }
 3626
 3627        false
 3628    }
 3629
 3630    fn linked_editing_ranges_for(
 3631        &self,
 3632        selection: Range<text::Anchor>,
 3633        cx: &App,
 3634    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3635        if self.linked_edit_ranges.is_empty() {
 3636            return None;
 3637        }
 3638        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3639            selection.end.buffer_id.and_then(|end_buffer_id| {
 3640                if selection.start.buffer_id != Some(end_buffer_id) {
 3641                    return None;
 3642                }
 3643                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3644                let snapshot = buffer.read(cx).snapshot();
 3645                self.linked_edit_ranges
 3646                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3647                    .map(|ranges| (ranges, snapshot, buffer))
 3648            })?;
 3649        use text::ToOffset as TO;
 3650        // find offset from the start of current range to current cursor position
 3651        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3652
 3653        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3654        let start_difference = start_offset - start_byte_offset;
 3655        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3656        let end_difference = end_offset - start_byte_offset;
 3657        // Current range has associated linked ranges.
 3658        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3659        for range in linked_ranges.iter() {
 3660            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3661            let end_offset = start_offset + end_difference;
 3662            let start_offset = start_offset + start_difference;
 3663            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3664                continue;
 3665            }
 3666            if self.selections.disjoint_anchor_ranges().any(|s| {
 3667                if s.start.buffer_id != selection.start.buffer_id
 3668                    || s.end.buffer_id != selection.end.buffer_id
 3669                {
 3670                    return false;
 3671                }
 3672                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3673                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3674            }) {
 3675                continue;
 3676            }
 3677            let start = buffer_snapshot.anchor_after(start_offset);
 3678            let end = buffer_snapshot.anchor_after(end_offset);
 3679            linked_edits
 3680                .entry(buffer.clone())
 3681                .or_default()
 3682                .push(start..end);
 3683        }
 3684        Some(linked_edits)
 3685    }
 3686
 3687    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3688        let text: Arc<str> = text.into();
 3689
 3690        if self.read_only(cx) {
 3691            return;
 3692        }
 3693
 3694        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3695
 3696        let selections = self.selections.all_adjusted(cx);
 3697        let mut bracket_inserted = false;
 3698        let mut edits = Vec::new();
 3699        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3700        let mut new_selections = Vec::with_capacity(selections.len());
 3701        let mut new_autoclose_regions = Vec::new();
 3702        let snapshot = self.buffer.read(cx).read(cx);
 3703        let mut clear_linked_edit_ranges = false;
 3704
 3705        for (selection, autoclose_region) in
 3706            self.selections_with_autoclose_regions(selections, &snapshot)
 3707        {
 3708            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3709                // Determine if the inserted text matches the opening or closing
 3710                // bracket of any of this language's bracket pairs.
 3711                let mut bracket_pair = None;
 3712                let mut is_bracket_pair_start = false;
 3713                let mut is_bracket_pair_end = false;
 3714                if !text.is_empty() {
 3715                    let mut bracket_pair_matching_end = None;
 3716                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3717                    //  and they are removing the character that triggered IME popup.
 3718                    for (pair, enabled) in scope.brackets() {
 3719                        if !pair.close && !pair.surround {
 3720                            continue;
 3721                        }
 3722
 3723                        if enabled && pair.start.ends_with(text.as_ref()) {
 3724                            let prefix_len = pair.start.len() - text.len();
 3725                            let preceding_text_matches_prefix = prefix_len == 0
 3726                                || (selection.start.column >= (prefix_len as u32)
 3727                                    && snapshot.contains_str_at(
 3728                                        Point::new(
 3729                                            selection.start.row,
 3730                                            selection.start.column - (prefix_len as u32),
 3731                                        ),
 3732                                        &pair.start[..prefix_len],
 3733                                    ));
 3734                            if preceding_text_matches_prefix {
 3735                                bracket_pair = Some(pair.clone());
 3736                                is_bracket_pair_start = true;
 3737                                break;
 3738                            }
 3739                        }
 3740                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3741                        {
 3742                            // take first bracket pair matching end, but don't break in case a later bracket
 3743                            // pair matches start
 3744                            bracket_pair_matching_end = Some(pair.clone());
 3745                        }
 3746                    }
 3747                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3748                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3749                        is_bracket_pair_end = true;
 3750                    }
 3751                }
 3752
 3753                if let Some(bracket_pair) = bracket_pair {
 3754                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3755                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3756                    let auto_surround =
 3757                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3758                    if selection.is_empty() {
 3759                        if is_bracket_pair_start {
 3760                            // If the inserted text is a suffix of an opening bracket and the
 3761                            // selection is preceded by the rest of the opening bracket, then
 3762                            // insert the closing bracket.
 3763                            let following_text_allows_autoclose = snapshot
 3764                                .chars_at(selection.start)
 3765                                .next()
 3766                                .map_or(true, |c| scope.should_autoclose_before(c));
 3767
 3768                            let preceding_text_allows_autoclose = selection.start.column == 0
 3769                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3770                                    true,
 3771                                    |c| {
 3772                                        bracket_pair.start != bracket_pair.end
 3773                                            || !snapshot
 3774                                                .char_classifier_at(selection.start)
 3775                                                .is_word(c)
 3776                                    },
 3777                                );
 3778
 3779                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3780                                && bracket_pair.start.len() == 1
 3781                            {
 3782                                let target = bracket_pair.start.chars().next().unwrap();
 3783                                let current_line_count = snapshot
 3784                                    .reversed_chars_at(selection.start)
 3785                                    .take_while(|&c| c != '\n')
 3786                                    .filter(|&c| c == target)
 3787                                    .count();
 3788                                current_line_count % 2 == 1
 3789                            } else {
 3790                                false
 3791                            };
 3792
 3793                            if autoclose
 3794                                && bracket_pair.close
 3795                                && following_text_allows_autoclose
 3796                                && preceding_text_allows_autoclose
 3797                                && !is_closing_quote
 3798                            {
 3799                                let anchor = snapshot.anchor_before(selection.end);
 3800                                new_selections.push((selection.map(|_| anchor), text.len()));
 3801                                new_autoclose_regions.push((
 3802                                    anchor,
 3803                                    text.len(),
 3804                                    selection.id,
 3805                                    bracket_pair.clone(),
 3806                                ));
 3807                                edits.push((
 3808                                    selection.range(),
 3809                                    format!("{}{}", text, bracket_pair.end).into(),
 3810                                ));
 3811                                bracket_inserted = true;
 3812                                continue;
 3813                            }
 3814                        }
 3815
 3816                        if let Some(region) = autoclose_region {
 3817                            // If the selection is followed by an auto-inserted closing bracket,
 3818                            // then don't insert that closing bracket again; just move the selection
 3819                            // past the closing bracket.
 3820                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3821                                && text.as_ref() == region.pair.end.as_str();
 3822                            if should_skip {
 3823                                let anchor = snapshot.anchor_after(selection.end);
 3824                                new_selections
 3825                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3826                                continue;
 3827                            }
 3828                        }
 3829
 3830                        let always_treat_brackets_as_autoclosed = snapshot
 3831                            .language_settings_at(selection.start, cx)
 3832                            .always_treat_brackets_as_autoclosed;
 3833                        if always_treat_brackets_as_autoclosed
 3834                            && is_bracket_pair_end
 3835                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3836                        {
 3837                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3838                            // and the inserted text is a closing bracket and the selection is followed
 3839                            // by the closing bracket then move the selection past the closing bracket.
 3840                            let anchor = snapshot.anchor_after(selection.end);
 3841                            new_selections.push((selection.map(|_| anchor), text.len()));
 3842                            continue;
 3843                        }
 3844                    }
 3845                    // If an opening bracket is 1 character long and is typed while
 3846                    // text is selected, then surround that text with the bracket pair.
 3847                    else if auto_surround
 3848                        && bracket_pair.surround
 3849                        && is_bracket_pair_start
 3850                        && bracket_pair.start.chars().count() == 1
 3851                    {
 3852                        edits.push((selection.start..selection.start, text.clone()));
 3853                        edits.push((
 3854                            selection.end..selection.end,
 3855                            bracket_pair.end.as_str().into(),
 3856                        ));
 3857                        bracket_inserted = true;
 3858                        new_selections.push((
 3859                            Selection {
 3860                                id: selection.id,
 3861                                start: snapshot.anchor_after(selection.start),
 3862                                end: snapshot.anchor_before(selection.end),
 3863                                reversed: selection.reversed,
 3864                                goal: selection.goal,
 3865                            },
 3866                            0,
 3867                        ));
 3868                        continue;
 3869                    }
 3870                }
 3871            }
 3872
 3873            if self.auto_replace_emoji_shortcode
 3874                && selection.is_empty()
 3875                && text.as_ref().ends_with(':')
 3876            {
 3877                if let Some(possible_emoji_short_code) =
 3878                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3879                {
 3880                    if !possible_emoji_short_code.is_empty() {
 3881                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3882                            let emoji_shortcode_start = Point::new(
 3883                                selection.start.row,
 3884                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3885                            );
 3886
 3887                            // Remove shortcode from buffer
 3888                            edits.push((
 3889                                emoji_shortcode_start..selection.start,
 3890                                "".to_string().into(),
 3891                            ));
 3892                            new_selections.push((
 3893                                Selection {
 3894                                    id: selection.id,
 3895                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3896                                    end: snapshot.anchor_before(selection.start),
 3897                                    reversed: selection.reversed,
 3898                                    goal: selection.goal,
 3899                                },
 3900                                0,
 3901                            ));
 3902
 3903                            // Insert emoji
 3904                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3905                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3906                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3907
 3908                            continue;
 3909                        }
 3910                    }
 3911                }
 3912            }
 3913
 3914            // If not handling any auto-close operation, then just replace the selected
 3915            // text with the given input and move the selection to the end of the
 3916            // newly inserted text.
 3917            let anchor = snapshot.anchor_after(selection.end);
 3918            if !self.linked_edit_ranges.is_empty() {
 3919                let start_anchor = snapshot.anchor_before(selection.start);
 3920
 3921                let is_word_char = text.chars().next().map_or(true, |char| {
 3922                    let classifier = snapshot
 3923                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3924                        .ignore_punctuation(true);
 3925                    classifier.is_word(char)
 3926                });
 3927
 3928                if is_word_char {
 3929                    if let Some(ranges) = self
 3930                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3931                    {
 3932                        for (buffer, edits) in ranges {
 3933                            linked_edits
 3934                                .entry(buffer.clone())
 3935                                .or_default()
 3936                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3937                        }
 3938                    }
 3939                } else {
 3940                    clear_linked_edit_ranges = true;
 3941                }
 3942            }
 3943
 3944            new_selections.push((selection.map(|_| anchor), 0));
 3945            edits.push((selection.start..selection.end, text.clone()));
 3946        }
 3947
 3948        drop(snapshot);
 3949
 3950        self.transact(window, cx, |this, window, cx| {
 3951            if clear_linked_edit_ranges {
 3952                this.linked_edit_ranges.clear();
 3953            }
 3954            let initial_buffer_versions =
 3955                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3956
 3957            this.buffer.update(cx, |buffer, cx| {
 3958                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3959            });
 3960            for (buffer, edits) in linked_edits {
 3961                buffer.update(cx, |buffer, cx| {
 3962                    let snapshot = buffer.snapshot();
 3963                    let edits = edits
 3964                        .into_iter()
 3965                        .map(|(range, text)| {
 3966                            use text::ToPoint as TP;
 3967                            let end_point = TP::to_point(&range.end, &snapshot);
 3968                            let start_point = TP::to_point(&range.start, &snapshot);
 3969                            (start_point..end_point, text)
 3970                        })
 3971                        .sorted_by_key(|(range, _)| range.start);
 3972                    buffer.edit(edits, None, cx);
 3973                })
 3974            }
 3975            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3976            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3977            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3978            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3979                .zip(new_selection_deltas)
 3980                .map(|(selection, delta)| Selection {
 3981                    id: selection.id,
 3982                    start: selection.start + delta,
 3983                    end: selection.end + delta,
 3984                    reversed: selection.reversed,
 3985                    goal: SelectionGoal::None,
 3986                })
 3987                .collect::<Vec<_>>();
 3988
 3989            let mut i = 0;
 3990            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3991                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3992                let start = map.buffer_snapshot.anchor_before(position);
 3993                let end = map.buffer_snapshot.anchor_after(position);
 3994                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3995                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3996                        Ordering::Less => i += 1,
 3997                        Ordering::Greater => break,
 3998                        Ordering::Equal => {
 3999                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4000                                Ordering::Less => i += 1,
 4001                                Ordering::Equal => break,
 4002                                Ordering::Greater => break,
 4003                            }
 4004                        }
 4005                    }
 4006                }
 4007                this.autoclose_regions.insert(
 4008                    i,
 4009                    AutocloseRegion {
 4010                        selection_id,
 4011                        range: start..end,
 4012                        pair,
 4013                    },
 4014                );
 4015            }
 4016
 4017            let had_active_inline_completion = this.has_active_inline_completion();
 4018            this.change_selections_without_updating_completions(
 4019                Some(Autoscroll::fit()),
 4020                window,
 4021                cx,
 4022                |s| s.select(new_selections),
 4023            );
 4024
 4025            if !bracket_inserted {
 4026                if let Some(on_type_format_task) =
 4027                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4028                {
 4029                    on_type_format_task.detach_and_log_err(cx);
 4030                }
 4031            }
 4032
 4033            let editor_settings = EditorSettings::get_global(cx);
 4034            if bracket_inserted
 4035                && (editor_settings.auto_signature_help
 4036                    || editor_settings.show_signature_help_after_edits)
 4037            {
 4038                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4039            }
 4040
 4041            let trigger_in_words =
 4042                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4043            if this.hard_wrap.is_some() {
 4044                let latest: Range<Point> = this.selections.newest(cx).range();
 4045                if latest.is_empty()
 4046                    && this
 4047                        .buffer()
 4048                        .read(cx)
 4049                        .snapshot(cx)
 4050                        .line_len(MultiBufferRow(latest.start.row))
 4051                        == latest.start.column
 4052                {
 4053                    this.rewrap_impl(
 4054                        RewrapOptions {
 4055                            override_language_settings: true,
 4056                            preserve_existing_whitespace: true,
 4057                        },
 4058                        cx,
 4059                    )
 4060                }
 4061            }
 4062            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4063            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4064            this.refresh_inline_completion(true, false, window, cx);
 4065            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4066        });
 4067    }
 4068
 4069    fn find_possible_emoji_shortcode_at_position(
 4070        snapshot: &MultiBufferSnapshot,
 4071        position: Point,
 4072    ) -> Option<String> {
 4073        let mut chars = Vec::new();
 4074        let mut found_colon = false;
 4075        for char in snapshot.reversed_chars_at(position).take(100) {
 4076            // Found a possible emoji shortcode in the middle of the buffer
 4077            if found_colon {
 4078                if char.is_whitespace() {
 4079                    chars.reverse();
 4080                    return Some(chars.iter().collect());
 4081                }
 4082                // If the previous character is not a whitespace, we are in the middle of a word
 4083                // and we only want to complete the shortcode if the word is made up of other emojis
 4084                let mut containing_word = String::new();
 4085                for ch in snapshot
 4086                    .reversed_chars_at(position)
 4087                    .skip(chars.len() + 1)
 4088                    .take(100)
 4089                {
 4090                    if ch.is_whitespace() {
 4091                        break;
 4092                    }
 4093                    containing_word.push(ch);
 4094                }
 4095                let containing_word = containing_word.chars().rev().collect::<String>();
 4096                if util::word_consists_of_emojis(containing_word.as_str()) {
 4097                    chars.reverse();
 4098                    return Some(chars.iter().collect());
 4099                }
 4100            }
 4101
 4102            if char.is_whitespace() || !char.is_ascii() {
 4103                return None;
 4104            }
 4105            if char == ':' {
 4106                found_colon = true;
 4107            } else {
 4108                chars.push(char);
 4109            }
 4110        }
 4111        // Found a possible emoji shortcode at the beginning of the buffer
 4112        chars.reverse();
 4113        Some(chars.iter().collect())
 4114    }
 4115
 4116    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4117        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4118        self.transact(window, cx, |this, window, cx| {
 4119            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4120                let selections = this.selections.all::<usize>(cx);
 4121                let multi_buffer = this.buffer.read(cx);
 4122                let buffer = multi_buffer.snapshot(cx);
 4123                selections
 4124                    .iter()
 4125                    .map(|selection| {
 4126                        let start_point = selection.start.to_point(&buffer);
 4127                        let mut existing_indent =
 4128                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4129                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4130                        let start = selection.start;
 4131                        let end = selection.end;
 4132                        let selection_is_empty = start == end;
 4133                        let language_scope = buffer.language_scope_at(start);
 4134                        let (
 4135                            comment_delimiter,
 4136                            doc_delimiter,
 4137                            insert_extra_newline,
 4138                            indent_on_newline,
 4139                            indent_on_extra_newline,
 4140                        ) = if let Some(language) = &language_scope {
 4141                            let mut insert_extra_newline =
 4142                                insert_extra_newline_brackets(&buffer, start..end, language)
 4143                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4144
 4145                            // Comment extension on newline is allowed only for cursor selections
 4146                            let comment_delimiter = maybe!({
 4147                                if !selection_is_empty {
 4148                                    return None;
 4149                                }
 4150
 4151                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4152                                    return None;
 4153                                }
 4154
 4155                                let delimiters = language.line_comment_prefixes();
 4156                                let max_len_of_delimiter =
 4157                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4158                                let (snapshot, range) =
 4159                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4160
 4161                                let num_of_whitespaces = snapshot
 4162                                    .chars_for_range(range.clone())
 4163                                    .take_while(|c| c.is_whitespace())
 4164                                    .count();
 4165                                let comment_candidate = snapshot
 4166                                    .chars_for_range(range)
 4167                                    .skip(num_of_whitespaces)
 4168                                    .take(max_len_of_delimiter)
 4169                                    .collect::<String>();
 4170                                let (delimiter, trimmed_len) = delimiters
 4171                                    .iter()
 4172                                    .filter_map(|delimiter| {
 4173                                        let prefix = delimiter.trim_end();
 4174                                        if comment_candidate.starts_with(prefix) {
 4175                                            Some((delimiter, prefix.len()))
 4176                                        } else {
 4177                                            None
 4178                                        }
 4179                                    })
 4180                                    .max_by_key(|(_, len)| *len)?;
 4181
 4182                                let cursor_is_placed_after_comment_marker =
 4183                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4184                                if cursor_is_placed_after_comment_marker {
 4185                                    Some(delimiter.clone())
 4186                                } else {
 4187                                    None
 4188                                }
 4189                            });
 4190
 4191                            let mut indent_on_newline = IndentSize::spaces(0);
 4192                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4193
 4194                            let doc_delimiter = maybe!({
 4195                                if !selection_is_empty {
 4196                                    return None;
 4197                                }
 4198
 4199                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4200                                    return None;
 4201                                }
 4202
 4203                                let DocumentationConfig {
 4204                                    start: start_tag,
 4205                                    end: end_tag,
 4206                                    prefix: delimiter,
 4207                                    tab_size: len,
 4208                                } = language.documentation()?;
 4209
 4210                                let is_within_block_comment = buffer
 4211                                    .language_scope_at(start_point)
 4212                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4213                                if !is_within_block_comment {
 4214                                    return None;
 4215                                }
 4216
 4217                                let (snapshot, range) =
 4218                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4219
 4220                                let num_of_whitespaces = snapshot
 4221                                    .chars_for_range(range.clone())
 4222                                    .take_while(|c| c.is_whitespace())
 4223                                    .count();
 4224
 4225                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4226                                let column = start_point.column;
 4227                                let cursor_is_after_start_tag = {
 4228                                    let start_tag_len = start_tag.len();
 4229                                    let start_tag_line = snapshot
 4230                                        .chars_for_range(range.clone())
 4231                                        .skip(num_of_whitespaces)
 4232                                        .take(start_tag_len)
 4233                                        .collect::<String>();
 4234                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4235                                        num_of_whitespaces + start_tag_len <= column as usize
 4236                                    } else {
 4237                                        false
 4238                                    }
 4239                                };
 4240
 4241                                let cursor_is_after_delimiter = {
 4242                                    let delimiter_trim = delimiter.trim_end();
 4243                                    let delimiter_line = snapshot
 4244                                        .chars_for_range(range.clone())
 4245                                        .skip(num_of_whitespaces)
 4246                                        .take(delimiter_trim.len())
 4247                                        .collect::<String>();
 4248                                    if delimiter_line.starts_with(delimiter_trim) {
 4249                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4250                                    } else {
 4251                                        false
 4252                                    }
 4253                                };
 4254
 4255                                let cursor_is_before_end_tag_if_exists = {
 4256                                    let mut char_position = 0u32;
 4257                                    let mut end_tag_offset = None;
 4258
 4259                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4260                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4261                                            let chars_before_match =
 4262                                                chunk[..byte_pos].chars().count() as u32;
 4263                                            end_tag_offset =
 4264                                                Some(char_position + chars_before_match);
 4265                                            break 'outer;
 4266                                        }
 4267                                        char_position += chunk.chars().count() as u32;
 4268                                    }
 4269
 4270                                    if let Some(end_tag_offset) = end_tag_offset {
 4271                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4272                                        if cursor_is_after_start_tag {
 4273                                            if cursor_is_before_end_tag {
 4274                                                insert_extra_newline = true;
 4275                                            }
 4276                                            let cursor_is_at_start_of_end_tag =
 4277                                                column == end_tag_offset;
 4278                                            if cursor_is_at_start_of_end_tag {
 4279                                                indent_on_extra_newline.len = (*len).into();
 4280                                            }
 4281                                        }
 4282                                        cursor_is_before_end_tag
 4283                                    } else {
 4284                                        true
 4285                                    }
 4286                                };
 4287
 4288                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4289                                    && cursor_is_before_end_tag_if_exists
 4290                                {
 4291                                    if cursor_is_after_start_tag {
 4292                                        indent_on_newline.len = (*len).into();
 4293                                    }
 4294                                    Some(delimiter.clone())
 4295                                } else {
 4296                                    None
 4297                                }
 4298                            });
 4299
 4300                            (
 4301                                comment_delimiter,
 4302                                doc_delimiter,
 4303                                insert_extra_newline,
 4304                                indent_on_newline,
 4305                                indent_on_extra_newline,
 4306                            )
 4307                        } else {
 4308                            (
 4309                                None,
 4310                                None,
 4311                                false,
 4312                                IndentSize::default(),
 4313                                IndentSize::default(),
 4314                            )
 4315                        };
 4316
 4317                        let prevent_auto_indent = doc_delimiter.is_some();
 4318                        let delimiter = comment_delimiter.or(doc_delimiter);
 4319
 4320                        let capacity_for_delimiter =
 4321                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4322                        let mut new_text = String::with_capacity(
 4323                            1 + capacity_for_delimiter
 4324                                + existing_indent.len as usize
 4325                                + indent_on_newline.len as usize
 4326                                + indent_on_extra_newline.len as usize,
 4327                        );
 4328                        new_text.push('\n');
 4329                        new_text.extend(existing_indent.chars());
 4330                        new_text.extend(indent_on_newline.chars());
 4331
 4332                        if let Some(delimiter) = &delimiter {
 4333                            new_text.push_str(delimiter);
 4334                        }
 4335
 4336                        if insert_extra_newline {
 4337                            new_text.push('\n');
 4338                            new_text.extend(existing_indent.chars());
 4339                            new_text.extend(indent_on_extra_newline.chars());
 4340                        }
 4341
 4342                        let anchor = buffer.anchor_after(end);
 4343                        let new_selection = selection.map(|_| anchor);
 4344                        (
 4345                            ((start..end, new_text), prevent_auto_indent),
 4346                            (insert_extra_newline, new_selection),
 4347                        )
 4348                    })
 4349                    .unzip()
 4350            };
 4351
 4352            let mut auto_indent_edits = Vec::new();
 4353            let mut edits = Vec::new();
 4354            for (edit, prevent_auto_indent) in edits_with_flags {
 4355                if prevent_auto_indent {
 4356                    edits.push(edit);
 4357                } else {
 4358                    auto_indent_edits.push(edit);
 4359                }
 4360            }
 4361            if !edits.is_empty() {
 4362                this.edit(edits, cx);
 4363            }
 4364            if !auto_indent_edits.is_empty() {
 4365                this.edit_with_autoindent(auto_indent_edits, cx);
 4366            }
 4367
 4368            let buffer = this.buffer.read(cx).snapshot(cx);
 4369            let new_selections = selection_info
 4370                .into_iter()
 4371                .map(|(extra_newline_inserted, new_selection)| {
 4372                    let mut cursor = new_selection.end.to_point(&buffer);
 4373                    if extra_newline_inserted {
 4374                        cursor.row -= 1;
 4375                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4376                    }
 4377                    new_selection.map(|_| cursor)
 4378                })
 4379                .collect();
 4380
 4381            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4382                s.select(new_selections)
 4383            });
 4384            this.refresh_inline_completion(true, false, window, cx);
 4385        });
 4386    }
 4387
 4388    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4389        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4390
 4391        let buffer = self.buffer.read(cx);
 4392        let snapshot = buffer.snapshot(cx);
 4393
 4394        let mut edits = Vec::new();
 4395        let mut rows = Vec::new();
 4396
 4397        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4398            let cursor = selection.head();
 4399            let row = cursor.row;
 4400
 4401            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4402
 4403            let newline = "\n".to_string();
 4404            edits.push((start_of_line..start_of_line, newline));
 4405
 4406            rows.push(row + rows_inserted as u32);
 4407        }
 4408
 4409        self.transact(window, cx, |editor, window, cx| {
 4410            editor.edit(edits, cx);
 4411
 4412            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4413                let mut index = 0;
 4414                s.move_cursors_with(|map, _, _| {
 4415                    let row = rows[index];
 4416                    index += 1;
 4417
 4418                    let point = Point::new(row, 0);
 4419                    let boundary = map.next_line_boundary(point).1;
 4420                    let clipped = map.clip_point(boundary, Bias::Left);
 4421
 4422                    (clipped, SelectionGoal::None)
 4423                });
 4424            });
 4425
 4426            let mut indent_edits = Vec::new();
 4427            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4428            for row in rows {
 4429                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4430                for (row, indent) in indents {
 4431                    if indent.len == 0 {
 4432                        continue;
 4433                    }
 4434
 4435                    let text = match indent.kind {
 4436                        IndentKind::Space => " ".repeat(indent.len as usize),
 4437                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4438                    };
 4439                    let point = Point::new(row.0, 0);
 4440                    indent_edits.push((point..point, text));
 4441                }
 4442            }
 4443            editor.edit(indent_edits, cx);
 4444        });
 4445    }
 4446
 4447    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4448        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4449
 4450        let buffer = self.buffer.read(cx);
 4451        let snapshot = buffer.snapshot(cx);
 4452
 4453        let mut edits = Vec::new();
 4454        let mut rows = Vec::new();
 4455        let mut rows_inserted = 0;
 4456
 4457        for selection in self.selections.all_adjusted(cx) {
 4458            let cursor = selection.head();
 4459            let row = cursor.row;
 4460
 4461            let point = Point::new(row + 1, 0);
 4462            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4463
 4464            let newline = "\n".to_string();
 4465            edits.push((start_of_line..start_of_line, newline));
 4466
 4467            rows_inserted += 1;
 4468            rows.push(row + rows_inserted);
 4469        }
 4470
 4471        self.transact(window, cx, |editor, window, cx| {
 4472            editor.edit(edits, cx);
 4473
 4474            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4475                let mut index = 0;
 4476                s.move_cursors_with(|map, _, _| {
 4477                    let row = rows[index];
 4478                    index += 1;
 4479
 4480                    let point = Point::new(row, 0);
 4481                    let boundary = map.next_line_boundary(point).1;
 4482                    let clipped = map.clip_point(boundary, Bias::Left);
 4483
 4484                    (clipped, SelectionGoal::None)
 4485                });
 4486            });
 4487
 4488            let mut indent_edits = Vec::new();
 4489            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4490            for row in rows {
 4491                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4492                for (row, indent) in indents {
 4493                    if indent.len == 0 {
 4494                        continue;
 4495                    }
 4496
 4497                    let text = match indent.kind {
 4498                        IndentKind::Space => " ".repeat(indent.len as usize),
 4499                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4500                    };
 4501                    let point = Point::new(row.0, 0);
 4502                    indent_edits.push((point..point, text));
 4503                }
 4504            }
 4505            editor.edit(indent_edits, cx);
 4506        });
 4507    }
 4508
 4509    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4510        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4511            original_indent_columns: Vec::new(),
 4512        });
 4513        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4514    }
 4515
 4516    fn insert_with_autoindent_mode(
 4517        &mut self,
 4518        text: &str,
 4519        autoindent_mode: Option<AutoindentMode>,
 4520        window: &mut Window,
 4521        cx: &mut Context<Self>,
 4522    ) {
 4523        if self.read_only(cx) {
 4524            return;
 4525        }
 4526
 4527        let text: Arc<str> = text.into();
 4528        self.transact(window, cx, |this, window, cx| {
 4529            let old_selections = this.selections.all_adjusted(cx);
 4530            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4531                let anchors = {
 4532                    let snapshot = buffer.read(cx);
 4533                    old_selections
 4534                        .iter()
 4535                        .map(|s| {
 4536                            let anchor = snapshot.anchor_after(s.head());
 4537                            s.map(|_| anchor)
 4538                        })
 4539                        .collect::<Vec<_>>()
 4540                };
 4541                buffer.edit(
 4542                    old_selections
 4543                        .iter()
 4544                        .map(|s| (s.start..s.end, text.clone())),
 4545                    autoindent_mode,
 4546                    cx,
 4547                );
 4548                anchors
 4549            });
 4550
 4551            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4552                s.select_anchors(selection_anchors);
 4553            });
 4554
 4555            cx.notify();
 4556        });
 4557    }
 4558
 4559    fn trigger_completion_on_input(
 4560        &mut self,
 4561        text: &str,
 4562        trigger_in_words: bool,
 4563        window: &mut Window,
 4564        cx: &mut Context<Self>,
 4565    ) {
 4566        let completions_source = self
 4567            .context_menu
 4568            .borrow()
 4569            .as_ref()
 4570            .and_then(|menu| match menu {
 4571                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4572                CodeContextMenu::CodeActions(_) => None,
 4573            });
 4574
 4575        match completions_source {
 4576            Some(CompletionsMenuSource::Words) => {
 4577                self.show_word_completions(&ShowWordCompletions, window, cx)
 4578            }
 4579            Some(CompletionsMenuSource::Normal)
 4580            | Some(CompletionsMenuSource::SnippetChoices)
 4581            | None
 4582                if self.is_completion_trigger(
 4583                    text,
 4584                    trigger_in_words,
 4585                    completions_source.is_some(),
 4586                    cx,
 4587                ) =>
 4588            {
 4589                self.show_completions(
 4590                    &ShowCompletions {
 4591                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4592                    },
 4593                    window,
 4594                    cx,
 4595                )
 4596            }
 4597            _ => {
 4598                self.hide_context_menu(window, cx);
 4599            }
 4600        }
 4601    }
 4602
 4603    fn is_completion_trigger(
 4604        &self,
 4605        text: &str,
 4606        trigger_in_words: bool,
 4607        menu_is_open: bool,
 4608        cx: &mut Context<Self>,
 4609    ) -> bool {
 4610        let position = self.selections.newest_anchor().head();
 4611        let multibuffer = self.buffer.read(cx);
 4612        let Some(buffer) = position
 4613            .buffer_id
 4614            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4615        else {
 4616            return false;
 4617        };
 4618
 4619        if let Some(completion_provider) = &self.completion_provider {
 4620            completion_provider.is_completion_trigger(
 4621                &buffer,
 4622                position.text_anchor,
 4623                text,
 4624                trigger_in_words,
 4625                menu_is_open,
 4626                cx,
 4627            )
 4628        } else {
 4629            false
 4630        }
 4631    }
 4632
 4633    /// If any empty selections is touching the start of its innermost containing autoclose
 4634    /// region, expand it to select the brackets.
 4635    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4636        let selections = self.selections.all::<usize>(cx);
 4637        let buffer = self.buffer.read(cx).read(cx);
 4638        let new_selections = self
 4639            .selections_with_autoclose_regions(selections, &buffer)
 4640            .map(|(mut selection, region)| {
 4641                if !selection.is_empty() {
 4642                    return selection;
 4643                }
 4644
 4645                if let Some(region) = region {
 4646                    let mut range = region.range.to_offset(&buffer);
 4647                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4648                        range.start -= region.pair.start.len();
 4649                        if buffer.contains_str_at(range.start, &region.pair.start)
 4650                            && buffer.contains_str_at(range.end, &region.pair.end)
 4651                        {
 4652                            range.end += region.pair.end.len();
 4653                            selection.start = range.start;
 4654                            selection.end = range.end;
 4655
 4656                            return selection;
 4657                        }
 4658                    }
 4659                }
 4660
 4661                let always_treat_brackets_as_autoclosed = buffer
 4662                    .language_settings_at(selection.start, cx)
 4663                    .always_treat_brackets_as_autoclosed;
 4664
 4665                if !always_treat_brackets_as_autoclosed {
 4666                    return selection;
 4667                }
 4668
 4669                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4670                    for (pair, enabled) in scope.brackets() {
 4671                        if !enabled || !pair.close {
 4672                            continue;
 4673                        }
 4674
 4675                        if buffer.contains_str_at(selection.start, &pair.end) {
 4676                            let pair_start_len = pair.start.len();
 4677                            if buffer.contains_str_at(
 4678                                selection.start.saturating_sub(pair_start_len),
 4679                                &pair.start,
 4680                            ) {
 4681                                selection.start -= pair_start_len;
 4682                                selection.end += pair.end.len();
 4683
 4684                                return selection;
 4685                            }
 4686                        }
 4687                    }
 4688                }
 4689
 4690                selection
 4691            })
 4692            .collect();
 4693
 4694        drop(buffer);
 4695        self.change_selections(None, window, cx, |selections| {
 4696            selections.select(new_selections)
 4697        });
 4698    }
 4699
 4700    /// Iterate the given selections, and for each one, find the smallest surrounding
 4701    /// autoclose region. This uses the ordering of the selections and the autoclose
 4702    /// regions to avoid repeated comparisons.
 4703    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4704        &'a self,
 4705        selections: impl IntoIterator<Item = Selection<D>>,
 4706        buffer: &'a MultiBufferSnapshot,
 4707    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4708        let mut i = 0;
 4709        let mut regions = self.autoclose_regions.as_slice();
 4710        selections.into_iter().map(move |selection| {
 4711            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4712
 4713            let mut enclosing = None;
 4714            while let Some(pair_state) = regions.get(i) {
 4715                if pair_state.range.end.to_offset(buffer) < range.start {
 4716                    regions = &regions[i + 1..];
 4717                    i = 0;
 4718                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4719                    break;
 4720                } else {
 4721                    if pair_state.selection_id == selection.id {
 4722                        enclosing = Some(pair_state);
 4723                    }
 4724                    i += 1;
 4725                }
 4726            }
 4727
 4728            (selection, enclosing)
 4729        })
 4730    }
 4731
 4732    /// Remove any autoclose regions that no longer contain their selection.
 4733    fn invalidate_autoclose_regions(
 4734        &mut self,
 4735        mut selections: &[Selection<Anchor>],
 4736        buffer: &MultiBufferSnapshot,
 4737    ) {
 4738        self.autoclose_regions.retain(|state| {
 4739            let mut i = 0;
 4740            while let Some(selection) = selections.get(i) {
 4741                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4742                    selections = &selections[1..];
 4743                    continue;
 4744                }
 4745                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4746                    break;
 4747                }
 4748                if selection.id == state.selection_id {
 4749                    return true;
 4750                } else {
 4751                    i += 1;
 4752                }
 4753            }
 4754            false
 4755        });
 4756    }
 4757
 4758    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4759        let offset = position.to_offset(buffer);
 4760        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4761        if offset > word_range.start && kind == Some(CharKind::Word) {
 4762            Some(
 4763                buffer
 4764                    .text_for_range(word_range.start..offset)
 4765                    .collect::<String>(),
 4766            )
 4767        } else {
 4768            None
 4769        }
 4770    }
 4771
 4772    pub fn toggle_inline_values(
 4773        &mut self,
 4774        _: &ToggleInlineValues,
 4775        _: &mut Window,
 4776        cx: &mut Context<Self>,
 4777    ) {
 4778        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4779
 4780        self.refresh_inline_values(cx);
 4781    }
 4782
 4783    pub fn toggle_inlay_hints(
 4784        &mut self,
 4785        _: &ToggleInlayHints,
 4786        _: &mut Window,
 4787        cx: &mut Context<Self>,
 4788    ) {
 4789        self.refresh_inlay_hints(
 4790            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4791            cx,
 4792        );
 4793    }
 4794
 4795    pub fn inlay_hints_enabled(&self) -> bool {
 4796        self.inlay_hint_cache.enabled
 4797    }
 4798
 4799    pub fn inline_values_enabled(&self) -> bool {
 4800        self.inline_value_cache.enabled
 4801    }
 4802
 4803    #[cfg(any(test, feature = "test-support"))]
 4804    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4805        self.display_map
 4806            .read(cx)
 4807            .current_inlays()
 4808            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4809            .cloned()
 4810            .collect()
 4811    }
 4812
 4813    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4814        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4815            return;
 4816        }
 4817
 4818        let reason_description = reason.description();
 4819        let ignore_debounce = matches!(
 4820            reason,
 4821            InlayHintRefreshReason::SettingsChange(_)
 4822                | InlayHintRefreshReason::Toggle(_)
 4823                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4824                | InlayHintRefreshReason::ModifiersChanged(_)
 4825        );
 4826        let (invalidate_cache, required_languages) = match reason {
 4827            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4828                match self.inlay_hint_cache.modifiers_override(enabled) {
 4829                    Some(enabled) => {
 4830                        if enabled {
 4831                            (InvalidationStrategy::RefreshRequested, None)
 4832                        } else {
 4833                            self.splice_inlays(
 4834                                &self
 4835                                    .visible_inlay_hints(cx)
 4836                                    .iter()
 4837                                    .map(|inlay| inlay.id)
 4838                                    .collect::<Vec<InlayId>>(),
 4839                                Vec::new(),
 4840                                cx,
 4841                            );
 4842                            return;
 4843                        }
 4844                    }
 4845                    None => return,
 4846                }
 4847            }
 4848            InlayHintRefreshReason::Toggle(enabled) => {
 4849                if self.inlay_hint_cache.toggle(enabled) {
 4850                    if enabled {
 4851                        (InvalidationStrategy::RefreshRequested, None)
 4852                    } else {
 4853                        self.splice_inlays(
 4854                            &self
 4855                                .visible_inlay_hints(cx)
 4856                                .iter()
 4857                                .map(|inlay| inlay.id)
 4858                                .collect::<Vec<InlayId>>(),
 4859                            Vec::new(),
 4860                            cx,
 4861                        );
 4862                        return;
 4863                    }
 4864                } else {
 4865                    return;
 4866                }
 4867            }
 4868            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4869                match self.inlay_hint_cache.update_settings(
 4870                    &self.buffer,
 4871                    new_settings,
 4872                    self.visible_inlay_hints(cx),
 4873                    cx,
 4874                ) {
 4875                    ControlFlow::Break(Some(InlaySplice {
 4876                        to_remove,
 4877                        to_insert,
 4878                    })) => {
 4879                        self.splice_inlays(&to_remove, to_insert, cx);
 4880                        return;
 4881                    }
 4882                    ControlFlow::Break(None) => return,
 4883                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4884                }
 4885            }
 4886            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4887                if let Some(InlaySplice {
 4888                    to_remove,
 4889                    to_insert,
 4890                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4891                {
 4892                    self.splice_inlays(&to_remove, to_insert, cx);
 4893                }
 4894                self.display_map.update(cx, |display_map, _| {
 4895                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4896                });
 4897                return;
 4898            }
 4899            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4900            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4901                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4902            }
 4903            InlayHintRefreshReason::RefreshRequested => {
 4904                (InvalidationStrategy::RefreshRequested, None)
 4905            }
 4906        };
 4907
 4908        if let Some(InlaySplice {
 4909            to_remove,
 4910            to_insert,
 4911        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4912            reason_description,
 4913            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4914            invalidate_cache,
 4915            ignore_debounce,
 4916            cx,
 4917        ) {
 4918            self.splice_inlays(&to_remove, to_insert, cx);
 4919        }
 4920    }
 4921
 4922    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4923        self.display_map
 4924            .read(cx)
 4925            .current_inlays()
 4926            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4927            .cloned()
 4928            .collect()
 4929    }
 4930
 4931    pub fn excerpts_for_inlay_hints_query(
 4932        &self,
 4933        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4934        cx: &mut Context<Editor>,
 4935    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4936        let Some(project) = self.project.as_ref() else {
 4937            return HashMap::default();
 4938        };
 4939        let project = project.read(cx);
 4940        let multi_buffer = self.buffer().read(cx);
 4941        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4942        let multi_buffer_visible_start = self
 4943            .scroll_manager
 4944            .anchor()
 4945            .anchor
 4946            .to_point(&multi_buffer_snapshot);
 4947        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4948            multi_buffer_visible_start
 4949                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4950            Bias::Left,
 4951        );
 4952        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4953        multi_buffer_snapshot
 4954            .range_to_buffer_ranges(multi_buffer_visible_range)
 4955            .into_iter()
 4956            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4957            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4958                let buffer_file = project::File::from_dyn(buffer.file())?;
 4959                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4960                let worktree_entry = buffer_worktree
 4961                    .read(cx)
 4962                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4963                if worktree_entry.is_ignored {
 4964                    return None;
 4965                }
 4966
 4967                let language = buffer.language()?;
 4968                if let Some(restrict_to_languages) = restrict_to_languages {
 4969                    if !restrict_to_languages.contains(language) {
 4970                        return None;
 4971                    }
 4972                }
 4973                Some((
 4974                    excerpt_id,
 4975                    (
 4976                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4977                        buffer.version().clone(),
 4978                        excerpt_visible_range,
 4979                    ),
 4980                ))
 4981            })
 4982            .collect()
 4983    }
 4984
 4985    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4986        TextLayoutDetails {
 4987            text_system: window.text_system().clone(),
 4988            editor_style: self.style.clone().unwrap(),
 4989            rem_size: window.rem_size(),
 4990            scroll_anchor: self.scroll_manager.anchor(),
 4991            visible_rows: self.visible_line_count(),
 4992            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4993        }
 4994    }
 4995
 4996    pub fn splice_inlays(
 4997        &self,
 4998        to_remove: &[InlayId],
 4999        to_insert: Vec<Inlay>,
 5000        cx: &mut Context<Self>,
 5001    ) {
 5002        self.display_map.update(cx, |display_map, cx| {
 5003            display_map.splice_inlays(to_remove, to_insert, cx)
 5004        });
 5005        cx.notify();
 5006    }
 5007
 5008    fn trigger_on_type_formatting(
 5009        &self,
 5010        input: String,
 5011        window: &mut Window,
 5012        cx: &mut Context<Self>,
 5013    ) -> Option<Task<Result<()>>> {
 5014        if input.len() != 1 {
 5015            return None;
 5016        }
 5017
 5018        let project = self.project.as_ref()?;
 5019        let position = self.selections.newest_anchor().head();
 5020        let (buffer, buffer_position) = self
 5021            .buffer
 5022            .read(cx)
 5023            .text_anchor_for_position(position, cx)?;
 5024
 5025        let settings = language_settings::language_settings(
 5026            buffer
 5027                .read(cx)
 5028                .language_at(buffer_position)
 5029                .map(|l| l.name()),
 5030            buffer.read(cx).file(),
 5031            cx,
 5032        );
 5033        if !settings.use_on_type_format {
 5034            return None;
 5035        }
 5036
 5037        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5038        // hence we do LSP request & edit on host side only — add formats to host's history.
 5039        let push_to_lsp_host_history = true;
 5040        // If this is not the host, append its history with new edits.
 5041        let push_to_client_history = project.read(cx).is_via_collab();
 5042
 5043        let on_type_formatting = project.update(cx, |project, cx| {
 5044            project.on_type_format(
 5045                buffer.clone(),
 5046                buffer_position,
 5047                input,
 5048                push_to_lsp_host_history,
 5049                cx,
 5050            )
 5051        });
 5052        Some(cx.spawn_in(window, async move |editor, cx| {
 5053            if let Some(transaction) = on_type_formatting.await? {
 5054                if push_to_client_history {
 5055                    buffer
 5056                        .update(cx, |buffer, _| {
 5057                            buffer.push_transaction(transaction, Instant::now());
 5058                            buffer.finalize_last_transaction();
 5059                        })
 5060                        .ok();
 5061                }
 5062                editor.update(cx, |editor, cx| {
 5063                    editor.refresh_document_highlights(cx);
 5064                })?;
 5065            }
 5066            Ok(())
 5067        }))
 5068    }
 5069
 5070    pub fn show_word_completions(
 5071        &mut self,
 5072        _: &ShowWordCompletions,
 5073        window: &mut Window,
 5074        cx: &mut Context<Self>,
 5075    ) {
 5076        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5077    }
 5078
 5079    pub fn show_completions(
 5080        &mut self,
 5081        options: &ShowCompletions,
 5082        window: &mut Window,
 5083        cx: &mut Context<Self>,
 5084    ) {
 5085        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5086    }
 5087
 5088    fn open_or_update_completions_menu(
 5089        &mut self,
 5090        requested_source: Option<CompletionsMenuSource>,
 5091        trigger: Option<&str>,
 5092        window: &mut Window,
 5093        cx: &mut Context<Self>,
 5094    ) {
 5095        if self.pending_rename.is_some() {
 5096            return;
 5097        }
 5098
 5099        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5100
 5101        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5102        // inserted and selected. To handle that case, the start of the selection is used so that
 5103        // the menu starts with all choices.
 5104        let position = self
 5105            .selections
 5106            .newest_anchor()
 5107            .start
 5108            .bias_right(&multibuffer_snapshot);
 5109        if position.diff_base_anchor.is_some() {
 5110            return;
 5111        }
 5112        let (buffer, buffer_position) =
 5113            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5114                output
 5115            } else {
 5116                return;
 5117            };
 5118        let buffer_snapshot = buffer.read(cx).snapshot();
 5119
 5120        let query: Option<Arc<String>> =
 5121            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5122
 5123        drop(multibuffer_snapshot);
 5124
 5125        let provider = match requested_source {
 5126            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5127            Some(CompletionsMenuSource::Words) => None,
 5128            Some(CompletionsMenuSource::SnippetChoices) => {
 5129                log::error!("bug: SnippetChoices requested_source is not handled");
 5130                None
 5131            }
 5132        };
 5133
 5134        let sort_completions = provider
 5135            .as_ref()
 5136            .map_or(false, |provider| provider.sort_completions());
 5137
 5138        let filter_completions = provider
 5139            .as_ref()
 5140            .map_or(true, |provider| provider.filter_completions());
 5141
 5142        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5143            if filter_completions {
 5144                menu.filter(query.clone(), provider.clone(), window, cx);
 5145            }
 5146            // When `is_incomplete` is false, no need to re-query completions when the current query
 5147            // is a suffix of the initial query.
 5148            if !menu.is_incomplete {
 5149                // If the new query is a suffix of the old query (typing more characters) and
 5150                // the previous result was complete, the existing completions can be filtered.
 5151                //
 5152                // Note that this is always true for snippet completions.
 5153                let query_matches = match (&menu.initial_query, &query) {
 5154                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5155                    (None, _) => true,
 5156                    _ => false,
 5157                };
 5158                if query_matches {
 5159                    let position_matches = if menu.initial_position == position {
 5160                        true
 5161                    } else {
 5162                        let snapshot = self.buffer.read(cx).read(cx);
 5163                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5164                    };
 5165                    if position_matches {
 5166                        return;
 5167                    }
 5168                }
 5169            }
 5170        };
 5171
 5172        let trigger_kind = match trigger {
 5173            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5174                CompletionTriggerKind::TRIGGER_CHARACTER
 5175            }
 5176            _ => CompletionTriggerKind::INVOKED,
 5177        };
 5178        let completion_context = CompletionContext {
 5179            trigger_character: trigger.and_then(|trigger| {
 5180                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5181                    Some(String::from(trigger))
 5182                } else {
 5183                    None
 5184                }
 5185            }),
 5186            trigger_kind,
 5187        };
 5188
 5189        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5190            buffer_snapshot.surrounding_word(buffer_position)
 5191        {
 5192            let word_to_exclude = buffer_snapshot
 5193                .text_for_range(word_range.clone())
 5194                .collect::<String>();
 5195            (
 5196                buffer_snapshot.anchor_before(word_range.start)
 5197                    ..buffer_snapshot.anchor_after(buffer_position),
 5198                Some(word_to_exclude),
 5199            )
 5200        } else {
 5201            (buffer_position..buffer_position, None)
 5202        };
 5203
 5204        let language = buffer_snapshot
 5205            .language_at(buffer_position)
 5206            .map(|language| language.name());
 5207
 5208        let completion_settings =
 5209            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5210
 5211        let show_completion_documentation = buffer_snapshot
 5212            .settings_at(buffer_position, cx)
 5213            .show_completion_documentation;
 5214
 5215        // The document can be large, so stay in reasonable bounds when searching for words,
 5216        // otherwise completion pop-up might be slow to appear.
 5217        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5218        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5219        let min_word_search = buffer_snapshot.clip_point(
 5220            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5221            Bias::Left,
 5222        );
 5223        let max_word_search = buffer_snapshot.clip_point(
 5224            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5225            Bias::Right,
 5226        );
 5227        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5228            ..buffer_snapshot.point_to_offset(max_word_search);
 5229
 5230        let skip_digits = query
 5231            .as_ref()
 5232            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5233
 5234        let (mut words, provider_responses) = match &provider {
 5235            Some(provider) => {
 5236                let provider_responses = provider.completions(
 5237                    position.excerpt_id,
 5238                    &buffer,
 5239                    buffer_position,
 5240                    completion_context,
 5241                    window,
 5242                    cx,
 5243                );
 5244
 5245                let words = match completion_settings.words {
 5246                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5247                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5248                        .background_spawn(async move {
 5249                            buffer_snapshot.words_in_range(WordsQuery {
 5250                                fuzzy_contents: None,
 5251                                range: word_search_range,
 5252                                skip_digits,
 5253                            })
 5254                        }),
 5255                };
 5256
 5257                (words, provider_responses)
 5258            }
 5259            None => (
 5260                cx.background_spawn(async move {
 5261                    buffer_snapshot.words_in_range(WordsQuery {
 5262                        fuzzy_contents: None,
 5263                        range: word_search_range,
 5264                        skip_digits,
 5265                    })
 5266                }),
 5267                Task::ready(Ok(Vec::new())),
 5268            ),
 5269        };
 5270
 5271        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5272
 5273        let id = post_inc(&mut self.next_completion_id);
 5274        let task = cx.spawn_in(window, async move |editor, cx| {
 5275            let Ok(()) = editor.update(cx, |this, _| {
 5276                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5277            }) else {
 5278                return;
 5279            };
 5280
 5281            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5282            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5283            let mut completions = Vec::new();
 5284            let mut is_incomplete = false;
 5285            if let Some(provider_responses) = provider_responses.await.log_err() {
 5286                if !provider_responses.is_empty() {
 5287                    for response in provider_responses {
 5288                        completions.extend(response.completions);
 5289                        is_incomplete = is_incomplete || response.is_incomplete;
 5290                    }
 5291                    if completion_settings.words == WordsCompletionMode::Fallback {
 5292                        words = Task::ready(BTreeMap::default());
 5293                    }
 5294                }
 5295            }
 5296
 5297            let mut words = words.await;
 5298            if let Some(word_to_exclude) = &word_to_exclude {
 5299                words.remove(word_to_exclude);
 5300            }
 5301            for lsp_completion in &completions {
 5302                words.remove(&lsp_completion.new_text);
 5303            }
 5304            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5305                replace_range: word_replace_range.clone(),
 5306                new_text: word.clone(),
 5307                label: CodeLabel::plain(word, None),
 5308                icon_path: None,
 5309                documentation: None,
 5310                source: CompletionSource::BufferWord {
 5311                    word_range,
 5312                    resolved: false,
 5313                },
 5314                insert_text_mode: Some(InsertTextMode::AS_IS),
 5315                confirm: None,
 5316            }));
 5317
 5318            let menu = if completions.is_empty() {
 5319                None
 5320            } else {
 5321                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5322                    let languages = editor
 5323                        .workspace
 5324                        .as_ref()
 5325                        .and_then(|(workspace, _)| workspace.upgrade())
 5326                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5327                    let menu = CompletionsMenu::new(
 5328                        id,
 5329                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5330                        sort_completions,
 5331                        show_completion_documentation,
 5332                        position,
 5333                        query.clone(),
 5334                        is_incomplete,
 5335                        buffer.clone(),
 5336                        completions.into(),
 5337                        snippet_sort_order,
 5338                        languages,
 5339                        language,
 5340                        cx,
 5341                    );
 5342
 5343                    let query = if filter_completions { query } else { None };
 5344                    let matches_task = if let Some(query) = query {
 5345                        menu.do_async_filtering(query, cx)
 5346                    } else {
 5347                        Task::ready(menu.unfiltered_matches())
 5348                    };
 5349                    (menu, matches_task)
 5350                }) else {
 5351                    return;
 5352                };
 5353
 5354                let matches = matches_task.await;
 5355
 5356                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5357                    // Newer menu already set, so exit.
 5358                    match editor.context_menu.borrow().as_ref() {
 5359                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5360                            if prev_menu.id > id {
 5361                                return;
 5362                            }
 5363                        }
 5364                        _ => {}
 5365                    };
 5366
 5367                    // Only valid to take prev_menu because it the new menu is immediately set
 5368                    // below, or the menu is hidden.
 5369                    match editor.context_menu.borrow_mut().take() {
 5370                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5371                            let position_matches =
 5372                                if prev_menu.initial_position == menu.initial_position {
 5373                                    true
 5374                                } else {
 5375                                    let snapshot = editor.buffer.read(cx).read(cx);
 5376                                    prev_menu.initial_position.to_offset(&snapshot)
 5377                                        == menu.initial_position.to_offset(&snapshot)
 5378                                };
 5379                            if position_matches {
 5380                                // Preserve markdown cache before `set_filter_results` because it will
 5381                                // try to populate the documentation cache.
 5382                                menu.preserve_markdown_cache(prev_menu);
 5383                            }
 5384                        }
 5385                        _ => {}
 5386                    };
 5387
 5388                    menu.set_filter_results(matches, provider, window, cx);
 5389                }) else {
 5390                    return;
 5391                };
 5392
 5393                menu.visible().then_some(menu)
 5394            };
 5395
 5396            editor
 5397                .update_in(cx, |editor, window, cx| {
 5398                    if editor.focus_handle.is_focused(window) {
 5399                        if let Some(menu) = menu {
 5400                            *editor.context_menu.borrow_mut() =
 5401                                Some(CodeContextMenu::Completions(menu));
 5402
 5403                            crate::hover_popover::hide_hover(editor, cx);
 5404                            if editor.show_edit_predictions_in_menu() {
 5405                                editor.update_visible_inline_completion(window, cx);
 5406                            } else {
 5407                                editor.discard_inline_completion(false, cx);
 5408                            }
 5409
 5410                            cx.notify();
 5411                            return;
 5412                        }
 5413                    }
 5414
 5415                    if editor.completion_tasks.len() <= 1 {
 5416                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5417                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5418                        // If it was already hidden and we don't show inline completions in the menu, we should
 5419                        // also show the inline-completion when available.
 5420                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5421                            editor.update_visible_inline_completion(window, cx);
 5422                        }
 5423                    }
 5424                })
 5425                .ok();
 5426        });
 5427
 5428        self.completion_tasks.push((id, task));
 5429    }
 5430
 5431    #[cfg(feature = "test-support")]
 5432    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5433        let menu = self.context_menu.borrow();
 5434        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5435            let completions = menu.completions.borrow();
 5436            Some(completions.to_vec())
 5437        } else {
 5438            None
 5439        }
 5440    }
 5441
 5442    pub fn with_completions_menu_matching_id<R>(
 5443        &self,
 5444        id: CompletionId,
 5445        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5446    ) -> R {
 5447        let mut context_menu = self.context_menu.borrow_mut();
 5448        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5449            return f(None);
 5450        };
 5451        if completions_menu.id != id {
 5452            return f(None);
 5453        }
 5454        f(Some(completions_menu))
 5455    }
 5456
 5457    pub fn confirm_completion(
 5458        &mut self,
 5459        action: &ConfirmCompletion,
 5460        window: &mut Window,
 5461        cx: &mut Context<Self>,
 5462    ) -> Option<Task<Result<()>>> {
 5463        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5464        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5465    }
 5466
 5467    pub fn confirm_completion_insert(
 5468        &mut self,
 5469        _: &ConfirmCompletionInsert,
 5470        window: &mut Window,
 5471        cx: &mut Context<Self>,
 5472    ) -> Option<Task<Result<()>>> {
 5473        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5474        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5475    }
 5476
 5477    pub fn confirm_completion_replace(
 5478        &mut self,
 5479        _: &ConfirmCompletionReplace,
 5480        window: &mut Window,
 5481        cx: &mut Context<Self>,
 5482    ) -> Option<Task<Result<()>>> {
 5483        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5484        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5485    }
 5486
 5487    pub fn compose_completion(
 5488        &mut self,
 5489        action: &ComposeCompletion,
 5490        window: &mut Window,
 5491        cx: &mut Context<Self>,
 5492    ) -> Option<Task<Result<()>>> {
 5493        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5494        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5495    }
 5496
 5497    fn do_completion(
 5498        &mut self,
 5499        item_ix: Option<usize>,
 5500        intent: CompletionIntent,
 5501        window: &mut Window,
 5502        cx: &mut Context<Editor>,
 5503    ) -> Option<Task<Result<()>>> {
 5504        use language::ToOffset as _;
 5505
 5506        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5507        else {
 5508            return None;
 5509        };
 5510
 5511        let candidate_id = {
 5512            let entries = completions_menu.entries.borrow();
 5513            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5514            if self.show_edit_predictions_in_menu() {
 5515                self.discard_inline_completion(true, cx);
 5516            }
 5517            mat.candidate_id
 5518        };
 5519
 5520        let completion = completions_menu
 5521            .completions
 5522            .borrow()
 5523            .get(candidate_id)?
 5524            .clone();
 5525        cx.stop_propagation();
 5526
 5527        let buffer_handle = completions_menu.buffer.clone();
 5528
 5529        let CompletionEdit {
 5530            new_text,
 5531            snippet,
 5532            replace_range,
 5533        } = process_completion_for_edit(
 5534            &completion,
 5535            intent,
 5536            &buffer_handle,
 5537            &completions_menu.initial_position.text_anchor,
 5538            cx,
 5539        );
 5540
 5541        let buffer = buffer_handle.read(cx);
 5542        let snapshot = self.buffer.read(cx).snapshot(cx);
 5543        let newest_anchor = self.selections.newest_anchor();
 5544        let replace_range_multibuffer = {
 5545            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5546            let multibuffer_anchor = snapshot
 5547                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5548                .unwrap()
 5549                ..snapshot
 5550                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5551                    .unwrap();
 5552            multibuffer_anchor.start.to_offset(&snapshot)
 5553                ..multibuffer_anchor.end.to_offset(&snapshot)
 5554        };
 5555        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5556            return None;
 5557        }
 5558
 5559        let old_text = buffer
 5560            .text_for_range(replace_range.clone())
 5561            .collect::<String>();
 5562        let lookbehind = newest_anchor
 5563            .start
 5564            .text_anchor
 5565            .to_offset(buffer)
 5566            .saturating_sub(replace_range.start);
 5567        let lookahead = replace_range
 5568            .end
 5569            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5570        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5571        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5572
 5573        let selections = self.selections.all::<usize>(cx);
 5574        let mut ranges = Vec::new();
 5575        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5576
 5577        for selection in &selections {
 5578            let range = if selection.id == newest_anchor.id {
 5579                replace_range_multibuffer.clone()
 5580            } else {
 5581                let mut range = selection.range();
 5582
 5583                // if prefix is present, don't duplicate it
 5584                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5585                    range.start = range.start.saturating_sub(lookbehind);
 5586
 5587                    // if suffix is also present, mimic the newest cursor and replace it
 5588                    if selection.id != newest_anchor.id
 5589                        && snapshot.contains_str_at(range.end, suffix)
 5590                    {
 5591                        range.end += lookahead;
 5592                    }
 5593                }
 5594                range
 5595            };
 5596
 5597            ranges.push(range.clone());
 5598
 5599            if !self.linked_edit_ranges.is_empty() {
 5600                let start_anchor = snapshot.anchor_before(range.start);
 5601                let end_anchor = snapshot.anchor_after(range.end);
 5602                if let Some(ranges) = self
 5603                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5604                {
 5605                    for (buffer, edits) in ranges {
 5606                        linked_edits
 5607                            .entry(buffer.clone())
 5608                            .or_default()
 5609                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5610                    }
 5611                }
 5612            }
 5613        }
 5614
 5615        let common_prefix_len = old_text
 5616            .chars()
 5617            .zip(new_text.chars())
 5618            .take_while(|(a, b)| a == b)
 5619            .map(|(a, _)| a.len_utf8())
 5620            .sum::<usize>();
 5621
 5622        cx.emit(EditorEvent::InputHandled {
 5623            utf16_range_to_replace: None,
 5624            text: new_text[common_prefix_len..].into(),
 5625        });
 5626
 5627        self.transact(window, cx, |this, window, cx| {
 5628            if let Some(mut snippet) = snippet {
 5629                snippet.text = new_text.to_string();
 5630                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5631            } else {
 5632                this.buffer.update(cx, |buffer, cx| {
 5633                    let auto_indent = match completion.insert_text_mode {
 5634                        Some(InsertTextMode::AS_IS) => None,
 5635                        _ => this.autoindent_mode.clone(),
 5636                    };
 5637                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5638                    buffer.edit(edits, auto_indent, cx);
 5639                });
 5640            }
 5641            for (buffer, edits) in linked_edits {
 5642                buffer.update(cx, |buffer, cx| {
 5643                    let snapshot = buffer.snapshot();
 5644                    let edits = edits
 5645                        .into_iter()
 5646                        .map(|(range, text)| {
 5647                            use text::ToPoint as TP;
 5648                            let end_point = TP::to_point(&range.end, &snapshot);
 5649                            let start_point = TP::to_point(&range.start, &snapshot);
 5650                            (start_point..end_point, text)
 5651                        })
 5652                        .sorted_by_key(|(range, _)| range.start);
 5653                    buffer.edit(edits, None, cx);
 5654                })
 5655            }
 5656
 5657            this.refresh_inline_completion(true, false, window, cx);
 5658        });
 5659
 5660        let show_new_completions_on_confirm = completion
 5661            .confirm
 5662            .as_ref()
 5663            .map_or(false, |confirm| confirm(intent, window, cx));
 5664        if show_new_completions_on_confirm {
 5665            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5666        }
 5667
 5668        let provider = self.completion_provider.as_ref()?;
 5669        drop(completion);
 5670        let apply_edits = provider.apply_additional_edits_for_completion(
 5671            buffer_handle,
 5672            completions_menu.completions.clone(),
 5673            candidate_id,
 5674            true,
 5675            cx,
 5676        );
 5677
 5678        let editor_settings = EditorSettings::get_global(cx);
 5679        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5680            // After the code completion is finished, users often want to know what signatures are needed.
 5681            // so we should automatically call signature_help
 5682            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5683        }
 5684
 5685        Some(cx.foreground_executor().spawn(async move {
 5686            apply_edits.await?;
 5687            Ok(())
 5688        }))
 5689    }
 5690
 5691    pub fn toggle_code_actions(
 5692        &mut self,
 5693        action: &ToggleCodeActions,
 5694        window: &mut Window,
 5695        cx: &mut Context<Self>,
 5696    ) {
 5697        let quick_launch = action.quick_launch;
 5698        let mut context_menu = self.context_menu.borrow_mut();
 5699        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5700            if code_actions.deployed_from == action.deployed_from {
 5701                // Toggle if we're selecting the same one
 5702                *context_menu = None;
 5703                cx.notify();
 5704                return;
 5705            } else {
 5706                // Otherwise, clear it and start a new one
 5707                *context_menu = None;
 5708                cx.notify();
 5709            }
 5710        }
 5711        drop(context_menu);
 5712        let snapshot = self.snapshot(window, cx);
 5713        let deployed_from = action.deployed_from.clone();
 5714        let action = action.clone();
 5715        self.completion_tasks.clear();
 5716        self.discard_inline_completion(false, cx);
 5717
 5718        let multibuffer_point = match &action.deployed_from {
 5719            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5720                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5721            }
 5722            _ => self.selections.newest::<Point>(cx).head(),
 5723        };
 5724        let Some((buffer, buffer_row)) = snapshot
 5725            .buffer_snapshot
 5726            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5727            .and_then(|(buffer_snapshot, range)| {
 5728                self.buffer()
 5729                    .read(cx)
 5730                    .buffer(buffer_snapshot.remote_id())
 5731                    .map(|buffer| (buffer, range.start.row))
 5732            })
 5733        else {
 5734            return;
 5735        };
 5736        let buffer_id = buffer.read(cx).remote_id();
 5737        let tasks = self
 5738            .tasks
 5739            .get(&(buffer_id, buffer_row))
 5740            .map(|t| Arc::new(t.to_owned()));
 5741
 5742        if !self.focus_handle.is_focused(window) {
 5743            return;
 5744        }
 5745        let project = self.project.clone();
 5746
 5747        let code_actions_task = match deployed_from {
 5748            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5749            _ => self.code_actions(buffer_row, window, cx),
 5750        };
 5751
 5752        let runnable_task = match deployed_from {
 5753            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5754            _ => {
 5755                let mut task_context_task = Task::ready(None);
 5756                if let Some(tasks) = &tasks {
 5757                    if let Some(project) = project {
 5758                        task_context_task =
 5759                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5760                    }
 5761                }
 5762
 5763                cx.spawn_in(window, {
 5764                    let buffer = buffer.clone();
 5765                    async move |editor, cx| {
 5766                        let task_context = task_context_task.await;
 5767
 5768                        let resolved_tasks =
 5769                            tasks
 5770                                .zip(task_context.clone())
 5771                                .map(|(tasks, task_context)| ResolvedTasks {
 5772                                    templates: tasks.resolve(&task_context).collect(),
 5773                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5774                                        multibuffer_point.row,
 5775                                        tasks.column,
 5776                                    )),
 5777                                });
 5778                        let debug_scenarios = editor
 5779                            .update(cx, |editor, cx| {
 5780                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5781                            })?
 5782                            .await;
 5783                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5784                    }
 5785                })
 5786            }
 5787        };
 5788
 5789        cx.spawn_in(window, async move |editor, cx| {
 5790            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5791            let code_actions = code_actions_task.await;
 5792            let spawn_straight_away = quick_launch
 5793                && resolved_tasks
 5794                    .as_ref()
 5795                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5796                && code_actions
 5797                    .as_ref()
 5798                    .map_or(true, |actions| actions.is_empty())
 5799                && debug_scenarios.is_empty();
 5800
 5801            editor.update_in(cx, |editor, window, cx| {
 5802                crate::hover_popover::hide_hover(editor, cx);
 5803                *editor.context_menu.borrow_mut() =
 5804                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5805                        buffer,
 5806                        actions: CodeActionContents::new(
 5807                            resolved_tasks,
 5808                            code_actions,
 5809                            debug_scenarios,
 5810                            task_context.unwrap_or_default(),
 5811                        ),
 5812                        selected_item: Default::default(),
 5813                        scroll_handle: UniformListScrollHandle::default(),
 5814                        deployed_from,
 5815                    }));
 5816                if spawn_straight_away {
 5817                    if let Some(task) = editor.confirm_code_action(
 5818                        &ConfirmCodeAction { item_ix: Some(0) },
 5819                        window,
 5820                        cx,
 5821                    ) {
 5822                        cx.notify();
 5823                        return task;
 5824                    }
 5825                }
 5826
 5827                Task::ready(Ok(()))
 5828            })
 5829        })
 5830        .detach_and_log_err(cx);
 5831    }
 5832
 5833    fn debug_scenarios(
 5834        &mut self,
 5835        resolved_tasks: &Option<ResolvedTasks>,
 5836        buffer: &Entity<Buffer>,
 5837        cx: &mut App,
 5838    ) -> Task<Vec<task::DebugScenario>> {
 5839        if cx.has_flag::<DebuggerFeatureFlag>() {
 5840            maybe!({
 5841                let project = self.project.as_ref()?;
 5842                let dap_store = project.read(cx).dap_store();
 5843                let mut scenarios = vec![];
 5844                let resolved_tasks = resolved_tasks.as_ref()?;
 5845                let buffer = buffer.read(cx);
 5846                let language = buffer.language()?;
 5847                let file = buffer.file();
 5848                let debug_adapter = language_settings(language.name().into(), file, cx)
 5849                    .debuggers
 5850                    .first()
 5851                    .map(SharedString::from)
 5852                    .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 5853
 5854                dap_store.update(cx, |dap_store, cx| {
 5855                    for (_, task) in &resolved_tasks.templates {
 5856                        let maybe_scenario = dap_store.debug_scenario_for_build_task(
 5857                            task.original_task().clone(),
 5858                            debug_adapter.clone().into(),
 5859                            task.display_label().to_owned().into(),
 5860                            cx,
 5861                        );
 5862                        scenarios.push(maybe_scenario);
 5863                    }
 5864                });
 5865                Some(cx.background_spawn(async move {
 5866                    let scenarios = futures::future::join_all(scenarios)
 5867                        .await
 5868                        .into_iter()
 5869                        .flatten()
 5870                        .collect::<Vec<_>>();
 5871                    scenarios
 5872                }))
 5873            })
 5874            .unwrap_or_else(|| Task::ready(vec![]))
 5875        } else {
 5876            Task::ready(vec![])
 5877        }
 5878    }
 5879
 5880    fn code_actions(
 5881        &mut self,
 5882        buffer_row: u32,
 5883        window: &mut Window,
 5884        cx: &mut Context<Self>,
 5885    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 5886        let mut task = self.code_actions_task.take();
 5887        cx.spawn_in(window, async move |editor, cx| {
 5888            while let Some(prev_task) = task {
 5889                prev_task.await.log_err();
 5890                task = editor
 5891                    .update(cx, |this, _| this.code_actions_task.take())
 5892                    .ok()?;
 5893            }
 5894
 5895            editor
 5896                .update(cx, |editor, cx| {
 5897                    editor
 5898                        .available_code_actions
 5899                        .clone()
 5900                        .and_then(|(location, code_actions)| {
 5901                            let snapshot = location.buffer.read(cx).snapshot();
 5902                            let point_range = location.range.to_point(&snapshot);
 5903                            let point_range = point_range.start.row..=point_range.end.row;
 5904                            if point_range.contains(&buffer_row) {
 5905                                Some(code_actions)
 5906                            } else {
 5907                                None
 5908                            }
 5909                        })
 5910                })
 5911                .ok()
 5912                .flatten()
 5913        })
 5914    }
 5915
 5916    pub fn confirm_code_action(
 5917        &mut self,
 5918        action: &ConfirmCodeAction,
 5919        window: &mut Window,
 5920        cx: &mut Context<Self>,
 5921    ) -> Option<Task<Result<()>>> {
 5922        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5923
 5924        let actions_menu =
 5925            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5926                menu
 5927            } else {
 5928                return None;
 5929            };
 5930
 5931        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5932        let action = actions_menu.actions.get(action_ix)?;
 5933        let title = action.label();
 5934        let buffer = actions_menu.buffer;
 5935        let workspace = self.workspace()?;
 5936
 5937        match action {
 5938            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5939                workspace.update(cx, |workspace, cx| {
 5940                    workspace.schedule_resolved_task(
 5941                        task_source_kind,
 5942                        resolved_task,
 5943                        false,
 5944                        window,
 5945                        cx,
 5946                    );
 5947
 5948                    Some(Task::ready(Ok(())))
 5949                })
 5950            }
 5951            CodeActionsItem::CodeAction {
 5952                excerpt_id,
 5953                action,
 5954                provider,
 5955            } => {
 5956                let apply_code_action =
 5957                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5958                let workspace = workspace.downgrade();
 5959                Some(cx.spawn_in(window, async move |editor, cx| {
 5960                    let project_transaction = apply_code_action.await?;
 5961                    Self::open_project_transaction(
 5962                        &editor,
 5963                        workspace,
 5964                        project_transaction,
 5965                        title,
 5966                        cx,
 5967                    )
 5968                    .await
 5969                }))
 5970            }
 5971            CodeActionsItem::DebugScenario(scenario) => {
 5972                let context = actions_menu.actions.context.clone();
 5973
 5974                workspace.update(cx, |workspace, cx| {
 5975                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5976                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5977                });
 5978                Some(Task::ready(Ok(())))
 5979            }
 5980        }
 5981    }
 5982
 5983    pub async fn open_project_transaction(
 5984        this: &WeakEntity<Editor>,
 5985        workspace: WeakEntity<Workspace>,
 5986        transaction: ProjectTransaction,
 5987        title: String,
 5988        cx: &mut AsyncWindowContext,
 5989    ) -> Result<()> {
 5990        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5991        cx.update(|_, cx| {
 5992            entries.sort_unstable_by_key(|(buffer, _)| {
 5993                buffer.read(cx).file().map(|f| f.path().clone())
 5994            });
 5995        })?;
 5996
 5997        // If the project transaction's edits are all contained within this editor, then
 5998        // avoid opening a new editor to display them.
 5999
 6000        if let Some((buffer, transaction)) = entries.first() {
 6001            if entries.len() == 1 {
 6002                let excerpt = this.update(cx, |editor, cx| {
 6003                    editor
 6004                        .buffer()
 6005                        .read(cx)
 6006                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6007                })?;
 6008                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6009                    if excerpted_buffer == *buffer {
 6010                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6011                            let excerpt_range = excerpt_range.to_offset(buffer);
 6012                            buffer
 6013                                .edited_ranges_for_transaction::<usize>(transaction)
 6014                                .all(|range| {
 6015                                    excerpt_range.start <= range.start
 6016                                        && excerpt_range.end >= range.end
 6017                                })
 6018                        })?;
 6019
 6020                        if all_edits_within_excerpt {
 6021                            return Ok(());
 6022                        }
 6023                    }
 6024                }
 6025            }
 6026        } else {
 6027            return Ok(());
 6028        }
 6029
 6030        let mut ranges_to_highlight = Vec::new();
 6031        let excerpt_buffer = cx.new(|cx| {
 6032            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6033            for (buffer_handle, transaction) in &entries {
 6034                let edited_ranges = buffer_handle
 6035                    .read(cx)
 6036                    .edited_ranges_for_transaction::<Point>(transaction)
 6037                    .collect::<Vec<_>>();
 6038                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6039                    PathKey::for_buffer(buffer_handle, cx),
 6040                    buffer_handle.clone(),
 6041                    edited_ranges,
 6042                    DEFAULT_MULTIBUFFER_CONTEXT,
 6043                    cx,
 6044                );
 6045
 6046                ranges_to_highlight.extend(ranges);
 6047            }
 6048            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6049            multibuffer
 6050        })?;
 6051
 6052        workspace.update_in(cx, |workspace, window, cx| {
 6053            let project = workspace.project().clone();
 6054            let editor =
 6055                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6056            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6057            editor.update(cx, |editor, cx| {
 6058                editor.highlight_background::<Self>(
 6059                    &ranges_to_highlight,
 6060                    |theme| theme.editor_highlighted_line_background,
 6061                    cx,
 6062                );
 6063            });
 6064        })?;
 6065
 6066        Ok(())
 6067    }
 6068
 6069    pub fn clear_code_action_providers(&mut self) {
 6070        self.code_action_providers.clear();
 6071        self.available_code_actions.take();
 6072    }
 6073
 6074    pub fn add_code_action_provider(
 6075        &mut self,
 6076        provider: Rc<dyn CodeActionProvider>,
 6077        window: &mut Window,
 6078        cx: &mut Context<Self>,
 6079    ) {
 6080        if self
 6081            .code_action_providers
 6082            .iter()
 6083            .any(|existing_provider| existing_provider.id() == provider.id())
 6084        {
 6085            return;
 6086        }
 6087
 6088        self.code_action_providers.push(provider);
 6089        self.refresh_code_actions(window, cx);
 6090    }
 6091
 6092    pub fn remove_code_action_provider(
 6093        &mut self,
 6094        id: Arc<str>,
 6095        window: &mut Window,
 6096        cx: &mut Context<Self>,
 6097    ) {
 6098        self.code_action_providers
 6099            .retain(|provider| provider.id() != id);
 6100        self.refresh_code_actions(window, cx);
 6101    }
 6102
 6103    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6104        !self.code_action_providers.is_empty()
 6105            && EditorSettings::get_global(cx).toolbar.code_actions
 6106    }
 6107
 6108    pub fn has_available_code_actions(&self) -> bool {
 6109        self.available_code_actions
 6110            .as_ref()
 6111            .is_some_and(|(_, actions)| !actions.is_empty())
 6112    }
 6113
 6114    fn render_inline_code_actions(
 6115        &self,
 6116        icon_size: ui::IconSize,
 6117        display_row: DisplayRow,
 6118        is_active: bool,
 6119        cx: &mut Context<Self>,
 6120    ) -> AnyElement {
 6121        let show_tooltip = !self.context_menu_visible();
 6122        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6123            .icon_size(icon_size)
 6124            .shape(ui::IconButtonShape::Square)
 6125            .style(ButtonStyle::Transparent)
 6126            .icon_color(ui::Color::Hidden)
 6127            .toggle_state(is_active)
 6128            .when(show_tooltip, |this| {
 6129                this.tooltip({
 6130                    let focus_handle = self.focus_handle.clone();
 6131                    move |window, cx| {
 6132                        Tooltip::for_action_in(
 6133                            "Toggle Code Actions",
 6134                            &ToggleCodeActions {
 6135                                deployed_from: None,
 6136                                quick_launch: false,
 6137                            },
 6138                            &focus_handle,
 6139                            window,
 6140                            cx,
 6141                        )
 6142                    }
 6143                })
 6144            })
 6145            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6146                window.focus(&editor.focus_handle(cx));
 6147                editor.toggle_code_actions(
 6148                    &crate::actions::ToggleCodeActions {
 6149                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6150                            display_row,
 6151                        )),
 6152                        quick_launch: false,
 6153                    },
 6154                    window,
 6155                    cx,
 6156                );
 6157            }))
 6158            .into_any_element()
 6159    }
 6160
 6161    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6162        &self.context_menu
 6163    }
 6164
 6165    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6166        let newest_selection = self.selections.newest_anchor().clone();
 6167        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6168        let buffer = self.buffer.read(cx);
 6169        if newest_selection.head().diff_base_anchor.is_some() {
 6170            return None;
 6171        }
 6172        let (start_buffer, start) =
 6173            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6174        let (end_buffer, end) =
 6175            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6176        if start_buffer != end_buffer {
 6177            return None;
 6178        }
 6179
 6180        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6181            cx.background_executor()
 6182                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6183                .await;
 6184
 6185            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6186                let providers = this.code_action_providers.clone();
 6187                let tasks = this
 6188                    .code_action_providers
 6189                    .iter()
 6190                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6191                    .collect::<Vec<_>>();
 6192                (providers, tasks)
 6193            })?;
 6194
 6195            let mut actions = Vec::new();
 6196            for (provider, provider_actions) in
 6197                providers.into_iter().zip(future::join_all(tasks).await)
 6198            {
 6199                if let Some(provider_actions) = provider_actions.log_err() {
 6200                    actions.extend(provider_actions.into_iter().map(|action| {
 6201                        AvailableCodeAction {
 6202                            excerpt_id: newest_selection.start.excerpt_id,
 6203                            action,
 6204                            provider: provider.clone(),
 6205                        }
 6206                    }));
 6207                }
 6208            }
 6209
 6210            this.update(cx, |this, cx| {
 6211                this.available_code_actions = if actions.is_empty() {
 6212                    None
 6213                } else {
 6214                    Some((
 6215                        Location {
 6216                            buffer: start_buffer,
 6217                            range: start..end,
 6218                        },
 6219                        actions.into(),
 6220                    ))
 6221                };
 6222                cx.notify();
 6223            })
 6224        }));
 6225        None
 6226    }
 6227
 6228    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6229        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6230            self.show_git_blame_inline = false;
 6231
 6232            self.show_git_blame_inline_delay_task =
 6233                Some(cx.spawn_in(window, async move |this, cx| {
 6234                    cx.background_executor().timer(delay).await;
 6235
 6236                    this.update(cx, |this, cx| {
 6237                        this.show_git_blame_inline = true;
 6238                        cx.notify();
 6239                    })
 6240                    .log_err();
 6241                }));
 6242        }
 6243    }
 6244
 6245    fn show_blame_popover(
 6246        &mut self,
 6247        blame_entry: &BlameEntry,
 6248        position: gpui::Point<Pixels>,
 6249        cx: &mut Context<Self>,
 6250    ) {
 6251        if let Some(state) = &mut self.inline_blame_popover {
 6252            state.hide_task.take();
 6253            cx.notify();
 6254        } else {
 6255            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6256            let show_task = cx.spawn(async move |editor, cx| {
 6257                cx.background_executor()
 6258                    .timer(std::time::Duration::from_millis(delay))
 6259                    .await;
 6260                editor
 6261                    .update(cx, |editor, cx| {
 6262                        if let Some(state) = &mut editor.inline_blame_popover {
 6263                            state.show_task = None;
 6264                            cx.notify();
 6265                        }
 6266                    })
 6267                    .ok();
 6268            });
 6269            let Some(blame) = self.blame.as_ref() else {
 6270                return;
 6271            };
 6272            let blame = blame.read(cx);
 6273            let details = blame.details_for_entry(&blame_entry);
 6274            let markdown = cx.new(|cx| {
 6275                Markdown::new(
 6276                    details
 6277                        .as_ref()
 6278                        .map(|message| message.message.clone())
 6279                        .unwrap_or_default(),
 6280                    None,
 6281                    None,
 6282                    cx,
 6283                )
 6284            });
 6285            self.inline_blame_popover = Some(InlineBlamePopover {
 6286                position,
 6287                show_task: Some(show_task),
 6288                hide_task: None,
 6289                popover_bounds: None,
 6290                popover_state: InlineBlamePopoverState {
 6291                    scroll_handle: ScrollHandle::new(),
 6292                    commit_message: details,
 6293                    markdown,
 6294                },
 6295            });
 6296        }
 6297    }
 6298
 6299    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6300        if let Some(state) = &mut self.inline_blame_popover {
 6301            if state.show_task.is_some() {
 6302                self.inline_blame_popover.take();
 6303                cx.notify();
 6304            } else {
 6305                let hide_task = cx.spawn(async move |editor, cx| {
 6306                    cx.background_executor()
 6307                        .timer(std::time::Duration::from_millis(100))
 6308                        .await;
 6309                    editor
 6310                        .update(cx, |editor, cx| {
 6311                            editor.inline_blame_popover.take();
 6312                            cx.notify();
 6313                        })
 6314                        .ok();
 6315                });
 6316                state.hide_task = Some(hide_task);
 6317            }
 6318        }
 6319    }
 6320
 6321    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6322        if self.pending_rename.is_some() {
 6323            return None;
 6324        }
 6325
 6326        let provider = self.semantics_provider.clone()?;
 6327        let buffer = self.buffer.read(cx);
 6328        let newest_selection = self.selections.newest_anchor().clone();
 6329        let cursor_position = newest_selection.head();
 6330        let (cursor_buffer, cursor_buffer_position) =
 6331            buffer.text_anchor_for_position(cursor_position, cx)?;
 6332        let (tail_buffer, tail_buffer_position) =
 6333            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6334        if cursor_buffer != tail_buffer {
 6335            return None;
 6336        }
 6337
 6338        let snapshot = cursor_buffer.read(cx).snapshot();
 6339        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6340        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6341        if start_word_range != end_word_range {
 6342            self.document_highlights_task.take();
 6343            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6344            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6345            return None;
 6346        }
 6347
 6348        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6349        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6350            cx.background_executor()
 6351                .timer(Duration::from_millis(debounce))
 6352                .await;
 6353
 6354            let highlights = if let Some(highlights) = cx
 6355                .update(|cx| {
 6356                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6357                })
 6358                .ok()
 6359                .flatten()
 6360            {
 6361                highlights.await.log_err()
 6362            } else {
 6363                None
 6364            };
 6365
 6366            if let Some(highlights) = highlights {
 6367                this.update(cx, |this, cx| {
 6368                    if this.pending_rename.is_some() {
 6369                        return;
 6370                    }
 6371
 6372                    let buffer_id = cursor_position.buffer_id;
 6373                    let buffer = this.buffer.read(cx);
 6374                    if !buffer
 6375                        .text_anchor_for_position(cursor_position, cx)
 6376                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6377                    {
 6378                        return;
 6379                    }
 6380
 6381                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6382                    let mut write_ranges = Vec::new();
 6383                    let mut read_ranges = Vec::new();
 6384                    for highlight in highlights {
 6385                        for (excerpt_id, excerpt_range) in
 6386                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6387                        {
 6388                            let start = highlight
 6389                                .range
 6390                                .start
 6391                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6392                            let end = highlight
 6393                                .range
 6394                                .end
 6395                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6396                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6397                                continue;
 6398                            }
 6399
 6400                            let range = Anchor {
 6401                                buffer_id,
 6402                                excerpt_id,
 6403                                text_anchor: start,
 6404                                diff_base_anchor: None,
 6405                            }..Anchor {
 6406                                buffer_id,
 6407                                excerpt_id,
 6408                                text_anchor: end,
 6409                                diff_base_anchor: None,
 6410                            };
 6411                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6412                                write_ranges.push(range);
 6413                            } else {
 6414                                read_ranges.push(range);
 6415                            }
 6416                        }
 6417                    }
 6418
 6419                    this.highlight_background::<DocumentHighlightRead>(
 6420                        &read_ranges,
 6421                        |theme| theme.editor_document_highlight_read_background,
 6422                        cx,
 6423                    );
 6424                    this.highlight_background::<DocumentHighlightWrite>(
 6425                        &write_ranges,
 6426                        |theme| theme.editor_document_highlight_write_background,
 6427                        cx,
 6428                    );
 6429                    cx.notify();
 6430                })
 6431                .log_err();
 6432            }
 6433        }));
 6434        None
 6435    }
 6436
 6437    fn prepare_highlight_query_from_selection(
 6438        &mut self,
 6439        cx: &mut Context<Editor>,
 6440    ) -> Option<(String, Range<Anchor>)> {
 6441        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6442            return None;
 6443        }
 6444        if !EditorSettings::get_global(cx).selection_highlight {
 6445            return None;
 6446        }
 6447        if self.selections.count() != 1 || self.selections.line_mode {
 6448            return None;
 6449        }
 6450        let selection = self.selections.newest::<Point>(cx);
 6451        if selection.is_empty() || selection.start.row != selection.end.row {
 6452            return None;
 6453        }
 6454        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6455        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6456        let query = multi_buffer_snapshot
 6457            .text_for_range(selection_anchor_range.clone())
 6458            .collect::<String>();
 6459        if query.trim().is_empty() {
 6460            return None;
 6461        }
 6462        Some((query, selection_anchor_range))
 6463    }
 6464
 6465    fn update_selection_occurrence_highlights(
 6466        &mut self,
 6467        query_text: String,
 6468        query_range: Range<Anchor>,
 6469        multi_buffer_range_to_query: Range<Point>,
 6470        use_debounce: bool,
 6471        window: &mut Window,
 6472        cx: &mut Context<Editor>,
 6473    ) -> Task<()> {
 6474        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6475        cx.spawn_in(window, async move |editor, cx| {
 6476            if use_debounce {
 6477                cx.background_executor()
 6478                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6479                    .await;
 6480            }
 6481            let match_task = cx.background_spawn(async move {
 6482                let buffer_ranges = multi_buffer_snapshot
 6483                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6484                    .into_iter()
 6485                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6486                let mut match_ranges = Vec::new();
 6487                let Ok(regex) = project::search::SearchQuery::text(
 6488                    query_text.clone(),
 6489                    false,
 6490                    false,
 6491                    false,
 6492                    Default::default(),
 6493                    Default::default(),
 6494                    false,
 6495                    None,
 6496                ) else {
 6497                    return Vec::default();
 6498                };
 6499                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6500                    match_ranges.extend(
 6501                        regex
 6502                            .search(&buffer_snapshot, Some(search_range.clone()))
 6503                            .await
 6504                            .into_iter()
 6505                            .filter_map(|match_range| {
 6506                                let match_start = buffer_snapshot
 6507                                    .anchor_after(search_range.start + match_range.start);
 6508                                let match_end = buffer_snapshot
 6509                                    .anchor_before(search_range.start + match_range.end);
 6510                                let match_anchor_range = Anchor::range_in_buffer(
 6511                                    excerpt_id,
 6512                                    buffer_snapshot.remote_id(),
 6513                                    match_start..match_end,
 6514                                );
 6515                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6516                            }),
 6517                    );
 6518                }
 6519                match_ranges
 6520            });
 6521            let match_ranges = match_task.await;
 6522            editor
 6523                .update_in(cx, |editor, _, cx| {
 6524                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6525                    if !match_ranges.is_empty() {
 6526                        editor.highlight_background::<SelectedTextHighlight>(
 6527                            &match_ranges,
 6528                            |theme| theme.editor_document_highlight_bracket_background,
 6529                            cx,
 6530                        )
 6531                    }
 6532                })
 6533                .log_err();
 6534        })
 6535    }
 6536
 6537    fn refresh_selected_text_highlights(
 6538        &mut self,
 6539        on_buffer_edit: bool,
 6540        window: &mut Window,
 6541        cx: &mut Context<Editor>,
 6542    ) {
 6543        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6544        else {
 6545            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6546            self.quick_selection_highlight_task.take();
 6547            self.debounced_selection_highlight_task.take();
 6548            return;
 6549        };
 6550        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6551        if on_buffer_edit
 6552            || self
 6553                .quick_selection_highlight_task
 6554                .as_ref()
 6555                .map_or(true, |(prev_anchor_range, _)| {
 6556                    prev_anchor_range != &query_range
 6557                })
 6558        {
 6559            let multi_buffer_visible_start = self
 6560                .scroll_manager
 6561                .anchor()
 6562                .anchor
 6563                .to_point(&multi_buffer_snapshot);
 6564            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6565                multi_buffer_visible_start
 6566                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6567                Bias::Left,
 6568            );
 6569            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6570            self.quick_selection_highlight_task = Some((
 6571                query_range.clone(),
 6572                self.update_selection_occurrence_highlights(
 6573                    query_text.clone(),
 6574                    query_range.clone(),
 6575                    multi_buffer_visible_range,
 6576                    false,
 6577                    window,
 6578                    cx,
 6579                ),
 6580            ));
 6581        }
 6582        if on_buffer_edit
 6583            || self
 6584                .debounced_selection_highlight_task
 6585                .as_ref()
 6586                .map_or(true, |(prev_anchor_range, _)| {
 6587                    prev_anchor_range != &query_range
 6588                })
 6589        {
 6590            let multi_buffer_start = multi_buffer_snapshot
 6591                .anchor_before(0)
 6592                .to_point(&multi_buffer_snapshot);
 6593            let multi_buffer_end = multi_buffer_snapshot
 6594                .anchor_after(multi_buffer_snapshot.len())
 6595                .to_point(&multi_buffer_snapshot);
 6596            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6597            self.debounced_selection_highlight_task = Some((
 6598                query_range.clone(),
 6599                self.update_selection_occurrence_highlights(
 6600                    query_text,
 6601                    query_range,
 6602                    multi_buffer_full_range,
 6603                    true,
 6604                    window,
 6605                    cx,
 6606                ),
 6607            ));
 6608        }
 6609    }
 6610
 6611    pub fn refresh_inline_completion(
 6612        &mut self,
 6613        debounce: bool,
 6614        user_requested: bool,
 6615        window: &mut Window,
 6616        cx: &mut Context<Self>,
 6617    ) -> Option<()> {
 6618        let provider = self.edit_prediction_provider()?;
 6619        let cursor = self.selections.newest_anchor().head();
 6620        let (buffer, cursor_buffer_position) =
 6621            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6622
 6623        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6624            self.discard_inline_completion(false, cx);
 6625            return None;
 6626        }
 6627
 6628        if !user_requested
 6629            && (!self.should_show_edit_predictions()
 6630                || !self.is_focused(window)
 6631                || buffer.read(cx).is_empty())
 6632        {
 6633            self.discard_inline_completion(false, cx);
 6634            return None;
 6635        }
 6636
 6637        self.update_visible_inline_completion(window, cx);
 6638        provider.refresh(
 6639            self.project.clone(),
 6640            buffer,
 6641            cursor_buffer_position,
 6642            debounce,
 6643            cx,
 6644        );
 6645        Some(())
 6646    }
 6647
 6648    fn show_edit_predictions_in_menu(&self) -> bool {
 6649        match self.edit_prediction_settings {
 6650            EditPredictionSettings::Disabled => false,
 6651            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6652        }
 6653    }
 6654
 6655    pub fn edit_predictions_enabled(&self) -> bool {
 6656        match self.edit_prediction_settings {
 6657            EditPredictionSettings::Disabled => false,
 6658            EditPredictionSettings::Enabled { .. } => true,
 6659        }
 6660    }
 6661
 6662    fn edit_prediction_requires_modifier(&self) -> bool {
 6663        match self.edit_prediction_settings {
 6664            EditPredictionSettings::Disabled => false,
 6665            EditPredictionSettings::Enabled {
 6666                preview_requires_modifier,
 6667                ..
 6668            } => preview_requires_modifier,
 6669        }
 6670    }
 6671
 6672    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6673        if self.edit_prediction_provider.is_none() {
 6674            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6675        } else {
 6676            let selection = self.selections.newest_anchor();
 6677            let cursor = selection.head();
 6678
 6679            if let Some((buffer, cursor_buffer_position)) =
 6680                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6681            {
 6682                self.edit_prediction_settings =
 6683                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6684            }
 6685        }
 6686    }
 6687
 6688    fn edit_prediction_settings_at_position(
 6689        &self,
 6690        buffer: &Entity<Buffer>,
 6691        buffer_position: language::Anchor,
 6692        cx: &App,
 6693    ) -> EditPredictionSettings {
 6694        if !self.mode.is_full()
 6695            || !self.show_inline_completions_override.unwrap_or(true)
 6696            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6697        {
 6698            return EditPredictionSettings::Disabled;
 6699        }
 6700
 6701        let buffer = buffer.read(cx);
 6702
 6703        let file = buffer.file();
 6704
 6705        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6706            return EditPredictionSettings::Disabled;
 6707        };
 6708
 6709        let by_provider = matches!(
 6710            self.menu_inline_completions_policy,
 6711            MenuInlineCompletionsPolicy::ByProvider
 6712        );
 6713
 6714        let show_in_menu = by_provider
 6715            && self
 6716                .edit_prediction_provider
 6717                .as_ref()
 6718                .map_or(false, |provider| {
 6719                    provider.provider.show_completions_in_menu()
 6720                });
 6721
 6722        let preview_requires_modifier =
 6723            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6724
 6725        EditPredictionSettings::Enabled {
 6726            show_in_menu,
 6727            preview_requires_modifier,
 6728        }
 6729    }
 6730
 6731    fn should_show_edit_predictions(&self) -> bool {
 6732        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6733    }
 6734
 6735    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6736        matches!(
 6737            self.edit_prediction_preview,
 6738            EditPredictionPreview::Active { .. }
 6739        )
 6740    }
 6741
 6742    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6743        let cursor = self.selections.newest_anchor().head();
 6744        if let Some((buffer, cursor_position)) =
 6745            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6746        {
 6747            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6748        } else {
 6749            false
 6750        }
 6751    }
 6752
 6753    pub fn supports_minimap(&self, cx: &App) -> bool {
 6754        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6755    }
 6756
 6757    fn edit_predictions_enabled_in_buffer(
 6758        &self,
 6759        buffer: &Entity<Buffer>,
 6760        buffer_position: language::Anchor,
 6761        cx: &App,
 6762    ) -> bool {
 6763        maybe!({
 6764            if self.read_only(cx) {
 6765                return Some(false);
 6766            }
 6767            let provider = self.edit_prediction_provider()?;
 6768            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6769                return Some(false);
 6770            }
 6771            let buffer = buffer.read(cx);
 6772            let Some(file) = buffer.file() else {
 6773                return Some(true);
 6774            };
 6775            let settings = all_language_settings(Some(file), cx);
 6776            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6777        })
 6778        .unwrap_or(false)
 6779    }
 6780
 6781    fn cycle_inline_completion(
 6782        &mut self,
 6783        direction: Direction,
 6784        window: &mut Window,
 6785        cx: &mut Context<Self>,
 6786    ) -> Option<()> {
 6787        let provider = self.edit_prediction_provider()?;
 6788        let cursor = self.selections.newest_anchor().head();
 6789        let (buffer, cursor_buffer_position) =
 6790            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6791        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6792            return None;
 6793        }
 6794
 6795        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6796        self.update_visible_inline_completion(window, cx);
 6797
 6798        Some(())
 6799    }
 6800
 6801    pub fn show_inline_completion(
 6802        &mut self,
 6803        _: &ShowEditPrediction,
 6804        window: &mut Window,
 6805        cx: &mut Context<Self>,
 6806    ) {
 6807        if !self.has_active_inline_completion() {
 6808            self.refresh_inline_completion(false, true, window, cx);
 6809            return;
 6810        }
 6811
 6812        self.update_visible_inline_completion(window, cx);
 6813    }
 6814
 6815    pub fn display_cursor_names(
 6816        &mut self,
 6817        _: &DisplayCursorNames,
 6818        window: &mut Window,
 6819        cx: &mut Context<Self>,
 6820    ) {
 6821        self.show_cursor_names(window, cx);
 6822    }
 6823
 6824    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6825        self.show_cursor_names = true;
 6826        cx.notify();
 6827        cx.spawn_in(window, async move |this, cx| {
 6828            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6829            this.update(cx, |this, cx| {
 6830                this.show_cursor_names = false;
 6831                cx.notify()
 6832            })
 6833            .ok()
 6834        })
 6835        .detach();
 6836    }
 6837
 6838    pub fn next_edit_prediction(
 6839        &mut self,
 6840        _: &NextEditPrediction,
 6841        window: &mut Window,
 6842        cx: &mut Context<Self>,
 6843    ) {
 6844        if self.has_active_inline_completion() {
 6845            self.cycle_inline_completion(Direction::Next, window, cx);
 6846        } else {
 6847            let is_copilot_disabled = self
 6848                .refresh_inline_completion(false, true, window, cx)
 6849                .is_none();
 6850            if is_copilot_disabled {
 6851                cx.propagate();
 6852            }
 6853        }
 6854    }
 6855
 6856    pub fn previous_edit_prediction(
 6857        &mut self,
 6858        _: &PreviousEditPrediction,
 6859        window: &mut Window,
 6860        cx: &mut Context<Self>,
 6861    ) {
 6862        if self.has_active_inline_completion() {
 6863            self.cycle_inline_completion(Direction::Prev, window, cx);
 6864        } else {
 6865            let is_copilot_disabled = self
 6866                .refresh_inline_completion(false, true, window, cx)
 6867                .is_none();
 6868            if is_copilot_disabled {
 6869                cx.propagate();
 6870            }
 6871        }
 6872    }
 6873
 6874    pub fn accept_edit_prediction(
 6875        &mut self,
 6876        _: &AcceptEditPrediction,
 6877        window: &mut Window,
 6878        cx: &mut Context<Self>,
 6879    ) {
 6880        if self.show_edit_predictions_in_menu() {
 6881            self.hide_context_menu(window, cx);
 6882        }
 6883
 6884        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6885            return;
 6886        };
 6887
 6888        self.report_inline_completion_event(
 6889            active_inline_completion.completion_id.clone(),
 6890            true,
 6891            cx,
 6892        );
 6893
 6894        match &active_inline_completion.completion {
 6895            InlineCompletion::Move { target, .. } => {
 6896                let target = *target;
 6897
 6898                if let Some(position_map) = &self.last_position_map {
 6899                    if position_map
 6900                        .visible_row_range
 6901                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6902                        || !self.edit_prediction_requires_modifier()
 6903                    {
 6904                        self.unfold_ranges(&[target..target], true, false, cx);
 6905                        // Note that this is also done in vim's handler of the Tab action.
 6906                        self.change_selections(
 6907                            Some(Autoscroll::newest()),
 6908                            window,
 6909                            cx,
 6910                            |selections| {
 6911                                selections.select_anchor_ranges([target..target]);
 6912                            },
 6913                        );
 6914                        self.clear_row_highlights::<EditPredictionPreview>();
 6915
 6916                        self.edit_prediction_preview
 6917                            .set_previous_scroll_position(None);
 6918                    } else {
 6919                        self.edit_prediction_preview
 6920                            .set_previous_scroll_position(Some(
 6921                                position_map.snapshot.scroll_anchor,
 6922                            ));
 6923
 6924                        self.highlight_rows::<EditPredictionPreview>(
 6925                            target..target,
 6926                            cx.theme().colors().editor_highlighted_line_background,
 6927                            RowHighlightOptions {
 6928                                autoscroll: true,
 6929                                ..Default::default()
 6930                            },
 6931                            cx,
 6932                        );
 6933                        self.request_autoscroll(Autoscroll::fit(), cx);
 6934                    }
 6935                }
 6936            }
 6937            InlineCompletion::Edit { edits, .. } => {
 6938                if let Some(provider) = self.edit_prediction_provider() {
 6939                    provider.accept(cx);
 6940                }
 6941
 6942                // Store the transaction ID and selections before applying the edit
 6943                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6944
 6945                let snapshot = self.buffer.read(cx).snapshot(cx);
 6946                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6947
 6948                self.buffer.update(cx, |buffer, cx| {
 6949                    buffer.edit(edits.iter().cloned(), None, cx)
 6950                });
 6951
 6952                self.change_selections(None, window, cx, |s| {
 6953                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6954                });
 6955
 6956                let selections = self.selections.disjoint_anchors();
 6957                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6958                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6959                    if has_new_transaction {
 6960                        self.selection_history
 6961                            .insert_transaction(transaction_id_now, selections);
 6962                    }
 6963                }
 6964
 6965                self.update_visible_inline_completion(window, cx);
 6966                if self.active_inline_completion.is_none() {
 6967                    self.refresh_inline_completion(true, true, window, cx);
 6968                }
 6969
 6970                cx.notify();
 6971            }
 6972        }
 6973
 6974        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6975    }
 6976
 6977    pub fn accept_partial_inline_completion(
 6978        &mut self,
 6979        _: &AcceptPartialEditPrediction,
 6980        window: &mut Window,
 6981        cx: &mut Context<Self>,
 6982    ) {
 6983        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6984            return;
 6985        };
 6986        if self.selections.count() != 1 {
 6987            return;
 6988        }
 6989
 6990        self.report_inline_completion_event(
 6991            active_inline_completion.completion_id.clone(),
 6992            true,
 6993            cx,
 6994        );
 6995
 6996        match &active_inline_completion.completion {
 6997            InlineCompletion::Move { target, .. } => {
 6998                let target = *target;
 6999                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7000                    selections.select_anchor_ranges([target..target]);
 7001                });
 7002            }
 7003            InlineCompletion::Edit { edits, .. } => {
 7004                // Find an insertion that starts at the cursor position.
 7005                let snapshot = self.buffer.read(cx).snapshot(cx);
 7006                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7007                let insertion = edits.iter().find_map(|(range, text)| {
 7008                    let range = range.to_offset(&snapshot);
 7009                    if range.is_empty() && range.start == cursor_offset {
 7010                        Some(text)
 7011                    } else {
 7012                        None
 7013                    }
 7014                });
 7015
 7016                if let Some(text) = insertion {
 7017                    let mut partial_completion = text
 7018                        .chars()
 7019                        .by_ref()
 7020                        .take_while(|c| c.is_alphabetic())
 7021                        .collect::<String>();
 7022                    if partial_completion.is_empty() {
 7023                        partial_completion = text
 7024                            .chars()
 7025                            .by_ref()
 7026                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7027                            .collect::<String>();
 7028                    }
 7029
 7030                    cx.emit(EditorEvent::InputHandled {
 7031                        utf16_range_to_replace: None,
 7032                        text: partial_completion.clone().into(),
 7033                    });
 7034
 7035                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7036
 7037                    self.refresh_inline_completion(true, true, window, cx);
 7038                    cx.notify();
 7039                } else {
 7040                    self.accept_edit_prediction(&Default::default(), window, cx);
 7041                }
 7042            }
 7043        }
 7044    }
 7045
 7046    fn discard_inline_completion(
 7047        &mut self,
 7048        should_report_inline_completion_event: bool,
 7049        cx: &mut Context<Self>,
 7050    ) -> bool {
 7051        if should_report_inline_completion_event {
 7052            let completion_id = self
 7053                .active_inline_completion
 7054                .as_ref()
 7055                .and_then(|active_completion| active_completion.completion_id.clone());
 7056
 7057            self.report_inline_completion_event(completion_id, false, cx);
 7058        }
 7059
 7060        if let Some(provider) = self.edit_prediction_provider() {
 7061            provider.discard(cx);
 7062        }
 7063
 7064        self.take_active_inline_completion(cx)
 7065    }
 7066
 7067    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7068        let Some(provider) = self.edit_prediction_provider() else {
 7069            return;
 7070        };
 7071
 7072        let Some((_, buffer, _)) = self
 7073            .buffer
 7074            .read(cx)
 7075            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7076        else {
 7077            return;
 7078        };
 7079
 7080        let extension = buffer
 7081            .read(cx)
 7082            .file()
 7083            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7084
 7085        let event_type = match accepted {
 7086            true => "Edit Prediction Accepted",
 7087            false => "Edit Prediction Discarded",
 7088        };
 7089        telemetry::event!(
 7090            event_type,
 7091            provider = provider.name(),
 7092            prediction_id = id,
 7093            suggestion_accepted = accepted,
 7094            file_extension = extension,
 7095        );
 7096    }
 7097
 7098    pub fn has_active_inline_completion(&self) -> bool {
 7099        self.active_inline_completion.is_some()
 7100    }
 7101
 7102    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7103        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7104            return false;
 7105        };
 7106
 7107        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7108        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7109        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7110        true
 7111    }
 7112
 7113    /// Returns true when we're displaying the edit prediction popover below the cursor
 7114    /// like we are not previewing and the LSP autocomplete menu is visible
 7115    /// or we are in `when_holding_modifier` mode.
 7116    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7117        if self.edit_prediction_preview_is_active()
 7118            || !self.show_edit_predictions_in_menu()
 7119            || !self.edit_predictions_enabled()
 7120        {
 7121            return false;
 7122        }
 7123
 7124        if self.has_visible_completions_menu() {
 7125            return true;
 7126        }
 7127
 7128        has_completion && self.edit_prediction_requires_modifier()
 7129    }
 7130
 7131    fn handle_modifiers_changed(
 7132        &mut self,
 7133        modifiers: Modifiers,
 7134        position_map: &PositionMap,
 7135        window: &mut Window,
 7136        cx: &mut Context<Self>,
 7137    ) {
 7138        if self.show_edit_predictions_in_menu() {
 7139            self.update_edit_prediction_preview(&modifiers, window, cx);
 7140        }
 7141
 7142        self.update_selection_mode(&modifiers, position_map, window, cx);
 7143
 7144        let mouse_position = window.mouse_position();
 7145        if !position_map.text_hitbox.is_hovered(window) {
 7146            return;
 7147        }
 7148
 7149        self.update_hovered_link(
 7150            position_map.point_for_position(mouse_position),
 7151            &position_map.snapshot,
 7152            modifiers,
 7153            window,
 7154            cx,
 7155        )
 7156    }
 7157
 7158    fn multi_cursor_modifier(
 7159        cursor_event: bool,
 7160        modifiers: &Modifiers,
 7161        cx: &mut Context<Self>,
 7162    ) -> bool {
 7163        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7164        if cursor_event {
 7165            match multi_cursor_setting {
 7166                MultiCursorModifier::Alt => modifiers.alt,
 7167                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7168            }
 7169        } else {
 7170            match multi_cursor_setting {
 7171                MultiCursorModifier::Alt => modifiers.secondary(),
 7172                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7173            }
 7174        }
 7175    }
 7176
 7177    fn columnar_selection_modifiers(multi_cursor_modifier: bool, modifiers: &Modifiers) -> bool {
 7178        modifiers.shift && multi_cursor_modifier && modifiers.number_of_modifiers() == 2
 7179    }
 7180
 7181    fn update_selection_mode(
 7182        &mut self,
 7183        modifiers: &Modifiers,
 7184        position_map: &PositionMap,
 7185        window: &mut Window,
 7186        cx: &mut Context<Self>,
 7187    ) {
 7188        let multi_cursor_modifier = Self::multi_cursor_modifier(true, modifiers, cx);
 7189        if !Self::columnar_selection_modifiers(multi_cursor_modifier, modifiers)
 7190            || self.selections.pending.is_none()
 7191        {
 7192            return;
 7193        }
 7194
 7195        let mouse_position = window.mouse_position();
 7196        let point_for_position = position_map.point_for_position(mouse_position);
 7197        let position = point_for_position.previous_valid;
 7198
 7199        self.select(
 7200            SelectPhase::BeginColumnar {
 7201                position,
 7202                reset: false,
 7203                goal_column: point_for_position.exact_unclipped.column(),
 7204            },
 7205            window,
 7206            cx,
 7207        );
 7208    }
 7209
 7210    fn update_edit_prediction_preview(
 7211        &mut self,
 7212        modifiers: &Modifiers,
 7213        window: &mut Window,
 7214        cx: &mut Context<Self>,
 7215    ) {
 7216        let mut modifiers_held = false;
 7217        if let Some(accept_keystroke) = self
 7218            .accept_edit_prediction_keybind(false, window, cx)
 7219            .keystroke()
 7220        {
 7221            modifiers_held = modifiers_held
 7222                || (&accept_keystroke.modifiers == modifiers
 7223                    && accept_keystroke.modifiers.modified());
 7224        };
 7225        if let Some(accept_partial_keystroke) = self
 7226            .accept_edit_prediction_keybind(true, window, cx)
 7227            .keystroke()
 7228        {
 7229            modifiers_held = modifiers_held
 7230                || (&accept_partial_keystroke.modifiers == modifiers
 7231                    && accept_partial_keystroke.modifiers.modified());
 7232        }
 7233
 7234        if modifiers_held {
 7235            if matches!(
 7236                self.edit_prediction_preview,
 7237                EditPredictionPreview::Inactive { .. }
 7238            ) {
 7239                self.edit_prediction_preview = EditPredictionPreview::Active {
 7240                    previous_scroll_position: None,
 7241                    since: Instant::now(),
 7242                };
 7243
 7244                self.update_visible_inline_completion(window, cx);
 7245                cx.notify();
 7246            }
 7247        } else if let EditPredictionPreview::Active {
 7248            previous_scroll_position,
 7249            since,
 7250        } = self.edit_prediction_preview
 7251        {
 7252            if let (Some(previous_scroll_position), Some(position_map)) =
 7253                (previous_scroll_position, self.last_position_map.as_ref())
 7254            {
 7255                self.set_scroll_position(
 7256                    previous_scroll_position
 7257                        .scroll_position(&position_map.snapshot.display_snapshot),
 7258                    window,
 7259                    cx,
 7260                );
 7261            }
 7262
 7263            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7264                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7265            };
 7266            self.clear_row_highlights::<EditPredictionPreview>();
 7267            self.update_visible_inline_completion(window, cx);
 7268            cx.notify();
 7269        }
 7270    }
 7271
 7272    fn update_visible_inline_completion(
 7273        &mut self,
 7274        _window: &mut Window,
 7275        cx: &mut Context<Self>,
 7276    ) -> Option<()> {
 7277        let selection = self.selections.newest_anchor();
 7278        let cursor = selection.head();
 7279        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7280        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7281        let excerpt_id = cursor.excerpt_id;
 7282
 7283        let show_in_menu = self.show_edit_predictions_in_menu();
 7284        let completions_menu_has_precedence = !show_in_menu
 7285            && (self.context_menu.borrow().is_some()
 7286                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7287
 7288        if completions_menu_has_precedence
 7289            || !offset_selection.is_empty()
 7290            || self
 7291                .active_inline_completion
 7292                .as_ref()
 7293                .map_or(false, |completion| {
 7294                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7295                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7296                    !invalidation_range.contains(&offset_selection.head())
 7297                })
 7298        {
 7299            self.discard_inline_completion(false, cx);
 7300            return None;
 7301        }
 7302
 7303        self.take_active_inline_completion(cx);
 7304        let Some(provider) = self.edit_prediction_provider() else {
 7305            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7306            return None;
 7307        };
 7308
 7309        let (buffer, cursor_buffer_position) =
 7310            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7311
 7312        self.edit_prediction_settings =
 7313            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7314
 7315        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7316
 7317        if self.edit_prediction_indent_conflict {
 7318            let cursor_point = cursor.to_point(&multibuffer);
 7319
 7320            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7321
 7322            if let Some((_, indent)) = indents.iter().next() {
 7323                if indent.len == cursor_point.column {
 7324                    self.edit_prediction_indent_conflict = false;
 7325                }
 7326            }
 7327        }
 7328
 7329        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7330        let edits = inline_completion
 7331            .edits
 7332            .into_iter()
 7333            .flat_map(|(range, new_text)| {
 7334                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7335                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7336                Some((start..end, new_text))
 7337            })
 7338            .collect::<Vec<_>>();
 7339        if edits.is_empty() {
 7340            return None;
 7341        }
 7342
 7343        let first_edit_start = edits.first().unwrap().0.start;
 7344        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7345        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7346
 7347        let last_edit_end = edits.last().unwrap().0.end;
 7348        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7349        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7350
 7351        let cursor_row = cursor.to_point(&multibuffer).row;
 7352
 7353        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7354
 7355        let mut inlay_ids = Vec::new();
 7356        let invalidation_row_range;
 7357        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7358            Some(cursor_row..edit_end_row)
 7359        } else if cursor_row > edit_end_row {
 7360            Some(edit_start_row..cursor_row)
 7361        } else {
 7362            None
 7363        };
 7364        let is_move =
 7365            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7366        let completion = if is_move {
 7367            invalidation_row_range =
 7368                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7369            let target = first_edit_start;
 7370            InlineCompletion::Move { target, snapshot }
 7371        } else {
 7372            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7373                && !self.inline_completions_hidden_for_vim_mode;
 7374
 7375            if show_completions_in_buffer {
 7376                if edits
 7377                    .iter()
 7378                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7379                {
 7380                    let mut inlays = Vec::new();
 7381                    for (range, new_text) in &edits {
 7382                        let inlay = Inlay::inline_completion(
 7383                            post_inc(&mut self.next_inlay_id),
 7384                            range.start,
 7385                            new_text.as_str(),
 7386                        );
 7387                        inlay_ids.push(inlay.id);
 7388                        inlays.push(inlay);
 7389                    }
 7390
 7391                    self.splice_inlays(&[], inlays, cx);
 7392                } else {
 7393                    let background_color = cx.theme().status().deleted_background;
 7394                    self.highlight_text::<InlineCompletionHighlight>(
 7395                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7396                        HighlightStyle {
 7397                            background_color: Some(background_color),
 7398                            ..Default::default()
 7399                        },
 7400                        cx,
 7401                    );
 7402                }
 7403            }
 7404
 7405            invalidation_row_range = edit_start_row..edit_end_row;
 7406
 7407            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7408                if provider.show_tab_accept_marker() {
 7409                    EditDisplayMode::TabAccept
 7410                } else {
 7411                    EditDisplayMode::Inline
 7412                }
 7413            } else {
 7414                EditDisplayMode::DiffPopover
 7415            };
 7416
 7417            InlineCompletion::Edit {
 7418                edits,
 7419                edit_preview: inline_completion.edit_preview,
 7420                display_mode,
 7421                snapshot,
 7422            }
 7423        };
 7424
 7425        let invalidation_range = multibuffer
 7426            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7427            ..multibuffer.anchor_after(Point::new(
 7428                invalidation_row_range.end,
 7429                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7430            ));
 7431
 7432        self.stale_inline_completion_in_menu = None;
 7433        self.active_inline_completion = Some(InlineCompletionState {
 7434            inlay_ids,
 7435            completion,
 7436            completion_id: inline_completion.id,
 7437            invalidation_range,
 7438        });
 7439
 7440        cx.notify();
 7441
 7442        Some(())
 7443    }
 7444
 7445    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7446        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7447    }
 7448
 7449    fn clear_tasks(&mut self) {
 7450        self.tasks.clear()
 7451    }
 7452
 7453    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7454        if self.tasks.insert(key, value).is_some() {
 7455            // This case should hopefully be rare, but just in case...
 7456            log::error!(
 7457                "multiple different run targets found on a single line, only the last target will be rendered"
 7458            )
 7459        }
 7460    }
 7461
 7462    /// Get all display points of breakpoints that will be rendered within editor
 7463    ///
 7464    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7465    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7466    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7467    fn active_breakpoints(
 7468        &self,
 7469        range: Range<DisplayRow>,
 7470        window: &mut Window,
 7471        cx: &mut Context<Self>,
 7472    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7473        let mut breakpoint_display_points = HashMap::default();
 7474
 7475        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7476            return breakpoint_display_points;
 7477        };
 7478
 7479        let snapshot = self.snapshot(window, cx);
 7480
 7481        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7482        let Some(project) = self.project.as_ref() else {
 7483            return breakpoint_display_points;
 7484        };
 7485
 7486        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7487            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7488
 7489        for (buffer_snapshot, range, excerpt_id) in
 7490            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7491        {
 7492            let Some(buffer) = project
 7493                .read(cx)
 7494                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7495            else {
 7496                continue;
 7497            };
 7498            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7499                &buffer,
 7500                Some(
 7501                    buffer_snapshot.anchor_before(range.start)
 7502                        ..buffer_snapshot.anchor_after(range.end),
 7503                ),
 7504                buffer_snapshot,
 7505                cx,
 7506            );
 7507            for (breakpoint, state) in breakpoints {
 7508                let multi_buffer_anchor =
 7509                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7510                let position = multi_buffer_anchor
 7511                    .to_point(&multi_buffer_snapshot)
 7512                    .to_display_point(&snapshot);
 7513
 7514                breakpoint_display_points.insert(
 7515                    position.row(),
 7516                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7517                );
 7518            }
 7519        }
 7520
 7521        breakpoint_display_points
 7522    }
 7523
 7524    fn breakpoint_context_menu(
 7525        &self,
 7526        anchor: Anchor,
 7527        window: &mut Window,
 7528        cx: &mut Context<Self>,
 7529    ) -> Entity<ui::ContextMenu> {
 7530        let weak_editor = cx.weak_entity();
 7531        let focus_handle = self.focus_handle(cx);
 7532
 7533        let row = self
 7534            .buffer
 7535            .read(cx)
 7536            .snapshot(cx)
 7537            .summary_for_anchor::<Point>(&anchor)
 7538            .row;
 7539
 7540        let breakpoint = self
 7541            .breakpoint_at_row(row, window, cx)
 7542            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7543
 7544        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7545            "Edit Log Breakpoint"
 7546        } else {
 7547            "Set Log Breakpoint"
 7548        };
 7549
 7550        let condition_breakpoint_msg = if breakpoint
 7551            .as_ref()
 7552            .is_some_and(|bp| bp.1.condition.is_some())
 7553        {
 7554            "Edit Condition Breakpoint"
 7555        } else {
 7556            "Set Condition Breakpoint"
 7557        };
 7558
 7559        let hit_condition_breakpoint_msg = if breakpoint
 7560            .as_ref()
 7561            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7562        {
 7563            "Edit Hit Condition Breakpoint"
 7564        } else {
 7565            "Set Hit Condition Breakpoint"
 7566        };
 7567
 7568        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7569            "Unset Breakpoint"
 7570        } else {
 7571            "Set Breakpoint"
 7572        };
 7573
 7574        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7575
 7576        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7577            BreakpointState::Enabled => Some("Disable"),
 7578            BreakpointState::Disabled => Some("Enable"),
 7579        });
 7580
 7581        let (anchor, breakpoint) =
 7582            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7583
 7584        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7585            menu.on_blur_subscription(Subscription::new(|| {}))
 7586                .context(focus_handle)
 7587                .when(run_to_cursor, |this| {
 7588                    let weak_editor = weak_editor.clone();
 7589                    this.entry("Run to cursor", None, move |window, cx| {
 7590                        weak_editor
 7591                            .update(cx, |editor, cx| {
 7592                                editor.change_selections(None, window, cx, |s| {
 7593                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7594                                });
 7595                            })
 7596                            .ok();
 7597
 7598                        window.dispatch_action(Box::new(RunToCursor), cx);
 7599                    })
 7600                    .separator()
 7601                })
 7602                .when_some(toggle_state_msg, |this, msg| {
 7603                    this.entry(msg, None, {
 7604                        let weak_editor = weak_editor.clone();
 7605                        let breakpoint = breakpoint.clone();
 7606                        move |_window, cx| {
 7607                            weak_editor
 7608                                .update(cx, |this, cx| {
 7609                                    this.edit_breakpoint_at_anchor(
 7610                                        anchor,
 7611                                        breakpoint.as_ref().clone(),
 7612                                        BreakpointEditAction::InvertState,
 7613                                        cx,
 7614                                    );
 7615                                })
 7616                                .log_err();
 7617                        }
 7618                    })
 7619                })
 7620                .entry(set_breakpoint_msg, None, {
 7621                    let weak_editor = weak_editor.clone();
 7622                    let breakpoint = breakpoint.clone();
 7623                    move |_window, cx| {
 7624                        weak_editor
 7625                            .update(cx, |this, cx| {
 7626                                this.edit_breakpoint_at_anchor(
 7627                                    anchor,
 7628                                    breakpoint.as_ref().clone(),
 7629                                    BreakpointEditAction::Toggle,
 7630                                    cx,
 7631                                );
 7632                            })
 7633                            .log_err();
 7634                    }
 7635                })
 7636                .entry(log_breakpoint_msg, None, {
 7637                    let breakpoint = breakpoint.clone();
 7638                    let weak_editor = weak_editor.clone();
 7639                    move |window, cx| {
 7640                        weak_editor
 7641                            .update(cx, |this, cx| {
 7642                                this.add_edit_breakpoint_block(
 7643                                    anchor,
 7644                                    breakpoint.as_ref(),
 7645                                    BreakpointPromptEditAction::Log,
 7646                                    window,
 7647                                    cx,
 7648                                );
 7649                            })
 7650                            .log_err();
 7651                    }
 7652                })
 7653                .entry(condition_breakpoint_msg, None, {
 7654                    let breakpoint = breakpoint.clone();
 7655                    let weak_editor = weak_editor.clone();
 7656                    move |window, cx| {
 7657                        weak_editor
 7658                            .update(cx, |this, cx| {
 7659                                this.add_edit_breakpoint_block(
 7660                                    anchor,
 7661                                    breakpoint.as_ref(),
 7662                                    BreakpointPromptEditAction::Condition,
 7663                                    window,
 7664                                    cx,
 7665                                );
 7666                            })
 7667                            .log_err();
 7668                    }
 7669                })
 7670                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7671                    weak_editor
 7672                        .update(cx, |this, cx| {
 7673                            this.add_edit_breakpoint_block(
 7674                                anchor,
 7675                                breakpoint.as_ref(),
 7676                                BreakpointPromptEditAction::HitCondition,
 7677                                window,
 7678                                cx,
 7679                            );
 7680                        })
 7681                        .log_err();
 7682                })
 7683        })
 7684    }
 7685
 7686    fn render_breakpoint(
 7687        &self,
 7688        position: Anchor,
 7689        row: DisplayRow,
 7690        breakpoint: &Breakpoint,
 7691        state: Option<BreakpointSessionState>,
 7692        cx: &mut Context<Self>,
 7693    ) -> IconButton {
 7694        let is_rejected = state.is_some_and(|s| !s.verified);
 7695        // Is it a breakpoint that shows up when hovering over gutter?
 7696        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7697            (false, false),
 7698            |PhantomBreakpointIndicator {
 7699                 is_active,
 7700                 display_row,
 7701                 collides_with_existing_breakpoint,
 7702             }| {
 7703                (
 7704                    is_active && display_row == row,
 7705                    collides_with_existing_breakpoint,
 7706                )
 7707            },
 7708        );
 7709
 7710        let (color, icon) = {
 7711            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7712                (false, false) => ui::IconName::DebugBreakpoint,
 7713                (true, false) => ui::IconName::DebugLogBreakpoint,
 7714                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7715                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7716            };
 7717
 7718            let color = if is_phantom {
 7719                Color::Hint
 7720            } else if is_rejected {
 7721                Color::Disabled
 7722            } else {
 7723                Color::Debugger
 7724            };
 7725
 7726            (color, icon)
 7727        };
 7728
 7729        let breakpoint = Arc::from(breakpoint.clone());
 7730
 7731        let alt_as_text = gpui::Keystroke {
 7732            modifiers: Modifiers::secondary_key(),
 7733            ..Default::default()
 7734        };
 7735        let primary_action_text = if breakpoint.is_disabled() {
 7736            "Enable breakpoint"
 7737        } else if is_phantom && !collides_with_existing {
 7738            "Set breakpoint"
 7739        } else {
 7740            "Unset breakpoint"
 7741        };
 7742        let focus_handle = self.focus_handle.clone();
 7743
 7744        let meta = if is_rejected {
 7745            SharedString::from("No executable code is associated with this line.")
 7746        } else if collides_with_existing && !breakpoint.is_disabled() {
 7747            SharedString::from(format!(
 7748                "{alt_as_text}-click to disable,\nright-click for more options."
 7749            ))
 7750        } else {
 7751            SharedString::from("Right-click for more options.")
 7752        };
 7753        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7754            .icon_size(IconSize::XSmall)
 7755            .size(ui::ButtonSize::None)
 7756            .when(is_rejected, |this| {
 7757                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7758            })
 7759            .icon_color(color)
 7760            .style(ButtonStyle::Transparent)
 7761            .on_click(cx.listener({
 7762                let breakpoint = breakpoint.clone();
 7763
 7764                move |editor, event: &ClickEvent, window, cx| {
 7765                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7766                        BreakpointEditAction::InvertState
 7767                    } else {
 7768                        BreakpointEditAction::Toggle
 7769                    };
 7770
 7771                    window.focus(&editor.focus_handle(cx));
 7772                    editor.edit_breakpoint_at_anchor(
 7773                        position,
 7774                        breakpoint.as_ref().clone(),
 7775                        edit_action,
 7776                        cx,
 7777                    );
 7778                }
 7779            }))
 7780            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7781                editor.set_breakpoint_context_menu(
 7782                    row,
 7783                    Some(position),
 7784                    event.down.position,
 7785                    window,
 7786                    cx,
 7787                );
 7788            }))
 7789            .tooltip(move |window, cx| {
 7790                Tooltip::with_meta_in(
 7791                    primary_action_text,
 7792                    Some(&ToggleBreakpoint),
 7793                    meta.clone(),
 7794                    &focus_handle,
 7795                    window,
 7796                    cx,
 7797                )
 7798            })
 7799    }
 7800
 7801    fn build_tasks_context(
 7802        project: &Entity<Project>,
 7803        buffer: &Entity<Buffer>,
 7804        buffer_row: u32,
 7805        tasks: &Arc<RunnableTasks>,
 7806        cx: &mut Context<Self>,
 7807    ) -> Task<Option<task::TaskContext>> {
 7808        let position = Point::new(buffer_row, tasks.column);
 7809        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7810        let location = Location {
 7811            buffer: buffer.clone(),
 7812            range: range_start..range_start,
 7813        };
 7814        // Fill in the environmental variables from the tree-sitter captures
 7815        let mut captured_task_variables = TaskVariables::default();
 7816        for (capture_name, value) in tasks.extra_variables.clone() {
 7817            captured_task_variables.insert(
 7818                task::VariableName::Custom(capture_name.into()),
 7819                value.clone(),
 7820            );
 7821        }
 7822        project.update(cx, |project, cx| {
 7823            project.task_store().update(cx, |task_store, cx| {
 7824                task_store.task_context_for_location(captured_task_variables, location, cx)
 7825            })
 7826        })
 7827    }
 7828
 7829    pub fn spawn_nearest_task(
 7830        &mut self,
 7831        action: &SpawnNearestTask,
 7832        window: &mut Window,
 7833        cx: &mut Context<Self>,
 7834    ) {
 7835        let Some((workspace, _)) = self.workspace.clone() else {
 7836            return;
 7837        };
 7838        let Some(project) = self.project.clone() else {
 7839            return;
 7840        };
 7841
 7842        // Try to find a closest, enclosing node using tree-sitter that has a
 7843        // task
 7844        let Some((buffer, buffer_row, tasks)) = self
 7845            .find_enclosing_node_task(cx)
 7846            // Or find the task that's closest in row-distance.
 7847            .or_else(|| self.find_closest_task(cx))
 7848        else {
 7849            return;
 7850        };
 7851
 7852        let reveal_strategy = action.reveal;
 7853        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7854        cx.spawn_in(window, async move |_, cx| {
 7855            let context = task_context.await?;
 7856            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7857
 7858            let resolved = &mut resolved_task.resolved;
 7859            resolved.reveal = reveal_strategy;
 7860
 7861            workspace
 7862                .update_in(cx, |workspace, window, cx| {
 7863                    workspace.schedule_resolved_task(
 7864                        task_source_kind,
 7865                        resolved_task,
 7866                        false,
 7867                        window,
 7868                        cx,
 7869                    );
 7870                })
 7871                .ok()
 7872        })
 7873        .detach();
 7874    }
 7875
 7876    fn find_closest_task(
 7877        &mut self,
 7878        cx: &mut Context<Self>,
 7879    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7880        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7881
 7882        let ((buffer_id, row), tasks) = self
 7883            .tasks
 7884            .iter()
 7885            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7886
 7887        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7888        let tasks = Arc::new(tasks.to_owned());
 7889        Some((buffer, *row, tasks))
 7890    }
 7891
 7892    fn find_enclosing_node_task(
 7893        &mut self,
 7894        cx: &mut Context<Self>,
 7895    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7896        let snapshot = self.buffer.read(cx).snapshot(cx);
 7897        let offset = self.selections.newest::<usize>(cx).head();
 7898        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7899        let buffer_id = excerpt.buffer().remote_id();
 7900
 7901        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7902        let mut cursor = layer.node().walk();
 7903
 7904        while cursor.goto_first_child_for_byte(offset).is_some() {
 7905            if cursor.node().end_byte() == offset {
 7906                cursor.goto_next_sibling();
 7907            }
 7908        }
 7909
 7910        // Ascend to the smallest ancestor that contains the range and has a task.
 7911        loop {
 7912            let node = cursor.node();
 7913            let node_range = node.byte_range();
 7914            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7915
 7916            // Check if this node contains our offset
 7917            if node_range.start <= offset && node_range.end >= offset {
 7918                // If it contains offset, check for task
 7919                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7920                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7921                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7922                }
 7923            }
 7924
 7925            if !cursor.goto_parent() {
 7926                break;
 7927            }
 7928        }
 7929        None
 7930    }
 7931
 7932    fn render_run_indicator(
 7933        &self,
 7934        _style: &EditorStyle,
 7935        is_active: bool,
 7936        row: DisplayRow,
 7937        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7938        cx: &mut Context<Self>,
 7939    ) -> IconButton {
 7940        let color = Color::Muted;
 7941        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7942
 7943        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7944            .shape(ui::IconButtonShape::Square)
 7945            .icon_size(IconSize::XSmall)
 7946            .icon_color(color)
 7947            .toggle_state(is_active)
 7948            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7949                let quick_launch = e.down.button == MouseButton::Left;
 7950                window.focus(&editor.focus_handle(cx));
 7951                editor.toggle_code_actions(
 7952                    &ToggleCodeActions {
 7953                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 7954                        quick_launch,
 7955                    },
 7956                    window,
 7957                    cx,
 7958                );
 7959            }))
 7960            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7961                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7962            }))
 7963    }
 7964
 7965    pub fn context_menu_visible(&self) -> bool {
 7966        !self.edit_prediction_preview_is_active()
 7967            && self
 7968                .context_menu
 7969                .borrow()
 7970                .as_ref()
 7971                .map_or(false, |menu| menu.visible())
 7972    }
 7973
 7974    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7975        self.context_menu
 7976            .borrow()
 7977            .as_ref()
 7978            .map(|menu| menu.origin())
 7979    }
 7980
 7981    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7982        self.context_menu_options = Some(options);
 7983    }
 7984
 7985    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7986    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7987
 7988    fn render_edit_prediction_popover(
 7989        &mut self,
 7990        text_bounds: &Bounds<Pixels>,
 7991        content_origin: gpui::Point<Pixels>,
 7992        right_margin: Pixels,
 7993        editor_snapshot: &EditorSnapshot,
 7994        visible_row_range: Range<DisplayRow>,
 7995        scroll_top: f32,
 7996        scroll_bottom: f32,
 7997        line_layouts: &[LineWithInvisibles],
 7998        line_height: Pixels,
 7999        scroll_pixel_position: gpui::Point<Pixels>,
 8000        newest_selection_head: Option<DisplayPoint>,
 8001        editor_width: Pixels,
 8002        style: &EditorStyle,
 8003        window: &mut Window,
 8004        cx: &mut App,
 8005    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8006        if self.mode().is_minimap() {
 8007            return None;
 8008        }
 8009        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8010
 8011        if self.edit_prediction_visible_in_cursor_popover(true) {
 8012            return None;
 8013        }
 8014
 8015        match &active_inline_completion.completion {
 8016            InlineCompletion::Move { target, .. } => {
 8017                let target_display_point = target.to_display_point(editor_snapshot);
 8018
 8019                if self.edit_prediction_requires_modifier() {
 8020                    if !self.edit_prediction_preview_is_active() {
 8021                        return None;
 8022                    }
 8023
 8024                    self.render_edit_prediction_modifier_jump_popover(
 8025                        text_bounds,
 8026                        content_origin,
 8027                        visible_row_range,
 8028                        line_layouts,
 8029                        line_height,
 8030                        scroll_pixel_position,
 8031                        newest_selection_head,
 8032                        target_display_point,
 8033                        window,
 8034                        cx,
 8035                    )
 8036                } else {
 8037                    self.render_edit_prediction_eager_jump_popover(
 8038                        text_bounds,
 8039                        content_origin,
 8040                        editor_snapshot,
 8041                        visible_row_range,
 8042                        scroll_top,
 8043                        scroll_bottom,
 8044                        line_height,
 8045                        scroll_pixel_position,
 8046                        target_display_point,
 8047                        editor_width,
 8048                        window,
 8049                        cx,
 8050                    )
 8051                }
 8052            }
 8053            InlineCompletion::Edit {
 8054                display_mode: EditDisplayMode::Inline,
 8055                ..
 8056            } => None,
 8057            InlineCompletion::Edit {
 8058                display_mode: EditDisplayMode::TabAccept,
 8059                edits,
 8060                ..
 8061            } => {
 8062                let range = &edits.first()?.0;
 8063                let target_display_point = range.end.to_display_point(editor_snapshot);
 8064
 8065                self.render_edit_prediction_end_of_line_popover(
 8066                    "Accept",
 8067                    editor_snapshot,
 8068                    visible_row_range,
 8069                    target_display_point,
 8070                    line_height,
 8071                    scroll_pixel_position,
 8072                    content_origin,
 8073                    editor_width,
 8074                    window,
 8075                    cx,
 8076                )
 8077            }
 8078            InlineCompletion::Edit {
 8079                edits,
 8080                edit_preview,
 8081                display_mode: EditDisplayMode::DiffPopover,
 8082                snapshot,
 8083            } => self.render_edit_prediction_diff_popover(
 8084                text_bounds,
 8085                content_origin,
 8086                right_margin,
 8087                editor_snapshot,
 8088                visible_row_range,
 8089                line_layouts,
 8090                line_height,
 8091                scroll_pixel_position,
 8092                newest_selection_head,
 8093                editor_width,
 8094                style,
 8095                edits,
 8096                edit_preview,
 8097                snapshot,
 8098                window,
 8099                cx,
 8100            ),
 8101        }
 8102    }
 8103
 8104    fn render_edit_prediction_modifier_jump_popover(
 8105        &mut self,
 8106        text_bounds: &Bounds<Pixels>,
 8107        content_origin: gpui::Point<Pixels>,
 8108        visible_row_range: Range<DisplayRow>,
 8109        line_layouts: &[LineWithInvisibles],
 8110        line_height: Pixels,
 8111        scroll_pixel_position: gpui::Point<Pixels>,
 8112        newest_selection_head: Option<DisplayPoint>,
 8113        target_display_point: DisplayPoint,
 8114        window: &mut Window,
 8115        cx: &mut App,
 8116    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8117        let scrolled_content_origin =
 8118            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8119
 8120        const SCROLL_PADDING_Y: Pixels = px(12.);
 8121
 8122        if target_display_point.row() < visible_row_range.start {
 8123            return self.render_edit_prediction_scroll_popover(
 8124                |_| SCROLL_PADDING_Y,
 8125                IconName::ArrowUp,
 8126                visible_row_range,
 8127                line_layouts,
 8128                newest_selection_head,
 8129                scrolled_content_origin,
 8130                window,
 8131                cx,
 8132            );
 8133        } else if target_display_point.row() >= visible_row_range.end {
 8134            return self.render_edit_prediction_scroll_popover(
 8135                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8136                IconName::ArrowDown,
 8137                visible_row_range,
 8138                line_layouts,
 8139                newest_selection_head,
 8140                scrolled_content_origin,
 8141                window,
 8142                cx,
 8143            );
 8144        }
 8145
 8146        const POLE_WIDTH: Pixels = px(2.);
 8147
 8148        let line_layout =
 8149            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8150        let target_column = target_display_point.column() as usize;
 8151
 8152        let target_x = line_layout.x_for_index(target_column);
 8153        let target_y =
 8154            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8155
 8156        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8157
 8158        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8159        border_color.l += 0.001;
 8160
 8161        let mut element = v_flex()
 8162            .items_end()
 8163            .when(flag_on_right, |el| el.items_start())
 8164            .child(if flag_on_right {
 8165                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8166                    .rounded_bl(px(0.))
 8167                    .rounded_tl(px(0.))
 8168                    .border_l_2()
 8169                    .border_color(border_color)
 8170            } else {
 8171                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8172                    .rounded_br(px(0.))
 8173                    .rounded_tr(px(0.))
 8174                    .border_r_2()
 8175                    .border_color(border_color)
 8176            })
 8177            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8178            .into_any();
 8179
 8180        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8181
 8182        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8183            - point(
 8184                if flag_on_right {
 8185                    POLE_WIDTH
 8186                } else {
 8187                    size.width - POLE_WIDTH
 8188                },
 8189                size.height - line_height,
 8190            );
 8191
 8192        origin.x = origin.x.max(content_origin.x);
 8193
 8194        element.prepaint_at(origin, window, cx);
 8195
 8196        Some((element, origin))
 8197    }
 8198
 8199    fn render_edit_prediction_scroll_popover(
 8200        &mut self,
 8201        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8202        scroll_icon: IconName,
 8203        visible_row_range: Range<DisplayRow>,
 8204        line_layouts: &[LineWithInvisibles],
 8205        newest_selection_head: Option<DisplayPoint>,
 8206        scrolled_content_origin: gpui::Point<Pixels>,
 8207        window: &mut Window,
 8208        cx: &mut App,
 8209    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8210        let mut element = self
 8211            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8212            .into_any();
 8213
 8214        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8215
 8216        let cursor = newest_selection_head?;
 8217        let cursor_row_layout =
 8218            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8219        let cursor_column = cursor.column() as usize;
 8220
 8221        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8222
 8223        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8224
 8225        element.prepaint_at(origin, window, cx);
 8226        Some((element, origin))
 8227    }
 8228
 8229    fn render_edit_prediction_eager_jump_popover(
 8230        &mut self,
 8231        text_bounds: &Bounds<Pixels>,
 8232        content_origin: gpui::Point<Pixels>,
 8233        editor_snapshot: &EditorSnapshot,
 8234        visible_row_range: Range<DisplayRow>,
 8235        scroll_top: f32,
 8236        scroll_bottom: f32,
 8237        line_height: Pixels,
 8238        scroll_pixel_position: gpui::Point<Pixels>,
 8239        target_display_point: DisplayPoint,
 8240        editor_width: Pixels,
 8241        window: &mut Window,
 8242        cx: &mut App,
 8243    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8244        if target_display_point.row().as_f32() < scroll_top {
 8245            let mut element = self
 8246                .render_edit_prediction_line_popover(
 8247                    "Jump to Edit",
 8248                    Some(IconName::ArrowUp),
 8249                    window,
 8250                    cx,
 8251                )?
 8252                .into_any();
 8253
 8254            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8255            let offset = point(
 8256                (text_bounds.size.width - size.width) / 2.,
 8257                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8258            );
 8259
 8260            let origin = text_bounds.origin + offset;
 8261            element.prepaint_at(origin, window, cx);
 8262            Some((element, origin))
 8263        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8264            let mut element = self
 8265                .render_edit_prediction_line_popover(
 8266                    "Jump to Edit",
 8267                    Some(IconName::ArrowDown),
 8268                    window,
 8269                    cx,
 8270                )?
 8271                .into_any();
 8272
 8273            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8274            let offset = point(
 8275                (text_bounds.size.width - size.width) / 2.,
 8276                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8277            );
 8278
 8279            let origin = text_bounds.origin + offset;
 8280            element.prepaint_at(origin, window, cx);
 8281            Some((element, origin))
 8282        } else {
 8283            self.render_edit_prediction_end_of_line_popover(
 8284                "Jump to Edit",
 8285                editor_snapshot,
 8286                visible_row_range,
 8287                target_display_point,
 8288                line_height,
 8289                scroll_pixel_position,
 8290                content_origin,
 8291                editor_width,
 8292                window,
 8293                cx,
 8294            )
 8295        }
 8296    }
 8297
 8298    fn render_edit_prediction_end_of_line_popover(
 8299        self: &mut Editor,
 8300        label: &'static str,
 8301        editor_snapshot: &EditorSnapshot,
 8302        visible_row_range: Range<DisplayRow>,
 8303        target_display_point: DisplayPoint,
 8304        line_height: Pixels,
 8305        scroll_pixel_position: gpui::Point<Pixels>,
 8306        content_origin: gpui::Point<Pixels>,
 8307        editor_width: Pixels,
 8308        window: &mut Window,
 8309        cx: &mut App,
 8310    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8311        let target_line_end = DisplayPoint::new(
 8312            target_display_point.row(),
 8313            editor_snapshot.line_len(target_display_point.row()),
 8314        );
 8315
 8316        let mut element = self
 8317            .render_edit_prediction_line_popover(label, None, window, cx)?
 8318            .into_any();
 8319
 8320        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8321
 8322        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8323
 8324        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8325        let mut origin = start_point
 8326            + line_origin
 8327            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8328        origin.x = origin.x.max(content_origin.x);
 8329
 8330        let max_x = content_origin.x + editor_width - size.width;
 8331
 8332        if origin.x > max_x {
 8333            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8334
 8335            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8336                origin.y += offset;
 8337                IconName::ArrowUp
 8338            } else {
 8339                origin.y -= offset;
 8340                IconName::ArrowDown
 8341            };
 8342
 8343            element = self
 8344                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8345                .into_any();
 8346
 8347            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8348
 8349            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8350        }
 8351
 8352        element.prepaint_at(origin, window, cx);
 8353        Some((element, origin))
 8354    }
 8355
 8356    fn render_edit_prediction_diff_popover(
 8357        self: &Editor,
 8358        text_bounds: &Bounds<Pixels>,
 8359        content_origin: gpui::Point<Pixels>,
 8360        right_margin: Pixels,
 8361        editor_snapshot: &EditorSnapshot,
 8362        visible_row_range: Range<DisplayRow>,
 8363        line_layouts: &[LineWithInvisibles],
 8364        line_height: Pixels,
 8365        scroll_pixel_position: gpui::Point<Pixels>,
 8366        newest_selection_head: Option<DisplayPoint>,
 8367        editor_width: Pixels,
 8368        style: &EditorStyle,
 8369        edits: &Vec<(Range<Anchor>, String)>,
 8370        edit_preview: &Option<language::EditPreview>,
 8371        snapshot: &language::BufferSnapshot,
 8372        window: &mut Window,
 8373        cx: &mut App,
 8374    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8375        let edit_start = edits
 8376            .first()
 8377            .unwrap()
 8378            .0
 8379            .start
 8380            .to_display_point(editor_snapshot);
 8381        let edit_end = edits
 8382            .last()
 8383            .unwrap()
 8384            .0
 8385            .end
 8386            .to_display_point(editor_snapshot);
 8387
 8388        let is_visible = visible_row_range.contains(&edit_start.row())
 8389            || visible_row_range.contains(&edit_end.row());
 8390        if !is_visible {
 8391            return None;
 8392        }
 8393
 8394        let highlighted_edits =
 8395            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8396
 8397        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8398        let line_count = highlighted_edits.text.lines().count();
 8399
 8400        const BORDER_WIDTH: Pixels = px(1.);
 8401
 8402        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8403        let has_keybind = keybind.is_some();
 8404
 8405        let mut element = h_flex()
 8406            .items_start()
 8407            .child(
 8408                h_flex()
 8409                    .bg(cx.theme().colors().editor_background)
 8410                    .border(BORDER_WIDTH)
 8411                    .shadow_sm()
 8412                    .border_color(cx.theme().colors().border)
 8413                    .rounded_l_lg()
 8414                    .when(line_count > 1, |el| el.rounded_br_lg())
 8415                    .pr_1()
 8416                    .child(styled_text),
 8417            )
 8418            .child(
 8419                h_flex()
 8420                    .h(line_height + BORDER_WIDTH * 2.)
 8421                    .px_1p5()
 8422                    .gap_1()
 8423                    // Workaround: For some reason, there's a gap if we don't do this
 8424                    .ml(-BORDER_WIDTH)
 8425                    .shadow(vec![gpui::BoxShadow {
 8426                        color: gpui::black().opacity(0.05),
 8427                        offset: point(px(1.), px(1.)),
 8428                        blur_radius: px(2.),
 8429                        spread_radius: px(0.),
 8430                    }])
 8431                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8432                    .border(BORDER_WIDTH)
 8433                    .border_color(cx.theme().colors().border)
 8434                    .rounded_r_lg()
 8435                    .id("edit_prediction_diff_popover_keybind")
 8436                    .when(!has_keybind, |el| {
 8437                        let status_colors = cx.theme().status();
 8438
 8439                        el.bg(status_colors.error_background)
 8440                            .border_color(status_colors.error.opacity(0.6))
 8441                            .child(Icon::new(IconName::Info).color(Color::Error))
 8442                            .cursor_default()
 8443                            .hoverable_tooltip(move |_window, cx| {
 8444                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8445                            })
 8446                    })
 8447                    .children(keybind),
 8448            )
 8449            .into_any();
 8450
 8451        let longest_row =
 8452            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8453        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8454            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8455        } else {
 8456            layout_line(
 8457                longest_row,
 8458                editor_snapshot,
 8459                style,
 8460                editor_width,
 8461                |_| false,
 8462                window,
 8463                cx,
 8464            )
 8465            .width
 8466        };
 8467
 8468        let viewport_bounds =
 8469            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8470                right: -right_margin,
 8471                ..Default::default()
 8472            });
 8473
 8474        let x_after_longest =
 8475            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8476                - scroll_pixel_position.x;
 8477
 8478        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8479
 8480        // Fully visible if it can be displayed within the window (allow overlapping other
 8481        // panes). However, this is only allowed if the popover starts within text_bounds.
 8482        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8483            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8484
 8485        let mut origin = if can_position_to_the_right {
 8486            point(
 8487                x_after_longest,
 8488                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8489                    - scroll_pixel_position.y,
 8490            )
 8491        } else {
 8492            let cursor_row = newest_selection_head.map(|head| head.row());
 8493            let above_edit = edit_start
 8494                .row()
 8495                .0
 8496                .checked_sub(line_count as u32)
 8497                .map(DisplayRow);
 8498            let below_edit = Some(edit_end.row() + 1);
 8499            let above_cursor =
 8500                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8501            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8502
 8503            // Place the edit popover adjacent to the edit if there is a location
 8504            // available that is onscreen and does not obscure the cursor. Otherwise,
 8505            // place it adjacent to the cursor.
 8506            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8507                .into_iter()
 8508                .flatten()
 8509                .find(|&start_row| {
 8510                    let end_row = start_row + line_count as u32;
 8511                    visible_row_range.contains(&start_row)
 8512                        && visible_row_range.contains(&end_row)
 8513                        && cursor_row.map_or(true, |cursor_row| {
 8514                            !((start_row..end_row).contains(&cursor_row))
 8515                        })
 8516                })?;
 8517
 8518            content_origin
 8519                + point(
 8520                    -scroll_pixel_position.x,
 8521                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8522                )
 8523        };
 8524
 8525        origin.x -= BORDER_WIDTH;
 8526
 8527        window.defer_draw(element, origin, 1);
 8528
 8529        // Do not return an element, since it will already be drawn due to defer_draw.
 8530        None
 8531    }
 8532
 8533    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8534        px(30.)
 8535    }
 8536
 8537    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8538        if self.read_only(cx) {
 8539            cx.theme().players().read_only()
 8540        } else {
 8541            self.style.as_ref().unwrap().local_player
 8542        }
 8543    }
 8544
 8545    fn render_edit_prediction_accept_keybind(
 8546        &self,
 8547        window: &mut Window,
 8548        cx: &App,
 8549    ) -> Option<AnyElement> {
 8550        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8551        let accept_keystroke = accept_binding.keystroke()?;
 8552
 8553        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8554
 8555        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8556            Color::Accent
 8557        } else {
 8558            Color::Muted
 8559        };
 8560
 8561        h_flex()
 8562            .px_0p5()
 8563            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8564            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8565            .text_size(TextSize::XSmall.rems(cx))
 8566            .child(h_flex().children(ui::render_modifiers(
 8567                &accept_keystroke.modifiers,
 8568                PlatformStyle::platform(),
 8569                Some(modifiers_color),
 8570                Some(IconSize::XSmall.rems().into()),
 8571                true,
 8572            )))
 8573            .when(is_platform_style_mac, |parent| {
 8574                parent.child(accept_keystroke.key.clone())
 8575            })
 8576            .when(!is_platform_style_mac, |parent| {
 8577                parent.child(
 8578                    Key::new(
 8579                        util::capitalize(&accept_keystroke.key),
 8580                        Some(Color::Default),
 8581                    )
 8582                    .size(Some(IconSize::XSmall.rems().into())),
 8583                )
 8584            })
 8585            .into_any()
 8586            .into()
 8587    }
 8588
 8589    fn render_edit_prediction_line_popover(
 8590        &self,
 8591        label: impl Into<SharedString>,
 8592        icon: Option<IconName>,
 8593        window: &mut Window,
 8594        cx: &App,
 8595    ) -> Option<Stateful<Div>> {
 8596        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8597
 8598        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8599        let has_keybind = keybind.is_some();
 8600
 8601        let result = h_flex()
 8602            .id("ep-line-popover")
 8603            .py_0p5()
 8604            .pl_1()
 8605            .pr(padding_right)
 8606            .gap_1()
 8607            .rounded_md()
 8608            .border_1()
 8609            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8610            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8611            .shadow_sm()
 8612            .when(!has_keybind, |el| {
 8613                let status_colors = cx.theme().status();
 8614
 8615                el.bg(status_colors.error_background)
 8616                    .border_color(status_colors.error.opacity(0.6))
 8617                    .pl_2()
 8618                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8619                    .cursor_default()
 8620                    .hoverable_tooltip(move |_window, cx| {
 8621                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8622                    })
 8623            })
 8624            .children(keybind)
 8625            .child(
 8626                Label::new(label)
 8627                    .size(LabelSize::Small)
 8628                    .when(!has_keybind, |el| {
 8629                        el.color(cx.theme().status().error.into()).strikethrough()
 8630                    }),
 8631            )
 8632            .when(!has_keybind, |el| {
 8633                el.child(
 8634                    h_flex().ml_1().child(
 8635                        Icon::new(IconName::Info)
 8636                            .size(IconSize::Small)
 8637                            .color(cx.theme().status().error.into()),
 8638                    ),
 8639                )
 8640            })
 8641            .when_some(icon, |element, icon| {
 8642                element.child(
 8643                    div()
 8644                        .mt(px(1.5))
 8645                        .child(Icon::new(icon).size(IconSize::Small)),
 8646                )
 8647            });
 8648
 8649        Some(result)
 8650    }
 8651
 8652    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8653        let accent_color = cx.theme().colors().text_accent;
 8654        let editor_bg_color = cx.theme().colors().editor_background;
 8655        editor_bg_color.blend(accent_color.opacity(0.1))
 8656    }
 8657
 8658    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8659        let accent_color = cx.theme().colors().text_accent;
 8660        let editor_bg_color = cx.theme().colors().editor_background;
 8661        editor_bg_color.blend(accent_color.opacity(0.6))
 8662    }
 8663
 8664    fn render_edit_prediction_cursor_popover(
 8665        &self,
 8666        min_width: Pixels,
 8667        max_width: Pixels,
 8668        cursor_point: Point,
 8669        style: &EditorStyle,
 8670        accept_keystroke: Option<&gpui::Keystroke>,
 8671        _window: &Window,
 8672        cx: &mut Context<Editor>,
 8673    ) -> Option<AnyElement> {
 8674        let provider = self.edit_prediction_provider.as_ref()?;
 8675
 8676        if provider.provider.needs_terms_acceptance(cx) {
 8677            return Some(
 8678                h_flex()
 8679                    .min_w(min_width)
 8680                    .flex_1()
 8681                    .px_2()
 8682                    .py_1()
 8683                    .gap_3()
 8684                    .elevation_2(cx)
 8685                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8686                    .id("accept-terms")
 8687                    .cursor_pointer()
 8688                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8689                    .on_click(cx.listener(|this, _event, window, cx| {
 8690                        cx.stop_propagation();
 8691                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8692                        window.dispatch_action(
 8693                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8694                            cx,
 8695                        );
 8696                    }))
 8697                    .child(
 8698                        h_flex()
 8699                            .flex_1()
 8700                            .gap_2()
 8701                            .child(Icon::new(IconName::ZedPredict))
 8702                            .child(Label::new("Accept Terms of Service"))
 8703                            .child(div().w_full())
 8704                            .child(
 8705                                Icon::new(IconName::ArrowUpRight)
 8706                                    .color(Color::Muted)
 8707                                    .size(IconSize::Small),
 8708                            )
 8709                            .into_any_element(),
 8710                    )
 8711                    .into_any(),
 8712            );
 8713        }
 8714
 8715        let is_refreshing = provider.provider.is_refreshing(cx);
 8716
 8717        fn pending_completion_container() -> Div {
 8718            h_flex()
 8719                .h_full()
 8720                .flex_1()
 8721                .gap_2()
 8722                .child(Icon::new(IconName::ZedPredict))
 8723        }
 8724
 8725        let completion = match &self.active_inline_completion {
 8726            Some(prediction) => {
 8727                if !self.has_visible_completions_menu() {
 8728                    const RADIUS: Pixels = px(6.);
 8729                    const BORDER_WIDTH: Pixels = px(1.);
 8730
 8731                    return Some(
 8732                        h_flex()
 8733                            .elevation_2(cx)
 8734                            .border(BORDER_WIDTH)
 8735                            .border_color(cx.theme().colors().border)
 8736                            .when(accept_keystroke.is_none(), |el| {
 8737                                el.border_color(cx.theme().status().error)
 8738                            })
 8739                            .rounded(RADIUS)
 8740                            .rounded_tl(px(0.))
 8741                            .overflow_hidden()
 8742                            .child(div().px_1p5().child(match &prediction.completion {
 8743                                InlineCompletion::Move { target, snapshot } => {
 8744                                    use text::ToPoint as _;
 8745                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8746                                    {
 8747                                        Icon::new(IconName::ZedPredictDown)
 8748                                    } else {
 8749                                        Icon::new(IconName::ZedPredictUp)
 8750                                    }
 8751                                }
 8752                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8753                            }))
 8754                            .child(
 8755                                h_flex()
 8756                                    .gap_1()
 8757                                    .py_1()
 8758                                    .px_2()
 8759                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8760                                    .border_l_1()
 8761                                    .border_color(cx.theme().colors().border)
 8762                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8763                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8764                                        el.child(
 8765                                            Label::new("Hold")
 8766                                                .size(LabelSize::Small)
 8767                                                .when(accept_keystroke.is_none(), |el| {
 8768                                                    el.strikethrough()
 8769                                                })
 8770                                                .line_height_style(LineHeightStyle::UiLabel),
 8771                                        )
 8772                                    })
 8773                                    .id("edit_prediction_cursor_popover_keybind")
 8774                                    .when(accept_keystroke.is_none(), |el| {
 8775                                        let status_colors = cx.theme().status();
 8776
 8777                                        el.bg(status_colors.error_background)
 8778                                            .border_color(status_colors.error.opacity(0.6))
 8779                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8780                                            .cursor_default()
 8781                                            .hoverable_tooltip(move |_window, cx| {
 8782                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8783                                                    .into()
 8784                                            })
 8785                                    })
 8786                                    .when_some(
 8787                                        accept_keystroke.as_ref(),
 8788                                        |el, accept_keystroke| {
 8789                                            el.child(h_flex().children(ui::render_modifiers(
 8790                                                &accept_keystroke.modifiers,
 8791                                                PlatformStyle::platform(),
 8792                                                Some(Color::Default),
 8793                                                Some(IconSize::XSmall.rems().into()),
 8794                                                false,
 8795                                            )))
 8796                                        },
 8797                                    ),
 8798                            )
 8799                            .into_any(),
 8800                    );
 8801                }
 8802
 8803                self.render_edit_prediction_cursor_popover_preview(
 8804                    prediction,
 8805                    cursor_point,
 8806                    style,
 8807                    cx,
 8808                )?
 8809            }
 8810
 8811            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8812                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8813                    stale_completion,
 8814                    cursor_point,
 8815                    style,
 8816                    cx,
 8817                )?,
 8818
 8819                None => {
 8820                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8821                }
 8822            },
 8823
 8824            None => pending_completion_container().child(Label::new("No Prediction")),
 8825        };
 8826
 8827        let completion = if is_refreshing {
 8828            completion
 8829                .with_animation(
 8830                    "loading-completion",
 8831                    Animation::new(Duration::from_secs(2))
 8832                        .repeat()
 8833                        .with_easing(pulsating_between(0.4, 0.8)),
 8834                    |label, delta| label.opacity(delta),
 8835                )
 8836                .into_any_element()
 8837        } else {
 8838            completion.into_any_element()
 8839        };
 8840
 8841        let has_completion = self.active_inline_completion.is_some();
 8842
 8843        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8844        Some(
 8845            h_flex()
 8846                .min_w(min_width)
 8847                .max_w(max_width)
 8848                .flex_1()
 8849                .elevation_2(cx)
 8850                .border_color(cx.theme().colors().border)
 8851                .child(
 8852                    div()
 8853                        .flex_1()
 8854                        .py_1()
 8855                        .px_2()
 8856                        .overflow_hidden()
 8857                        .child(completion),
 8858                )
 8859                .when_some(accept_keystroke, |el, accept_keystroke| {
 8860                    if !accept_keystroke.modifiers.modified() {
 8861                        return el;
 8862                    }
 8863
 8864                    el.child(
 8865                        h_flex()
 8866                            .h_full()
 8867                            .border_l_1()
 8868                            .rounded_r_lg()
 8869                            .border_color(cx.theme().colors().border)
 8870                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8871                            .gap_1()
 8872                            .py_1()
 8873                            .px_2()
 8874                            .child(
 8875                                h_flex()
 8876                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8877                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8878                                    .child(h_flex().children(ui::render_modifiers(
 8879                                        &accept_keystroke.modifiers,
 8880                                        PlatformStyle::platform(),
 8881                                        Some(if !has_completion {
 8882                                            Color::Muted
 8883                                        } else {
 8884                                            Color::Default
 8885                                        }),
 8886                                        None,
 8887                                        false,
 8888                                    ))),
 8889                            )
 8890                            .child(Label::new("Preview").into_any_element())
 8891                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8892                    )
 8893                })
 8894                .into_any(),
 8895        )
 8896    }
 8897
 8898    fn render_edit_prediction_cursor_popover_preview(
 8899        &self,
 8900        completion: &InlineCompletionState,
 8901        cursor_point: Point,
 8902        style: &EditorStyle,
 8903        cx: &mut Context<Editor>,
 8904    ) -> Option<Div> {
 8905        use text::ToPoint as _;
 8906
 8907        fn render_relative_row_jump(
 8908            prefix: impl Into<String>,
 8909            current_row: u32,
 8910            target_row: u32,
 8911        ) -> Div {
 8912            let (row_diff, arrow) = if target_row < current_row {
 8913                (current_row - target_row, IconName::ArrowUp)
 8914            } else {
 8915                (target_row - current_row, IconName::ArrowDown)
 8916            };
 8917
 8918            h_flex()
 8919                .child(
 8920                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8921                        .color(Color::Muted)
 8922                        .size(LabelSize::Small),
 8923                )
 8924                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8925        }
 8926
 8927        match &completion.completion {
 8928            InlineCompletion::Move {
 8929                target, snapshot, ..
 8930            } => Some(
 8931                h_flex()
 8932                    .px_2()
 8933                    .gap_2()
 8934                    .flex_1()
 8935                    .child(
 8936                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8937                            Icon::new(IconName::ZedPredictDown)
 8938                        } else {
 8939                            Icon::new(IconName::ZedPredictUp)
 8940                        },
 8941                    )
 8942                    .child(Label::new("Jump to Edit")),
 8943            ),
 8944
 8945            InlineCompletion::Edit {
 8946                edits,
 8947                edit_preview,
 8948                snapshot,
 8949                display_mode: _,
 8950            } => {
 8951                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8952
 8953                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8954                    &snapshot,
 8955                    &edits,
 8956                    edit_preview.as_ref()?,
 8957                    true,
 8958                    cx,
 8959                )
 8960                .first_line_preview();
 8961
 8962                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8963                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8964
 8965                let preview = h_flex()
 8966                    .gap_1()
 8967                    .min_w_16()
 8968                    .child(styled_text)
 8969                    .when(has_more_lines, |parent| parent.child(""));
 8970
 8971                let left = if first_edit_row != cursor_point.row {
 8972                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8973                        .into_any_element()
 8974                } else {
 8975                    Icon::new(IconName::ZedPredict).into_any_element()
 8976                };
 8977
 8978                Some(
 8979                    h_flex()
 8980                        .h_full()
 8981                        .flex_1()
 8982                        .gap_2()
 8983                        .pr_1()
 8984                        .overflow_x_hidden()
 8985                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8986                        .child(left)
 8987                        .child(preview),
 8988                )
 8989            }
 8990        }
 8991    }
 8992
 8993    pub fn render_context_menu(
 8994        &self,
 8995        style: &EditorStyle,
 8996        max_height_in_lines: u32,
 8997        window: &mut Window,
 8998        cx: &mut Context<Editor>,
 8999    ) -> Option<AnyElement> {
 9000        let menu = self.context_menu.borrow();
 9001        let menu = menu.as_ref()?;
 9002        if !menu.visible() {
 9003            return None;
 9004        };
 9005        Some(menu.render(style, max_height_in_lines, window, cx))
 9006    }
 9007
 9008    fn render_context_menu_aside(
 9009        &mut self,
 9010        max_size: Size<Pixels>,
 9011        window: &mut Window,
 9012        cx: &mut Context<Editor>,
 9013    ) -> Option<AnyElement> {
 9014        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9015            if menu.visible() {
 9016                menu.render_aside(max_size, window, cx)
 9017            } else {
 9018                None
 9019            }
 9020        })
 9021    }
 9022
 9023    fn hide_context_menu(
 9024        &mut self,
 9025        window: &mut Window,
 9026        cx: &mut Context<Self>,
 9027    ) -> Option<CodeContextMenu> {
 9028        cx.notify();
 9029        self.completion_tasks.clear();
 9030        let context_menu = self.context_menu.borrow_mut().take();
 9031        self.stale_inline_completion_in_menu.take();
 9032        self.update_visible_inline_completion(window, cx);
 9033        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9034            if let Some(completion_provider) = &self.completion_provider {
 9035                completion_provider.selection_changed(None, window, cx);
 9036            }
 9037        }
 9038        context_menu
 9039    }
 9040
 9041    fn show_snippet_choices(
 9042        &mut self,
 9043        choices: &Vec<String>,
 9044        selection: Range<Anchor>,
 9045        cx: &mut Context<Self>,
 9046    ) {
 9047        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9048            (Some(a), Some(b)) if a == b => a,
 9049            _ => {
 9050                log::error!("expected anchor range to have matching buffer IDs");
 9051                return;
 9052            }
 9053        };
 9054        let multi_buffer = self.buffer().read(cx);
 9055        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9056            return;
 9057        };
 9058
 9059        let id = post_inc(&mut self.next_completion_id);
 9060        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9061        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9062            CompletionsMenu::new_snippet_choices(
 9063                id,
 9064                true,
 9065                choices,
 9066                selection,
 9067                buffer,
 9068                snippet_sort_order,
 9069            ),
 9070        ));
 9071    }
 9072
 9073    pub fn insert_snippet(
 9074        &mut self,
 9075        insertion_ranges: &[Range<usize>],
 9076        snippet: Snippet,
 9077        window: &mut Window,
 9078        cx: &mut Context<Self>,
 9079    ) -> Result<()> {
 9080        struct Tabstop<T> {
 9081            is_end_tabstop: bool,
 9082            ranges: Vec<Range<T>>,
 9083            choices: Option<Vec<String>>,
 9084        }
 9085
 9086        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9087            let snippet_text: Arc<str> = snippet.text.clone().into();
 9088            let edits = insertion_ranges
 9089                .iter()
 9090                .cloned()
 9091                .map(|range| (range, snippet_text.clone()));
 9092            let autoindent_mode = AutoindentMode::Block {
 9093                original_indent_columns: Vec::new(),
 9094            };
 9095            buffer.edit(edits, Some(autoindent_mode), cx);
 9096
 9097            let snapshot = &*buffer.read(cx);
 9098            let snippet = &snippet;
 9099            snippet
 9100                .tabstops
 9101                .iter()
 9102                .map(|tabstop| {
 9103                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9104                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9105                    });
 9106                    let mut tabstop_ranges = tabstop
 9107                        .ranges
 9108                        .iter()
 9109                        .flat_map(|tabstop_range| {
 9110                            let mut delta = 0_isize;
 9111                            insertion_ranges.iter().map(move |insertion_range| {
 9112                                let insertion_start = insertion_range.start as isize + delta;
 9113                                delta +=
 9114                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9115
 9116                                let start = ((insertion_start + tabstop_range.start) as usize)
 9117                                    .min(snapshot.len());
 9118                                let end = ((insertion_start + tabstop_range.end) as usize)
 9119                                    .min(snapshot.len());
 9120                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9121                            })
 9122                        })
 9123                        .collect::<Vec<_>>();
 9124                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9125
 9126                    Tabstop {
 9127                        is_end_tabstop,
 9128                        ranges: tabstop_ranges,
 9129                        choices: tabstop.choices.clone(),
 9130                    }
 9131                })
 9132                .collect::<Vec<_>>()
 9133        });
 9134        if let Some(tabstop) = tabstops.first() {
 9135            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9136                // Reverse order so that the first range is the newest created selection.
 9137                // Completions will use it and autoscroll will prioritize it.
 9138                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9139            });
 9140
 9141            if let Some(choices) = &tabstop.choices {
 9142                if let Some(selection) = tabstop.ranges.first() {
 9143                    self.show_snippet_choices(choices, selection.clone(), cx)
 9144                }
 9145            }
 9146
 9147            // If we're already at the last tabstop and it's at the end of the snippet,
 9148            // we're done, we don't need to keep the state around.
 9149            if !tabstop.is_end_tabstop {
 9150                let choices = tabstops
 9151                    .iter()
 9152                    .map(|tabstop| tabstop.choices.clone())
 9153                    .collect();
 9154
 9155                let ranges = tabstops
 9156                    .into_iter()
 9157                    .map(|tabstop| tabstop.ranges)
 9158                    .collect::<Vec<_>>();
 9159
 9160                self.snippet_stack.push(SnippetState {
 9161                    active_index: 0,
 9162                    ranges,
 9163                    choices,
 9164                });
 9165            }
 9166
 9167            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9168            if self.autoclose_regions.is_empty() {
 9169                let snapshot = self.buffer.read(cx).snapshot(cx);
 9170                for selection in &mut self.selections.all::<Point>(cx) {
 9171                    let selection_head = selection.head();
 9172                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9173                        continue;
 9174                    };
 9175
 9176                    let mut bracket_pair = None;
 9177                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9178                    let prev_chars = snapshot
 9179                        .reversed_chars_at(selection_head)
 9180                        .collect::<String>();
 9181                    for (pair, enabled) in scope.brackets() {
 9182                        if enabled
 9183                            && pair.close
 9184                            && prev_chars.starts_with(pair.start.as_str())
 9185                            && next_chars.starts_with(pair.end.as_str())
 9186                        {
 9187                            bracket_pair = Some(pair.clone());
 9188                            break;
 9189                        }
 9190                    }
 9191                    if let Some(pair) = bracket_pair {
 9192                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9193                        let autoclose_enabled =
 9194                            self.use_autoclose && snapshot_settings.use_autoclose;
 9195                        if autoclose_enabled {
 9196                            let start = snapshot.anchor_after(selection_head);
 9197                            let end = snapshot.anchor_after(selection_head);
 9198                            self.autoclose_regions.push(AutocloseRegion {
 9199                                selection_id: selection.id,
 9200                                range: start..end,
 9201                                pair,
 9202                            });
 9203                        }
 9204                    }
 9205                }
 9206            }
 9207        }
 9208        Ok(())
 9209    }
 9210
 9211    pub fn move_to_next_snippet_tabstop(
 9212        &mut self,
 9213        window: &mut Window,
 9214        cx: &mut Context<Self>,
 9215    ) -> bool {
 9216        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9217    }
 9218
 9219    pub fn move_to_prev_snippet_tabstop(
 9220        &mut self,
 9221        window: &mut Window,
 9222        cx: &mut Context<Self>,
 9223    ) -> bool {
 9224        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9225    }
 9226
 9227    pub fn move_to_snippet_tabstop(
 9228        &mut self,
 9229        bias: Bias,
 9230        window: &mut Window,
 9231        cx: &mut Context<Self>,
 9232    ) -> bool {
 9233        if let Some(mut snippet) = self.snippet_stack.pop() {
 9234            match bias {
 9235                Bias::Left => {
 9236                    if snippet.active_index > 0 {
 9237                        snippet.active_index -= 1;
 9238                    } else {
 9239                        self.snippet_stack.push(snippet);
 9240                        return false;
 9241                    }
 9242                }
 9243                Bias::Right => {
 9244                    if snippet.active_index + 1 < snippet.ranges.len() {
 9245                        snippet.active_index += 1;
 9246                    } else {
 9247                        self.snippet_stack.push(snippet);
 9248                        return false;
 9249                    }
 9250                }
 9251            }
 9252            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9253                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9254                    // Reverse order so that the first range is the newest created selection.
 9255                    // Completions will use it and autoscroll will prioritize it.
 9256                    s.select_ranges(current_ranges.iter().rev().cloned())
 9257                });
 9258
 9259                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9260                    if let Some(selection) = current_ranges.first() {
 9261                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9262                    }
 9263                }
 9264
 9265                // If snippet state is not at the last tabstop, push it back on the stack
 9266                if snippet.active_index + 1 < snippet.ranges.len() {
 9267                    self.snippet_stack.push(snippet);
 9268                }
 9269                return true;
 9270            }
 9271        }
 9272
 9273        false
 9274    }
 9275
 9276    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9277        self.transact(window, cx, |this, window, cx| {
 9278            this.select_all(&SelectAll, window, cx);
 9279            this.insert("", window, cx);
 9280        });
 9281    }
 9282
 9283    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9284        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9285        self.transact(window, cx, |this, window, cx| {
 9286            this.select_autoclose_pair(window, cx);
 9287            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9288            if !this.linked_edit_ranges.is_empty() {
 9289                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9290                let snapshot = this.buffer.read(cx).snapshot(cx);
 9291
 9292                for selection in selections.iter() {
 9293                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9294                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9295                    if selection_start.buffer_id != selection_end.buffer_id {
 9296                        continue;
 9297                    }
 9298                    if let Some(ranges) =
 9299                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9300                    {
 9301                        for (buffer, entries) in ranges {
 9302                            linked_ranges.entry(buffer).or_default().extend(entries);
 9303                        }
 9304                    }
 9305                }
 9306            }
 9307
 9308            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9309            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9310            for selection in &mut selections {
 9311                if selection.is_empty() {
 9312                    let old_head = selection.head();
 9313                    let mut new_head =
 9314                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9315                            .to_point(&display_map);
 9316                    if let Some((buffer, line_buffer_range)) = display_map
 9317                        .buffer_snapshot
 9318                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9319                    {
 9320                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9321                        let indent_len = match indent_size.kind {
 9322                            IndentKind::Space => {
 9323                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9324                            }
 9325                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9326                        };
 9327                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9328                            let indent_len = indent_len.get();
 9329                            new_head = cmp::min(
 9330                                new_head,
 9331                                MultiBufferPoint::new(
 9332                                    old_head.row,
 9333                                    ((old_head.column - 1) / indent_len) * indent_len,
 9334                                ),
 9335                            );
 9336                        }
 9337                    }
 9338
 9339                    selection.set_head(new_head, SelectionGoal::None);
 9340                }
 9341            }
 9342
 9343            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9344                s.select(selections)
 9345            });
 9346            this.insert("", window, cx);
 9347            let empty_str: Arc<str> = Arc::from("");
 9348            for (buffer, edits) in linked_ranges {
 9349                let snapshot = buffer.read(cx).snapshot();
 9350                use text::ToPoint as TP;
 9351
 9352                let edits = edits
 9353                    .into_iter()
 9354                    .map(|range| {
 9355                        let end_point = TP::to_point(&range.end, &snapshot);
 9356                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9357
 9358                        if end_point == start_point {
 9359                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9360                                .saturating_sub(1);
 9361                            start_point =
 9362                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9363                        };
 9364
 9365                        (start_point..end_point, empty_str.clone())
 9366                    })
 9367                    .sorted_by_key(|(range, _)| range.start)
 9368                    .collect::<Vec<_>>();
 9369                buffer.update(cx, |this, cx| {
 9370                    this.edit(edits, None, cx);
 9371                })
 9372            }
 9373            this.refresh_inline_completion(true, false, window, cx);
 9374            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9375        });
 9376    }
 9377
 9378    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9379        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9380        self.transact(window, cx, |this, window, cx| {
 9381            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9382                s.move_with(|map, selection| {
 9383                    if selection.is_empty() {
 9384                        let cursor = movement::right(map, selection.head());
 9385                        selection.end = cursor;
 9386                        selection.reversed = true;
 9387                        selection.goal = SelectionGoal::None;
 9388                    }
 9389                })
 9390            });
 9391            this.insert("", window, cx);
 9392            this.refresh_inline_completion(true, false, window, cx);
 9393        });
 9394    }
 9395
 9396    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9397        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9398        if self.move_to_prev_snippet_tabstop(window, cx) {
 9399            return;
 9400        }
 9401        self.outdent(&Outdent, window, cx);
 9402    }
 9403
 9404    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9405        if self.move_to_next_snippet_tabstop(window, cx) {
 9406            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9407            return;
 9408        }
 9409        if self.read_only(cx) {
 9410            return;
 9411        }
 9412        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9413        let mut selections = self.selections.all_adjusted(cx);
 9414        let buffer = self.buffer.read(cx);
 9415        let snapshot = buffer.snapshot(cx);
 9416        let rows_iter = selections.iter().map(|s| s.head().row);
 9417        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9418
 9419        let has_some_cursor_in_whitespace = selections
 9420            .iter()
 9421            .filter(|selection| selection.is_empty())
 9422            .any(|selection| {
 9423                let cursor = selection.head();
 9424                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9425                cursor.column < current_indent.len
 9426            });
 9427
 9428        let mut edits = Vec::new();
 9429        let mut prev_edited_row = 0;
 9430        let mut row_delta = 0;
 9431        for selection in &mut selections {
 9432            if selection.start.row != prev_edited_row {
 9433                row_delta = 0;
 9434            }
 9435            prev_edited_row = selection.end.row;
 9436
 9437            // If the selection is non-empty, then increase the indentation of the selected lines.
 9438            if !selection.is_empty() {
 9439                row_delta =
 9440                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9441                continue;
 9442            }
 9443
 9444            let cursor = selection.head();
 9445            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9446            if let Some(suggested_indent) =
 9447                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9448            {
 9449                // Don't do anything if already at suggested indent
 9450                // and there is any other cursor which is not
 9451                if has_some_cursor_in_whitespace
 9452                    && cursor.column == current_indent.len
 9453                    && current_indent.len == suggested_indent.len
 9454                {
 9455                    continue;
 9456                }
 9457
 9458                // Adjust line and move cursor to suggested indent
 9459                // if cursor is not at suggested indent
 9460                if cursor.column < suggested_indent.len
 9461                    && cursor.column <= current_indent.len
 9462                    && current_indent.len <= suggested_indent.len
 9463                {
 9464                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9465                    selection.end = selection.start;
 9466                    if row_delta == 0 {
 9467                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9468                            cursor.row,
 9469                            current_indent,
 9470                            suggested_indent,
 9471                        ));
 9472                        row_delta = suggested_indent.len - current_indent.len;
 9473                    }
 9474                    continue;
 9475                }
 9476
 9477                // If current indent is more than suggested indent
 9478                // only move cursor to current indent and skip indent
 9479                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9480                    selection.start = Point::new(cursor.row, current_indent.len);
 9481                    selection.end = selection.start;
 9482                    continue;
 9483                }
 9484            }
 9485
 9486            // Otherwise, insert a hard or soft tab.
 9487            let settings = buffer.language_settings_at(cursor, cx);
 9488            let tab_size = if settings.hard_tabs {
 9489                IndentSize::tab()
 9490            } else {
 9491                let tab_size = settings.tab_size.get();
 9492                let indent_remainder = snapshot
 9493                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9494                    .flat_map(str::chars)
 9495                    .fold(row_delta % tab_size, |counter: u32, c| {
 9496                        if c == '\t' {
 9497                            0
 9498                        } else {
 9499                            (counter + 1) % tab_size
 9500                        }
 9501                    });
 9502
 9503                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9504                IndentSize::spaces(chars_to_next_tab_stop)
 9505            };
 9506            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9507            selection.end = selection.start;
 9508            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9509            row_delta += tab_size.len;
 9510        }
 9511
 9512        self.transact(window, cx, |this, window, cx| {
 9513            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9514            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9515                s.select(selections)
 9516            });
 9517            this.refresh_inline_completion(true, false, window, cx);
 9518        });
 9519    }
 9520
 9521    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9522        if self.read_only(cx) {
 9523            return;
 9524        }
 9525        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9526        let mut selections = self.selections.all::<Point>(cx);
 9527        let mut prev_edited_row = 0;
 9528        let mut row_delta = 0;
 9529        let mut edits = Vec::new();
 9530        let buffer = self.buffer.read(cx);
 9531        let snapshot = buffer.snapshot(cx);
 9532        for selection in &mut selections {
 9533            if selection.start.row != prev_edited_row {
 9534                row_delta = 0;
 9535            }
 9536            prev_edited_row = selection.end.row;
 9537
 9538            row_delta =
 9539                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9540        }
 9541
 9542        self.transact(window, cx, |this, window, cx| {
 9543            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9544            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9545                s.select(selections)
 9546            });
 9547        });
 9548    }
 9549
 9550    fn indent_selection(
 9551        buffer: &MultiBuffer,
 9552        snapshot: &MultiBufferSnapshot,
 9553        selection: &mut Selection<Point>,
 9554        edits: &mut Vec<(Range<Point>, String)>,
 9555        delta_for_start_row: u32,
 9556        cx: &App,
 9557    ) -> u32 {
 9558        let settings = buffer.language_settings_at(selection.start, cx);
 9559        let tab_size = settings.tab_size.get();
 9560        let indent_kind = if settings.hard_tabs {
 9561            IndentKind::Tab
 9562        } else {
 9563            IndentKind::Space
 9564        };
 9565        let mut start_row = selection.start.row;
 9566        let mut end_row = selection.end.row + 1;
 9567
 9568        // If a selection ends at the beginning of a line, don't indent
 9569        // that last line.
 9570        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9571            end_row -= 1;
 9572        }
 9573
 9574        // Avoid re-indenting a row that has already been indented by a
 9575        // previous selection, but still update this selection's column
 9576        // to reflect that indentation.
 9577        if delta_for_start_row > 0 {
 9578            start_row += 1;
 9579            selection.start.column += delta_for_start_row;
 9580            if selection.end.row == selection.start.row {
 9581                selection.end.column += delta_for_start_row;
 9582            }
 9583        }
 9584
 9585        let mut delta_for_end_row = 0;
 9586        let has_multiple_rows = start_row + 1 != end_row;
 9587        for row in start_row..end_row {
 9588            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9589            let indent_delta = match (current_indent.kind, indent_kind) {
 9590                (IndentKind::Space, IndentKind::Space) => {
 9591                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9592                    IndentSize::spaces(columns_to_next_tab_stop)
 9593                }
 9594                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9595                (_, IndentKind::Tab) => IndentSize::tab(),
 9596            };
 9597
 9598            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9599                0
 9600            } else {
 9601                selection.start.column
 9602            };
 9603            let row_start = Point::new(row, start);
 9604            edits.push((
 9605                row_start..row_start,
 9606                indent_delta.chars().collect::<String>(),
 9607            ));
 9608
 9609            // Update this selection's endpoints to reflect the indentation.
 9610            if row == selection.start.row {
 9611                selection.start.column += indent_delta.len;
 9612            }
 9613            if row == selection.end.row {
 9614                selection.end.column += indent_delta.len;
 9615                delta_for_end_row = indent_delta.len;
 9616            }
 9617        }
 9618
 9619        if selection.start.row == selection.end.row {
 9620            delta_for_start_row + delta_for_end_row
 9621        } else {
 9622            delta_for_end_row
 9623        }
 9624    }
 9625
 9626    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9627        if self.read_only(cx) {
 9628            return;
 9629        }
 9630        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9631        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9632        let selections = self.selections.all::<Point>(cx);
 9633        let mut deletion_ranges = Vec::new();
 9634        let mut last_outdent = None;
 9635        {
 9636            let buffer = self.buffer.read(cx);
 9637            let snapshot = buffer.snapshot(cx);
 9638            for selection in &selections {
 9639                let settings = buffer.language_settings_at(selection.start, cx);
 9640                let tab_size = settings.tab_size.get();
 9641                let mut rows = selection.spanned_rows(false, &display_map);
 9642
 9643                // Avoid re-outdenting a row that has already been outdented by a
 9644                // previous selection.
 9645                if let Some(last_row) = last_outdent {
 9646                    if last_row == rows.start {
 9647                        rows.start = rows.start.next_row();
 9648                    }
 9649                }
 9650                let has_multiple_rows = rows.len() > 1;
 9651                for row in rows.iter_rows() {
 9652                    let indent_size = snapshot.indent_size_for_line(row);
 9653                    if indent_size.len > 0 {
 9654                        let deletion_len = match indent_size.kind {
 9655                            IndentKind::Space => {
 9656                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9657                                if columns_to_prev_tab_stop == 0 {
 9658                                    tab_size
 9659                                } else {
 9660                                    columns_to_prev_tab_stop
 9661                                }
 9662                            }
 9663                            IndentKind::Tab => 1,
 9664                        };
 9665                        let start = if has_multiple_rows
 9666                            || deletion_len > selection.start.column
 9667                            || indent_size.len < selection.start.column
 9668                        {
 9669                            0
 9670                        } else {
 9671                            selection.start.column - deletion_len
 9672                        };
 9673                        deletion_ranges.push(
 9674                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9675                        );
 9676                        last_outdent = Some(row);
 9677                    }
 9678                }
 9679            }
 9680        }
 9681
 9682        self.transact(window, cx, |this, window, cx| {
 9683            this.buffer.update(cx, |buffer, cx| {
 9684                let empty_str: Arc<str> = Arc::default();
 9685                buffer.edit(
 9686                    deletion_ranges
 9687                        .into_iter()
 9688                        .map(|range| (range, empty_str.clone())),
 9689                    None,
 9690                    cx,
 9691                );
 9692            });
 9693            let selections = this.selections.all::<usize>(cx);
 9694            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9695                s.select(selections)
 9696            });
 9697        });
 9698    }
 9699
 9700    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9701        if self.read_only(cx) {
 9702            return;
 9703        }
 9704        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9705        let selections = self
 9706            .selections
 9707            .all::<usize>(cx)
 9708            .into_iter()
 9709            .map(|s| s.range());
 9710
 9711        self.transact(window, cx, |this, window, cx| {
 9712            this.buffer.update(cx, |buffer, cx| {
 9713                buffer.autoindent_ranges(selections, cx);
 9714            });
 9715            let selections = this.selections.all::<usize>(cx);
 9716            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9717                s.select(selections)
 9718            });
 9719        });
 9720    }
 9721
 9722    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9723        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9724        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9725        let selections = self.selections.all::<Point>(cx);
 9726
 9727        let mut new_cursors = Vec::new();
 9728        let mut edit_ranges = Vec::new();
 9729        let mut selections = selections.iter().peekable();
 9730        while let Some(selection) = selections.next() {
 9731            let mut rows = selection.spanned_rows(false, &display_map);
 9732            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9733
 9734            // Accumulate contiguous regions of rows that we want to delete.
 9735            while let Some(next_selection) = selections.peek() {
 9736                let next_rows = next_selection.spanned_rows(false, &display_map);
 9737                if next_rows.start <= rows.end {
 9738                    rows.end = next_rows.end;
 9739                    selections.next().unwrap();
 9740                } else {
 9741                    break;
 9742                }
 9743            }
 9744
 9745            let buffer = &display_map.buffer_snapshot;
 9746            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9747            let edit_end;
 9748            let cursor_buffer_row;
 9749            if buffer.max_point().row >= rows.end.0 {
 9750                // If there's a line after the range, delete the \n from the end of the row range
 9751                // and position the cursor on the next line.
 9752                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9753                cursor_buffer_row = rows.end;
 9754            } else {
 9755                // If there isn't a line after the range, delete the \n from the line before the
 9756                // start of the row range and position the cursor there.
 9757                edit_start = edit_start.saturating_sub(1);
 9758                edit_end = buffer.len();
 9759                cursor_buffer_row = rows.start.previous_row();
 9760            }
 9761
 9762            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9763            *cursor.column_mut() =
 9764                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9765
 9766            new_cursors.push((
 9767                selection.id,
 9768                buffer.anchor_after(cursor.to_point(&display_map)),
 9769            ));
 9770            edit_ranges.push(edit_start..edit_end);
 9771        }
 9772
 9773        self.transact(window, cx, |this, window, cx| {
 9774            let buffer = this.buffer.update(cx, |buffer, cx| {
 9775                let empty_str: Arc<str> = Arc::default();
 9776                buffer.edit(
 9777                    edit_ranges
 9778                        .into_iter()
 9779                        .map(|range| (range, empty_str.clone())),
 9780                    None,
 9781                    cx,
 9782                );
 9783                buffer.snapshot(cx)
 9784            });
 9785            let new_selections = new_cursors
 9786                .into_iter()
 9787                .map(|(id, cursor)| {
 9788                    let cursor = cursor.to_point(&buffer);
 9789                    Selection {
 9790                        id,
 9791                        start: cursor,
 9792                        end: cursor,
 9793                        reversed: false,
 9794                        goal: SelectionGoal::None,
 9795                    }
 9796                })
 9797                .collect();
 9798
 9799            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9800                s.select(new_selections);
 9801            });
 9802        });
 9803    }
 9804
 9805    pub fn join_lines_impl(
 9806        &mut self,
 9807        insert_whitespace: bool,
 9808        window: &mut Window,
 9809        cx: &mut Context<Self>,
 9810    ) {
 9811        if self.read_only(cx) {
 9812            return;
 9813        }
 9814        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9815        for selection in self.selections.all::<Point>(cx) {
 9816            let start = MultiBufferRow(selection.start.row);
 9817            // Treat single line selections as if they include the next line. Otherwise this action
 9818            // would do nothing for single line selections individual cursors.
 9819            let end = if selection.start.row == selection.end.row {
 9820                MultiBufferRow(selection.start.row + 1)
 9821            } else {
 9822                MultiBufferRow(selection.end.row)
 9823            };
 9824
 9825            if let Some(last_row_range) = row_ranges.last_mut() {
 9826                if start <= last_row_range.end {
 9827                    last_row_range.end = end;
 9828                    continue;
 9829                }
 9830            }
 9831            row_ranges.push(start..end);
 9832        }
 9833
 9834        let snapshot = self.buffer.read(cx).snapshot(cx);
 9835        let mut cursor_positions = Vec::new();
 9836        for row_range in &row_ranges {
 9837            let anchor = snapshot.anchor_before(Point::new(
 9838                row_range.end.previous_row().0,
 9839                snapshot.line_len(row_range.end.previous_row()),
 9840            ));
 9841            cursor_positions.push(anchor..anchor);
 9842        }
 9843
 9844        self.transact(window, cx, |this, window, cx| {
 9845            for row_range in row_ranges.into_iter().rev() {
 9846                for row in row_range.iter_rows().rev() {
 9847                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9848                    let next_line_row = row.next_row();
 9849                    let indent = snapshot.indent_size_for_line(next_line_row);
 9850                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9851
 9852                    let replace =
 9853                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9854                            " "
 9855                        } else {
 9856                            ""
 9857                        };
 9858
 9859                    this.buffer.update(cx, |buffer, cx| {
 9860                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9861                    });
 9862                }
 9863            }
 9864
 9865            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9866                s.select_anchor_ranges(cursor_positions)
 9867            });
 9868        });
 9869    }
 9870
 9871    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9872        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9873        self.join_lines_impl(true, window, cx);
 9874    }
 9875
 9876    pub fn sort_lines_case_sensitive(
 9877        &mut self,
 9878        _: &SortLinesCaseSensitive,
 9879        window: &mut Window,
 9880        cx: &mut Context<Self>,
 9881    ) {
 9882        self.manipulate_lines(window, cx, |lines| lines.sort())
 9883    }
 9884
 9885    pub fn sort_lines_case_insensitive(
 9886        &mut self,
 9887        _: &SortLinesCaseInsensitive,
 9888        window: &mut Window,
 9889        cx: &mut Context<Self>,
 9890    ) {
 9891        self.manipulate_lines(window, cx, |lines| {
 9892            lines.sort_by_key(|line| line.to_lowercase())
 9893        })
 9894    }
 9895
 9896    pub fn unique_lines_case_insensitive(
 9897        &mut self,
 9898        _: &UniqueLinesCaseInsensitive,
 9899        window: &mut Window,
 9900        cx: &mut Context<Self>,
 9901    ) {
 9902        self.manipulate_lines(window, cx, |lines| {
 9903            let mut seen = HashSet::default();
 9904            lines.retain(|line| seen.insert(line.to_lowercase()));
 9905        })
 9906    }
 9907
 9908    pub fn unique_lines_case_sensitive(
 9909        &mut self,
 9910        _: &UniqueLinesCaseSensitive,
 9911        window: &mut Window,
 9912        cx: &mut Context<Self>,
 9913    ) {
 9914        self.manipulate_lines(window, cx, |lines| {
 9915            let mut seen = HashSet::default();
 9916            lines.retain(|line| seen.insert(*line));
 9917        })
 9918    }
 9919
 9920    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9921        let Some(project) = self.project.clone() else {
 9922            return;
 9923        };
 9924        self.reload(project, window, cx)
 9925            .detach_and_notify_err(window, cx);
 9926    }
 9927
 9928    pub fn restore_file(
 9929        &mut self,
 9930        _: &::git::RestoreFile,
 9931        window: &mut Window,
 9932        cx: &mut Context<Self>,
 9933    ) {
 9934        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9935        let mut buffer_ids = HashSet::default();
 9936        let snapshot = self.buffer().read(cx).snapshot(cx);
 9937        for selection in self.selections.all::<usize>(cx) {
 9938            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9939        }
 9940
 9941        let buffer = self.buffer().read(cx);
 9942        let ranges = buffer_ids
 9943            .into_iter()
 9944            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9945            .collect::<Vec<_>>();
 9946
 9947        self.restore_hunks_in_ranges(ranges, window, cx);
 9948    }
 9949
 9950    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9951        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9952        let selections = self
 9953            .selections
 9954            .all(cx)
 9955            .into_iter()
 9956            .map(|s| s.range())
 9957            .collect();
 9958        self.restore_hunks_in_ranges(selections, window, cx);
 9959    }
 9960
 9961    pub fn restore_hunks_in_ranges(
 9962        &mut self,
 9963        ranges: Vec<Range<Point>>,
 9964        window: &mut Window,
 9965        cx: &mut Context<Editor>,
 9966    ) {
 9967        let mut revert_changes = HashMap::default();
 9968        let chunk_by = self
 9969            .snapshot(window, cx)
 9970            .hunks_for_ranges(ranges)
 9971            .into_iter()
 9972            .chunk_by(|hunk| hunk.buffer_id);
 9973        for (buffer_id, hunks) in &chunk_by {
 9974            let hunks = hunks.collect::<Vec<_>>();
 9975            for hunk in &hunks {
 9976                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9977            }
 9978            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9979        }
 9980        drop(chunk_by);
 9981        if !revert_changes.is_empty() {
 9982            self.transact(window, cx, |editor, window, cx| {
 9983                editor.restore(revert_changes, window, cx);
 9984            });
 9985        }
 9986    }
 9987
 9988    pub fn open_active_item_in_terminal(
 9989        &mut self,
 9990        _: &OpenInTerminal,
 9991        window: &mut Window,
 9992        cx: &mut Context<Self>,
 9993    ) {
 9994        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9995            let project_path = buffer.read(cx).project_path(cx)?;
 9996            let project = self.project.as_ref()?.read(cx);
 9997            let entry = project.entry_for_path(&project_path, cx)?;
 9998            let parent = match &entry.canonical_path {
 9999                Some(canonical_path) => canonical_path.to_path_buf(),
10000                None => project.absolute_path(&project_path, cx)?,
10001            }
10002            .parent()?
10003            .to_path_buf();
10004            Some(parent)
10005        }) {
10006            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10007        }
10008    }
10009
10010    fn set_breakpoint_context_menu(
10011        &mut self,
10012        display_row: DisplayRow,
10013        position: Option<Anchor>,
10014        clicked_point: gpui::Point<Pixels>,
10015        window: &mut Window,
10016        cx: &mut Context<Self>,
10017    ) {
10018        if !cx.has_flag::<DebuggerFeatureFlag>() {
10019            return;
10020        }
10021        let source = self
10022            .buffer
10023            .read(cx)
10024            .snapshot(cx)
10025            .anchor_before(Point::new(display_row.0, 0u32));
10026
10027        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10028
10029        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10030            self,
10031            source,
10032            clicked_point,
10033            context_menu,
10034            window,
10035            cx,
10036        );
10037    }
10038
10039    fn add_edit_breakpoint_block(
10040        &mut self,
10041        anchor: Anchor,
10042        breakpoint: &Breakpoint,
10043        edit_action: BreakpointPromptEditAction,
10044        window: &mut Window,
10045        cx: &mut Context<Self>,
10046    ) {
10047        let weak_editor = cx.weak_entity();
10048        let bp_prompt = cx.new(|cx| {
10049            BreakpointPromptEditor::new(
10050                weak_editor,
10051                anchor,
10052                breakpoint.clone(),
10053                edit_action,
10054                window,
10055                cx,
10056            )
10057        });
10058
10059        let height = bp_prompt.update(cx, |this, cx| {
10060            this.prompt
10061                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10062        });
10063        let cloned_prompt = bp_prompt.clone();
10064        let blocks = vec![BlockProperties {
10065            style: BlockStyle::Sticky,
10066            placement: BlockPlacement::Above(anchor),
10067            height: Some(height),
10068            render: Arc::new(move |cx| {
10069                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10070                cloned_prompt.clone().into_any_element()
10071            }),
10072            priority: 0,
10073            render_in_minimap: true,
10074        }];
10075
10076        let focus_handle = bp_prompt.focus_handle(cx);
10077        window.focus(&focus_handle);
10078
10079        let block_ids = self.insert_blocks(blocks, None, cx);
10080        bp_prompt.update(cx, |prompt, _| {
10081            prompt.add_block_ids(block_ids);
10082        });
10083    }
10084
10085    pub(crate) fn breakpoint_at_row(
10086        &self,
10087        row: u32,
10088        window: &mut Window,
10089        cx: &mut Context<Self>,
10090    ) -> Option<(Anchor, Breakpoint)> {
10091        let snapshot = self.snapshot(window, cx);
10092        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10093
10094        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10095    }
10096
10097    pub(crate) fn breakpoint_at_anchor(
10098        &self,
10099        breakpoint_position: Anchor,
10100        snapshot: &EditorSnapshot,
10101        cx: &mut Context<Self>,
10102    ) -> Option<(Anchor, Breakpoint)> {
10103        let project = self.project.clone()?;
10104
10105        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10106            snapshot
10107                .buffer_snapshot
10108                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10109        })?;
10110
10111        let enclosing_excerpt = breakpoint_position.excerpt_id;
10112        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10113        let buffer_snapshot = buffer.read(cx).snapshot();
10114
10115        let row = buffer_snapshot
10116            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10117            .row;
10118
10119        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10120        let anchor_end = snapshot
10121            .buffer_snapshot
10122            .anchor_after(Point::new(row, line_len));
10123
10124        let bp = self
10125            .breakpoint_store
10126            .as_ref()?
10127            .read_with(cx, |breakpoint_store, cx| {
10128                breakpoint_store
10129                    .breakpoints(
10130                        &buffer,
10131                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10132                        &buffer_snapshot,
10133                        cx,
10134                    )
10135                    .next()
10136                    .and_then(|(bp, _)| {
10137                        let breakpoint_row = buffer_snapshot
10138                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10139                            .row;
10140
10141                        if breakpoint_row == row {
10142                            snapshot
10143                                .buffer_snapshot
10144                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10145                                .map(|position| (position, bp.bp.clone()))
10146                        } else {
10147                            None
10148                        }
10149                    })
10150            });
10151        bp
10152    }
10153
10154    pub fn edit_log_breakpoint(
10155        &mut self,
10156        _: &EditLogBreakpoint,
10157        window: &mut Window,
10158        cx: &mut Context<Self>,
10159    ) {
10160        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10161            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10162                message: None,
10163                state: BreakpointState::Enabled,
10164                condition: None,
10165                hit_condition: None,
10166            });
10167
10168            self.add_edit_breakpoint_block(
10169                anchor,
10170                &breakpoint,
10171                BreakpointPromptEditAction::Log,
10172                window,
10173                cx,
10174            );
10175        }
10176    }
10177
10178    fn breakpoints_at_cursors(
10179        &self,
10180        window: &mut Window,
10181        cx: &mut Context<Self>,
10182    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10183        let snapshot = self.snapshot(window, cx);
10184        let cursors = self
10185            .selections
10186            .disjoint_anchors()
10187            .into_iter()
10188            .map(|selection| {
10189                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10190
10191                let breakpoint_position = self
10192                    .breakpoint_at_row(cursor_position.row, window, cx)
10193                    .map(|bp| bp.0)
10194                    .unwrap_or_else(|| {
10195                        snapshot
10196                            .display_snapshot
10197                            .buffer_snapshot
10198                            .anchor_after(Point::new(cursor_position.row, 0))
10199                    });
10200
10201                let breakpoint = self
10202                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10203                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10204
10205                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10206            })
10207            // 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.
10208            .collect::<HashMap<Anchor, _>>();
10209
10210        cursors.into_iter().collect()
10211    }
10212
10213    pub fn enable_breakpoint(
10214        &mut self,
10215        _: &crate::actions::EnableBreakpoint,
10216        window: &mut Window,
10217        cx: &mut Context<Self>,
10218    ) {
10219        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10220            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10221                continue;
10222            };
10223            self.edit_breakpoint_at_anchor(
10224                anchor,
10225                breakpoint,
10226                BreakpointEditAction::InvertState,
10227                cx,
10228            );
10229        }
10230    }
10231
10232    pub fn disable_breakpoint(
10233        &mut self,
10234        _: &crate::actions::DisableBreakpoint,
10235        window: &mut Window,
10236        cx: &mut Context<Self>,
10237    ) {
10238        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10239            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10240                continue;
10241            };
10242            self.edit_breakpoint_at_anchor(
10243                anchor,
10244                breakpoint,
10245                BreakpointEditAction::InvertState,
10246                cx,
10247            );
10248        }
10249    }
10250
10251    pub fn toggle_breakpoint(
10252        &mut self,
10253        _: &crate::actions::ToggleBreakpoint,
10254        window: &mut Window,
10255        cx: &mut Context<Self>,
10256    ) {
10257        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10258            if let Some(breakpoint) = breakpoint {
10259                self.edit_breakpoint_at_anchor(
10260                    anchor,
10261                    breakpoint,
10262                    BreakpointEditAction::Toggle,
10263                    cx,
10264                );
10265            } else {
10266                self.edit_breakpoint_at_anchor(
10267                    anchor,
10268                    Breakpoint::new_standard(),
10269                    BreakpointEditAction::Toggle,
10270                    cx,
10271                );
10272            }
10273        }
10274    }
10275
10276    pub fn edit_breakpoint_at_anchor(
10277        &mut self,
10278        breakpoint_position: Anchor,
10279        breakpoint: Breakpoint,
10280        edit_action: BreakpointEditAction,
10281        cx: &mut Context<Self>,
10282    ) {
10283        let Some(breakpoint_store) = &self.breakpoint_store else {
10284            return;
10285        };
10286
10287        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10288            if breakpoint_position == Anchor::min() {
10289                self.buffer()
10290                    .read(cx)
10291                    .excerpt_buffer_ids()
10292                    .into_iter()
10293                    .next()
10294            } else {
10295                None
10296            }
10297        }) else {
10298            return;
10299        };
10300
10301        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10302            return;
10303        };
10304
10305        breakpoint_store.update(cx, |breakpoint_store, cx| {
10306            breakpoint_store.toggle_breakpoint(
10307                buffer,
10308                BreakpointWithPosition {
10309                    position: breakpoint_position.text_anchor,
10310                    bp: breakpoint,
10311                },
10312                edit_action,
10313                cx,
10314            );
10315        });
10316
10317        cx.notify();
10318    }
10319
10320    #[cfg(any(test, feature = "test-support"))]
10321    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10322        self.breakpoint_store.clone()
10323    }
10324
10325    pub fn prepare_restore_change(
10326        &self,
10327        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10328        hunk: &MultiBufferDiffHunk,
10329        cx: &mut App,
10330    ) -> Option<()> {
10331        if hunk.is_created_file() {
10332            return None;
10333        }
10334        let buffer = self.buffer.read(cx);
10335        let diff = buffer.diff_for(hunk.buffer_id)?;
10336        let buffer = buffer.buffer(hunk.buffer_id)?;
10337        let buffer = buffer.read(cx);
10338        let original_text = diff
10339            .read(cx)
10340            .base_text()
10341            .as_rope()
10342            .slice(hunk.diff_base_byte_range.clone());
10343        let buffer_snapshot = buffer.snapshot();
10344        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10345        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10346            probe
10347                .0
10348                .start
10349                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10350                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10351        }) {
10352            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10353            Some(())
10354        } else {
10355            None
10356        }
10357    }
10358
10359    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10360        self.manipulate_lines(window, cx, |lines| lines.reverse())
10361    }
10362
10363    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10364        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10365    }
10366
10367    fn manipulate_lines<Fn>(
10368        &mut self,
10369        window: &mut Window,
10370        cx: &mut Context<Self>,
10371        mut callback: Fn,
10372    ) where
10373        Fn: FnMut(&mut Vec<&str>),
10374    {
10375        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10376
10377        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10378        let buffer = self.buffer.read(cx).snapshot(cx);
10379
10380        let mut edits = Vec::new();
10381
10382        let selections = self.selections.all::<Point>(cx);
10383        let mut selections = selections.iter().peekable();
10384        let mut contiguous_row_selections = Vec::new();
10385        let mut new_selections = Vec::new();
10386        let mut added_lines = 0;
10387        let mut removed_lines = 0;
10388
10389        while let Some(selection) = selections.next() {
10390            let (start_row, end_row) = consume_contiguous_rows(
10391                &mut contiguous_row_selections,
10392                selection,
10393                &display_map,
10394                &mut selections,
10395            );
10396
10397            let start_point = Point::new(start_row.0, 0);
10398            let end_point = Point::new(
10399                end_row.previous_row().0,
10400                buffer.line_len(end_row.previous_row()),
10401            );
10402            let text = buffer
10403                .text_for_range(start_point..end_point)
10404                .collect::<String>();
10405
10406            let mut lines = text.split('\n').collect_vec();
10407
10408            let lines_before = lines.len();
10409            callback(&mut lines);
10410            let lines_after = lines.len();
10411
10412            edits.push((start_point..end_point, lines.join("\n")));
10413
10414            // Selections must change based on added and removed line count
10415            let start_row =
10416                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10417            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10418            new_selections.push(Selection {
10419                id: selection.id,
10420                start: start_row,
10421                end: end_row,
10422                goal: SelectionGoal::None,
10423                reversed: selection.reversed,
10424            });
10425
10426            if lines_after > lines_before {
10427                added_lines += lines_after - lines_before;
10428            } else if lines_before > lines_after {
10429                removed_lines += lines_before - lines_after;
10430            }
10431        }
10432
10433        self.transact(window, cx, |this, window, cx| {
10434            let buffer = this.buffer.update(cx, |buffer, cx| {
10435                buffer.edit(edits, None, cx);
10436                buffer.snapshot(cx)
10437            });
10438
10439            // Recalculate offsets on newly edited buffer
10440            let new_selections = new_selections
10441                .iter()
10442                .map(|s| {
10443                    let start_point = Point::new(s.start.0, 0);
10444                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10445                    Selection {
10446                        id: s.id,
10447                        start: buffer.point_to_offset(start_point),
10448                        end: buffer.point_to_offset(end_point),
10449                        goal: s.goal,
10450                        reversed: s.reversed,
10451                    }
10452                })
10453                .collect();
10454
10455            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10456                s.select(new_selections);
10457            });
10458
10459            this.request_autoscroll(Autoscroll::fit(), cx);
10460        });
10461    }
10462
10463    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10464        self.manipulate_text(window, cx, |text| {
10465            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10466            if has_upper_case_characters {
10467                text.to_lowercase()
10468            } else {
10469                text.to_uppercase()
10470            }
10471        })
10472    }
10473
10474    pub fn convert_to_upper_case(
10475        &mut self,
10476        _: &ConvertToUpperCase,
10477        window: &mut Window,
10478        cx: &mut Context<Self>,
10479    ) {
10480        self.manipulate_text(window, cx, |text| text.to_uppercase())
10481    }
10482
10483    pub fn convert_to_lower_case(
10484        &mut self,
10485        _: &ConvertToLowerCase,
10486        window: &mut Window,
10487        cx: &mut Context<Self>,
10488    ) {
10489        self.manipulate_text(window, cx, |text| text.to_lowercase())
10490    }
10491
10492    pub fn convert_to_title_case(
10493        &mut self,
10494        _: &ConvertToTitleCase,
10495        window: &mut Window,
10496        cx: &mut Context<Self>,
10497    ) {
10498        self.manipulate_text(window, cx, |text| {
10499            text.split('\n')
10500                .map(|line| line.to_case(Case::Title))
10501                .join("\n")
10502        })
10503    }
10504
10505    pub fn convert_to_snake_case(
10506        &mut self,
10507        _: &ConvertToSnakeCase,
10508        window: &mut Window,
10509        cx: &mut Context<Self>,
10510    ) {
10511        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10512    }
10513
10514    pub fn convert_to_kebab_case(
10515        &mut self,
10516        _: &ConvertToKebabCase,
10517        window: &mut Window,
10518        cx: &mut Context<Self>,
10519    ) {
10520        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10521    }
10522
10523    pub fn convert_to_upper_camel_case(
10524        &mut self,
10525        _: &ConvertToUpperCamelCase,
10526        window: &mut Window,
10527        cx: &mut Context<Self>,
10528    ) {
10529        self.manipulate_text(window, cx, |text| {
10530            text.split('\n')
10531                .map(|line| line.to_case(Case::UpperCamel))
10532                .join("\n")
10533        })
10534    }
10535
10536    pub fn convert_to_lower_camel_case(
10537        &mut self,
10538        _: &ConvertToLowerCamelCase,
10539        window: &mut Window,
10540        cx: &mut Context<Self>,
10541    ) {
10542        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10543    }
10544
10545    pub fn convert_to_opposite_case(
10546        &mut self,
10547        _: &ConvertToOppositeCase,
10548        window: &mut Window,
10549        cx: &mut Context<Self>,
10550    ) {
10551        self.manipulate_text(window, cx, |text| {
10552            text.chars()
10553                .fold(String::with_capacity(text.len()), |mut t, c| {
10554                    if c.is_uppercase() {
10555                        t.extend(c.to_lowercase());
10556                    } else {
10557                        t.extend(c.to_uppercase());
10558                    }
10559                    t
10560                })
10561        })
10562    }
10563
10564    pub fn convert_to_rot13(
10565        &mut self,
10566        _: &ConvertToRot13,
10567        window: &mut Window,
10568        cx: &mut Context<Self>,
10569    ) {
10570        self.manipulate_text(window, cx, |text| {
10571            text.chars()
10572                .map(|c| match c {
10573                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10574                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10575                    _ => c,
10576                })
10577                .collect()
10578        })
10579    }
10580
10581    pub fn convert_to_rot47(
10582        &mut self,
10583        _: &ConvertToRot47,
10584        window: &mut Window,
10585        cx: &mut Context<Self>,
10586    ) {
10587        self.manipulate_text(window, cx, |text| {
10588            text.chars()
10589                .map(|c| {
10590                    let code_point = c as u32;
10591                    if code_point >= 33 && code_point <= 126 {
10592                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10593                    }
10594                    c
10595                })
10596                .collect()
10597        })
10598    }
10599
10600    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10601    where
10602        Fn: FnMut(&str) -> String,
10603    {
10604        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10605        let buffer = self.buffer.read(cx).snapshot(cx);
10606
10607        let mut new_selections = Vec::new();
10608        let mut edits = Vec::new();
10609        let mut selection_adjustment = 0i32;
10610
10611        for selection in self.selections.all::<usize>(cx) {
10612            let selection_is_empty = selection.is_empty();
10613
10614            let (start, end) = if selection_is_empty {
10615                let word_range = movement::surrounding_word(
10616                    &display_map,
10617                    selection.start.to_display_point(&display_map),
10618                );
10619                let start = word_range.start.to_offset(&display_map, Bias::Left);
10620                let end = word_range.end.to_offset(&display_map, Bias::Left);
10621                (start, end)
10622            } else {
10623                (selection.start, selection.end)
10624            };
10625
10626            let text = buffer.text_for_range(start..end).collect::<String>();
10627            let old_length = text.len() as i32;
10628            let text = callback(&text);
10629
10630            new_selections.push(Selection {
10631                start: (start as i32 - selection_adjustment) as usize,
10632                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10633                goal: SelectionGoal::None,
10634                ..selection
10635            });
10636
10637            selection_adjustment += old_length - text.len() as i32;
10638
10639            edits.push((start..end, text));
10640        }
10641
10642        self.transact(window, cx, |this, window, cx| {
10643            this.buffer.update(cx, |buffer, cx| {
10644                buffer.edit(edits, None, cx);
10645            });
10646
10647            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10648                s.select(new_selections);
10649            });
10650
10651            this.request_autoscroll(Autoscroll::fit(), cx);
10652        });
10653    }
10654
10655    pub fn move_selection_on_drop(
10656        &mut self,
10657        selection: &Selection<Anchor>,
10658        target: DisplayPoint,
10659        is_cut: bool,
10660        window: &mut Window,
10661        cx: &mut Context<Self>,
10662    ) {
10663        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10664        let buffer = &display_map.buffer_snapshot;
10665        let mut edits = Vec::new();
10666        let insert_point = display_map
10667            .clip_point(target, Bias::Left)
10668            .to_point(&display_map);
10669        let text = buffer
10670            .text_for_range(selection.start..selection.end)
10671            .collect::<String>();
10672        if is_cut {
10673            edits.push(((selection.start..selection.end), String::new()));
10674        }
10675        let insert_anchor = buffer.anchor_before(insert_point);
10676        edits.push(((insert_anchor..insert_anchor), text));
10677        let last_edit_start = insert_anchor.bias_left(buffer);
10678        let last_edit_end = insert_anchor.bias_right(buffer);
10679        self.transact(window, cx, |this, window, cx| {
10680            this.buffer.update(cx, |buffer, cx| {
10681                buffer.edit(edits, None, cx);
10682            });
10683            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10684                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10685            });
10686        });
10687    }
10688
10689    pub fn clear_selection_drag_state(&mut self) {
10690        self.selection_drag_state = SelectionDragState::None;
10691    }
10692
10693    pub fn duplicate(
10694        &mut self,
10695        upwards: bool,
10696        whole_lines: bool,
10697        window: &mut Window,
10698        cx: &mut Context<Self>,
10699    ) {
10700        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10701
10702        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10703        let buffer = &display_map.buffer_snapshot;
10704        let selections = self.selections.all::<Point>(cx);
10705
10706        let mut edits = Vec::new();
10707        let mut selections_iter = selections.iter().peekable();
10708        while let Some(selection) = selections_iter.next() {
10709            let mut rows = selection.spanned_rows(false, &display_map);
10710            // duplicate line-wise
10711            if whole_lines || selection.start == selection.end {
10712                // Avoid duplicating the same lines twice.
10713                while let Some(next_selection) = selections_iter.peek() {
10714                    let next_rows = next_selection.spanned_rows(false, &display_map);
10715                    if next_rows.start < rows.end {
10716                        rows.end = next_rows.end;
10717                        selections_iter.next().unwrap();
10718                    } else {
10719                        break;
10720                    }
10721                }
10722
10723                // Copy the text from the selected row region and splice it either at the start
10724                // or end of the region.
10725                let start = Point::new(rows.start.0, 0);
10726                let end = Point::new(
10727                    rows.end.previous_row().0,
10728                    buffer.line_len(rows.end.previous_row()),
10729                );
10730                let text = buffer
10731                    .text_for_range(start..end)
10732                    .chain(Some("\n"))
10733                    .collect::<String>();
10734                let insert_location = if upwards {
10735                    Point::new(rows.end.0, 0)
10736                } else {
10737                    start
10738                };
10739                edits.push((insert_location..insert_location, text));
10740            } else {
10741                // duplicate character-wise
10742                let start = selection.start;
10743                let end = selection.end;
10744                let text = buffer.text_for_range(start..end).collect::<String>();
10745                edits.push((selection.end..selection.end, text));
10746            }
10747        }
10748
10749        self.transact(window, cx, |this, _, cx| {
10750            this.buffer.update(cx, |buffer, cx| {
10751                buffer.edit(edits, None, cx);
10752            });
10753
10754            this.request_autoscroll(Autoscroll::fit(), cx);
10755        });
10756    }
10757
10758    pub fn duplicate_line_up(
10759        &mut self,
10760        _: &DuplicateLineUp,
10761        window: &mut Window,
10762        cx: &mut Context<Self>,
10763    ) {
10764        self.duplicate(true, true, window, cx);
10765    }
10766
10767    pub fn duplicate_line_down(
10768        &mut self,
10769        _: &DuplicateLineDown,
10770        window: &mut Window,
10771        cx: &mut Context<Self>,
10772    ) {
10773        self.duplicate(false, true, window, cx);
10774    }
10775
10776    pub fn duplicate_selection(
10777        &mut self,
10778        _: &DuplicateSelection,
10779        window: &mut Window,
10780        cx: &mut Context<Self>,
10781    ) {
10782        self.duplicate(false, false, window, cx);
10783    }
10784
10785    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10786        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10787
10788        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10789        let buffer = self.buffer.read(cx).snapshot(cx);
10790
10791        let mut edits = Vec::new();
10792        let mut unfold_ranges = Vec::new();
10793        let mut refold_creases = Vec::new();
10794
10795        let selections = self.selections.all::<Point>(cx);
10796        let mut selections = selections.iter().peekable();
10797        let mut contiguous_row_selections = Vec::new();
10798        let mut new_selections = Vec::new();
10799
10800        while let Some(selection) = selections.next() {
10801            // Find all the selections that span a contiguous row range
10802            let (start_row, end_row) = consume_contiguous_rows(
10803                &mut contiguous_row_selections,
10804                selection,
10805                &display_map,
10806                &mut selections,
10807            );
10808
10809            // Move the text spanned by the row range to be before the line preceding the row range
10810            if start_row.0 > 0 {
10811                let range_to_move = Point::new(
10812                    start_row.previous_row().0,
10813                    buffer.line_len(start_row.previous_row()),
10814                )
10815                    ..Point::new(
10816                        end_row.previous_row().0,
10817                        buffer.line_len(end_row.previous_row()),
10818                    );
10819                let insertion_point = display_map
10820                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10821                    .0;
10822
10823                // Don't move lines across excerpts
10824                if buffer
10825                    .excerpt_containing(insertion_point..range_to_move.end)
10826                    .is_some()
10827                {
10828                    let text = buffer
10829                        .text_for_range(range_to_move.clone())
10830                        .flat_map(|s| s.chars())
10831                        .skip(1)
10832                        .chain(['\n'])
10833                        .collect::<String>();
10834
10835                    edits.push((
10836                        buffer.anchor_after(range_to_move.start)
10837                            ..buffer.anchor_before(range_to_move.end),
10838                        String::new(),
10839                    ));
10840                    let insertion_anchor = buffer.anchor_after(insertion_point);
10841                    edits.push((insertion_anchor..insertion_anchor, text));
10842
10843                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10844
10845                    // Move selections up
10846                    new_selections.extend(contiguous_row_selections.drain(..).map(
10847                        |mut selection| {
10848                            selection.start.row -= row_delta;
10849                            selection.end.row -= row_delta;
10850                            selection
10851                        },
10852                    ));
10853
10854                    // Move folds up
10855                    unfold_ranges.push(range_to_move.clone());
10856                    for fold in display_map.folds_in_range(
10857                        buffer.anchor_before(range_to_move.start)
10858                            ..buffer.anchor_after(range_to_move.end),
10859                    ) {
10860                        let mut start = fold.range.start.to_point(&buffer);
10861                        let mut end = fold.range.end.to_point(&buffer);
10862                        start.row -= row_delta;
10863                        end.row -= row_delta;
10864                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10865                    }
10866                }
10867            }
10868
10869            // If we didn't move line(s), preserve the existing selections
10870            new_selections.append(&mut contiguous_row_selections);
10871        }
10872
10873        self.transact(window, cx, |this, window, cx| {
10874            this.unfold_ranges(&unfold_ranges, true, true, cx);
10875            this.buffer.update(cx, |buffer, cx| {
10876                for (range, text) in edits {
10877                    buffer.edit([(range, text)], None, cx);
10878                }
10879            });
10880            this.fold_creases(refold_creases, true, window, cx);
10881            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10882                s.select(new_selections);
10883            })
10884        });
10885    }
10886
10887    pub fn move_line_down(
10888        &mut self,
10889        _: &MoveLineDown,
10890        window: &mut Window,
10891        cx: &mut Context<Self>,
10892    ) {
10893        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10894
10895        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10896        let buffer = self.buffer.read(cx).snapshot(cx);
10897
10898        let mut edits = Vec::new();
10899        let mut unfold_ranges = Vec::new();
10900        let mut refold_creases = Vec::new();
10901
10902        let selections = self.selections.all::<Point>(cx);
10903        let mut selections = selections.iter().peekable();
10904        let mut contiguous_row_selections = Vec::new();
10905        let mut new_selections = Vec::new();
10906
10907        while let Some(selection) = selections.next() {
10908            // Find all the selections that span a contiguous row range
10909            let (start_row, end_row) = consume_contiguous_rows(
10910                &mut contiguous_row_selections,
10911                selection,
10912                &display_map,
10913                &mut selections,
10914            );
10915
10916            // Move the text spanned by the row range to be after the last line of the row range
10917            if end_row.0 <= buffer.max_point().row {
10918                let range_to_move =
10919                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10920                let insertion_point = display_map
10921                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10922                    .0;
10923
10924                // Don't move lines across excerpt boundaries
10925                if buffer
10926                    .excerpt_containing(range_to_move.start..insertion_point)
10927                    .is_some()
10928                {
10929                    let mut text = String::from("\n");
10930                    text.extend(buffer.text_for_range(range_to_move.clone()));
10931                    text.pop(); // Drop trailing newline
10932                    edits.push((
10933                        buffer.anchor_after(range_to_move.start)
10934                            ..buffer.anchor_before(range_to_move.end),
10935                        String::new(),
10936                    ));
10937                    let insertion_anchor = buffer.anchor_after(insertion_point);
10938                    edits.push((insertion_anchor..insertion_anchor, text));
10939
10940                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10941
10942                    // Move selections down
10943                    new_selections.extend(contiguous_row_selections.drain(..).map(
10944                        |mut selection| {
10945                            selection.start.row += row_delta;
10946                            selection.end.row += row_delta;
10947                            selection
10948                        },
10949                    ));
10950
10951                    // Move folds down
10952                    unfold_ranges.push(range_to_move.clone());
10953                    for fold in display_map.folds_in_range(
10954                        buffer.anchor_before(range_to_move.start)
10955                            ..buffer.anchor_after(range_to_move.end),
10956                    ) {
10957                        let mut start = fold.range.start.to_point(&buffer);
10958                        let mut end = fold.range.end.to_point(&buffer);
10959                        start.row += row_delta;
10960                        end.row += row_delta;
10961                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10962                    }
10963                }
10964            }
10965
10966            // If we didn't move line(s), preserve the existing selections
10967            new_selections.append(&mut contiguous_row_selections);
10968        }
10969
10970        self.transact(window, cx, |this, window, cx| {
10971            this.unfold_ranges(&unfold_ranges, true, true, cx);
10972            this.buffer.update(cx, |buffer, cx| {
10973                for (range, text) in edits {
10974                    buffer.edit([(range, text)], None, cx);
10975                }
10976            });
10977            this.fold_creases(refold_creases, true, window, cx);
10978            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10979                s.select(new_selections)
10980            });
10981        });
10982    }
10983
10984    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10985        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10986        let text_layout_details = &self.text_layout_details(window);
10987        self.transact(window, cx, |this, window, cx| {
10988            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10989                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10990                s.move_with(|display_map, selection| {
10991                    if !selection.is_empty() {
10992                        return;
10993                    }
10994
10995                    let mut head = selection.head();
10996                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10997                    if head.column() == display_map.line_len(head.row()) {
10998                        transpose_offset = display_map
10999                            .buffer_snapshot
11000                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11001                    }
11002
11003                    if transpose_offset == 0 {
11004                        return;
11005                    }
11006
11007                    *head.column_mut() += 1;
11008                    head = display_map.clip_point(head, Bias::Right);
11009                    let goal = SelectionGoal::HorizontalPosition(
11010                        display_map
11011                            .x_for_display_point(head, text_layout_details)
11012                            .into(),
11013                    );
11014                    selection.collapse_to(head, goal);
11015
11016                    let transpose_start = display_map
11017                        .buffer_snapshot
11018                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11019                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11020                        let transpose_end = display_map
11021                            .buffer_snapshot
11022                            .clip_offset(transpose_offset + 1, Bias::Right);
11023                        if let Some(ch) =
11024                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11025                        {
11026                            edits.push((transpose_start..transpose_offset, String::new()));
11027                            edits.push((transpose_end..transpose_end, ch.to_string()));
11028                        }
11029                    }
11030                });
11031                edits
11032            });
11033            this.buffer
11034                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11035            let selections = this.selections.all::<usize>(cx);
11036            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11037                s.select(selections);
11038            });
11039        });
11040    }
11041
11042    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11043        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11044        self.rewrap_impl(RewrapOptions::default(), cx)
11045    }
11046
11047    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11048        let buffer = self.buffer.read(cx).snapshot(cx);
11049        let selections = self.selections.all::<Point>(cx);
11050
11051        // Shrink and split selections to respect paragraph boundaries.
11052        let ranges = selections.into_iter().flat_map(|selection| {
11053            let language_settings = buffer.language_settings_at(selection.head(), cx);
11054            let language_scope = buffer.language_scope_at(selection.head());
11055
11056            let Some(start_row) = (selection.start.row..=selection.end.row)
11057                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11058            else {
11059                return vec![];
11060            };
11061            let Some(end_row) = (selection.start.row..=selection.end.row)
11062                .rev()
11063                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11064            else {
11065                return vec![];
11066            };
11067
11068            let mut row = start_row;
11069            let mut ranges = Vec::new();
11070            while let Some(blank_row) =
11071                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11072            {
11073                let next_paragraph_start = (blank_row + 1..=end_row)
11074                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11075                    .unwrap();
11076                ranges.push((
11077                    language_settings.clone(),
11078                    language_scope.clone(),
11079                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11080                ));
11081                row = next_paragraph_start;
11082            }
11083            ranges.push((
11084                language_settings.clone(),
11085                language_scope.clone(),
11086                Point::new(row, 0)..Point::new(end_row, 0),
11087            ));
11088
11089            ranges
11090        });
11091
11092        let mut edits = Vec::new();
11093        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11094
11095        for (language_settings, language_scope, range) in ranges {
11096            let mut start_row = range.start.row;
11097            let mut end_row = range.end.row;
11098
11099            // Skip selections that overlap with a range that has already been rewrapped.
11100            let selection_range = start_row..end_row;
11101            if rewrapped_row_ranges
11102                .iter()
11103                .any(|range| range.overlaps(&selection_range))
11104            {
11105                continue;
11106            }
11107
11108            let tab_size = language_settings.tab_size;
11109
11110            // Since not all lines in the selection may be at the same indent
11111            // level, choose the indent size that is the most common between all
11112            // of the lines.
11113            //
11114            // If there is a tie, we use the deepest indent.
11115            let (indent_size, indent_end) = {
11116                let mut indent_size_occurrences = HashMap::default();
11117                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11118
11119                for row in start_row..=end_row {
11120                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11121                    rows_by_indent_size.entry(indent).or_default().push(row);
11122                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11123                }
11124
11125                let indent_size = indent_size_occurrences
11126                    .into_iter()
11127                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11128                    .map(|(indent, _)| indent)
11129                    .unwrap_or_default();
11130                let row = rows_by_indent_size[&indent_size][0];
11131                let indent_end = Point::new(row, indent_size.len);
11132
11133                (indent_size, indent_end)
11134            };
11135
11136            let mut line_prefix = indent_size.chars().collect::<String>();
11137
11138            let mut inside_comment = false;
11139            if let Some(comment_prefix) = language_scope.and_then(|language| {
11140                language
11141                    .line_comment_prefixes()
11142                    .iter()
11143                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11144                    .cloned()
11145            }) {
11146                line_prefix.push_str(&comment_prefix);
11147                inside_comment = true;
11148            }
11149
11150            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11151                RewrapBehavior::InComments => inside_comment,
11152                RewrapBehavior::InSelections => !range.is_empty(),
11153                RewrapBehavior::Anywhere => true,
11154            };
11155
11156            let should_rewrap = options.override_language_settings
11157                || allow_rewrap_based_on_language
11158                || self.hard_wrap.is_some();
11159            if !should_rewrap {
11160                continue;
11161            }
11162
11163            if range.is_empty() {
11164                'expand_upwards: while start_row > 0 {
11165                    let prev_row = start_row - 1;
11166                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11167                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11168                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11169                    {
11170                        start_row = prev_row;
11171                    } else {
11172                        break 'expand_upwards;
11173                    }
11174                }
11175
11176                'expand_downwards: while end_row < buffer.max_point().row {
11177                    let next_row = end_row + 1;
11178                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11179                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11180                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11181                    {
11182                        end_row = next_row;
11183                    } else {
11184                        break 'expand_downwards;
11185                    }
11186                }
11187            }
11188
11189            let start = Point::new(start_row, 0);
11190            let start_offset = start.to_offset(&buffer);
11191            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11192            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11193            let Some(lines_without_prefixes) = selection_text
11194                .lines()
11195                .map(|line| {
11196                    line.strip_prefix(&line_prefix)
11197                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11198                        .with_context(|| {
11199                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11200                        })
11201                })
11202                .collect::<Result<Vec<_>, _>>()
11203                .log_err()
11204            else {
11205                continue;
11206            };
11207
11208            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11209                buffer
11210                    .language_settings_at(Point::new(start_row, 0), cx)
11211                    .preferred_line_length as usize
11212            });
11213            let wrapped_text = wrap_with_prefix(
11214                line_prefix,
11215                lines_without_prefixes.join("\n"),
11216                wrap_column,
11217                tab_size,
11218                options.preserve_existing_whitespace,
11219            );
11220
11221            // TODO: should always use char-based diff while still supporting cursor behavior that
11222            // matches vim.
11223            let mut diff_options = DiffOptions::default();
11224            if options.override_language_settings {
11225                diff_options.max_word_diff_len = 0;
11226                diff_options.max_word_diff_line_count = 0;
11227            } else {
11228                diff_options.max_word_diff_len = usize::MAX;
11229                diff_options.max_word_diff_line_count = usize::MAX;
11230            }
11231
11232            for (old_range, new_text) in
11233                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11234            {
11235                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11236                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11237                edits.push((edit_start..edit_end, new_text));
11238            }
11239
11240            rewrapped_row_ranges.push(start_row..=end_row);
11241        }
11242
11243        self.buffer
11244            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11245    }
11246
11247    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11248        let mut text = String::new();
11249        let buffer = self.buffer.read(cx).snapshot(cx);
11250        let mut selections = self.selections.all::<Point>(cx);
11251        let mut clipboard_selections = Vec::with_capacity(selections.len());
11252        {
11253            let max_point = buffer.max_point();
11254            let mut is_first = true;
11255            for selection in &mut selections {
11256                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11257                if is_entire_line {
11258                    selection.start = Point::new(selection.start.row, 0);
11259                    if !selection.is_empty() && selection.end.column == 0 {
11260                        selection.end = cmp::min(max_point, selection.end);
11261                    } else {
11262                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11263                    }
11264                    selection.goal = SelectionGoal::None;
11265                }
11266                if is_first {
11267                    is_first = false;
11268                } else {
11269                    text += "\n";
11270                }
11271                let mut len = 0;
11272                for chunk in buffer.text_for_range(selection.start..selection.end) {
11273                    text.push_str(chunk);
11274                    len += chunk.len();
11275                }
11276                clipboard_selections.push(ClipboardSelection {
11277                    len,
11278                    is_entire_line,
11279                    first_line_indent: buffer
11280                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11281                        .len,
11282                });
11283            }
11284        }
11285
11286        self.transact(window, cx, |this, window, cx| {
11287            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11288                s.select(selections);
11289            });
11290            this.insert("", window, cx);
11291        });
11292        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11293    }
11294
11295    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11296        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11297        let item = self.cut_common(window, cx);
11298        cx.write_to_clipboard(item);
11299    }
11300
11301    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11302        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11303        self.change_selections(None, window, cx, |s| {
11304            s.move_with(|snapshot, sel| {
11305                if sel.is_empty() {
11306                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11307                }
11308            });
11309        });
11310        let item = self.cut_common(window, cx);
11311        cx.set_global(KillRing(item))
11312    }
11313
11314    pub fn kill_ring_yank(
11315        &mut self,
11316        _: &KillRingYank,
11317        window: &mut Window,
11318        cx: &mut Context<Self>,
11319    ) {
11320        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11321        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11322            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11323                (kill_ring.text().to_string(), kill_ring.metadata_json())
11324            } else {
11325                return;
11326            }
11327        } else {
11328            return;
11329        };
11330        self.do_paste(&text, metadata, false, window, cx);
11331    }
11332
11333    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11334        self.do_copy(true, cx);
11335    }
11336
11337    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11338        self.do_copy(false, cx);
11339    }
11340
11341    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11342        let selections = self.selections.all::<Point>(cx);
11343        let buffer = self.buffer.read(cx).read(cx);
11344        let mut text = String::new();
11345
11346        let mut clipboard_selections = Vec::with_capacity(selections.len());
11347        {
11348            let max_point = buffer.max_point();
11349            let mut is_first = true;
11350            for selection in &selections {
11351                let mut start = selection.start;
11352                let mut end = selection.end;
11353                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11354                if is_entire_line {
11355                    start = Point::new(start.row, 0);
11356                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11357                }
11358
11359                let mut trimmed_selections = Vec::new();
11360                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11361                    let row = MultiBufferRow(start.row);
11362                    let first_indent = buffer.indent_size_for_line(row);
11363                    if first_indent.len == 0 || start.column > first_indent.len {
11364                        trimmed_selections.push(start..end);
11365                    } else {
11366                        trimmed_selections.push(
11367                            Point::new(row.0, first_indent.len)
11368                                ..Point::new(row.0, buffer.line_len(row)),
11369                        );
11370                        for row in start.row + 1..=end.row {
11371                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11372                            if row == end.row {
11373                                line_len = end.column;
11374                            }
11375                            if line_len == 0 {
11376                                trimmed_selections
11377                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11378                                continue;
11379                            }
11380                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11381                            if row_indent_size.len >= first_indent.len {
11382                                trimmed_selections.push(
11383                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11384                                );
11385                            } else {
11386                                trimmed_selections.clear();
11387                                trimmed_selections.push(start..end);
11388                                break;
11389                            }
11390                        }
11391                    }
11392                } else {
11393                    trimmed_selections.push(start..end);
11394                }
11395
11396                for trimmed_range in trimmed_selections {
11397                    if is_first {
11398                        is_first = false;
11399                    } else {
11400                        text += "\n";
11401                    }
11402                    let mut len = 0;
11403                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11404                        text.push_str(chunk);
11405                        len += chunk.len();
11406                    }
11407                    clipboard_selections.push(ClipboardSelection {
11408                        len,
11409                        is_entire_line,
11410                        first_line_indent: buffer
11411                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11412                            .len,
11413                    });
11414                }
11415            }
11416        }
11417
11418        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11419            text,
11420            clipboard_selections,
11421        ));
11422    }
11423
11424    pub fn do_paste(
11425        &mut self,
11426        text: &String,
11427        clipboard_selections: Option<Vec<ClipboardSelection>>,
11428        handle_entire_lines: bool,
11429        window: &mut Window,
11430        cx: &mut Context<Self>,
11431    ) {
11432        if self.read_only(cx) {
11433            return;
11434        }
11435
11436        let clipboard_text = Cow::Borrowed(text);
11437
11438        self.transact(window, cx, |this, window, cx| {
11439            if let Some(mut clipboard_selections) = clipboard_selections {
11440                let old_selections = this.selections.all::<usize>(cx);
11441                let all_selections_were_entire_line =
11442                    clipboard_selections.iter().all(|s| s.is_entire_line);
11443                let first_selection_indent_column =
11444                    clipboard_selections.first().map(|s| s.first_line_indent);
11445                if clipboard_selections.len() != old_selections.len() {
11446                    clipboard_selections.drain(..);
11447                }
11448                let cursor_offset = this.selections.last::<usize>(cx).head();
11449                let mut auto_indent_on_paste = true;
11450
11451                this.buffer.update(cx, |buffer, cx| {
11452                    let snapshot = buffer.read(cx);
11453                    auto_indent_on_paste = snapshot
11454                        .language_settings_at(cursor_offset, cx)
11455                        .auto_indent_on_paste;
11456
11457                    let mut start_offset = 0;
11458                    let mut edits = Vec::new();
11459                    let mut original_indent_columns = Vec::new();
11460                    for (ix, selection) in old_selections.iter().enumerate() {
11461                        let to_insert;
11462                        let entire_line;
11463                        let original_indent_column;
11464                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11465                            let end_offset = start_offset + clipboard_selection.len;
11466                            to_insert = &clipboard_text[start_offset..end_offset];
11467                            entire_line = clipboard_selection.is_entire_line;
11468                            start_offset = end_offset + 1;
11469                            original_indent_column = Some(clipboard_selection.first_line_indent);
11470                        } else {
11471                            to_insert = clipboard_text.as_str();
11472                            entire_line = all_selections_were_entire_line;
11473                            original_indent_column = first_selection_indent_column
11474                        }
11475
11476                        // If the corresponding selection was empty when this slice of the
11477                        // clipboard text was written, then the entire line containing the
11478                        // selection was copied. If this selection is also currently empty,
11479                        // then paste the line before the current line of the buffer.
11480                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11481                            let column = selection.start.to_point(&snapshot).column as usize;
11482                            let line_start = selection.start - column;
11483                            line_start..line_start
11484                        } else {
11485                            selection.range()
11486                        };
11487
11488                        edits.push((range, to_insert));
11489                        original_indent_columns.push(original_indent_column);
11490                    }
11491                    drop(snapshot);
11492
11493                    buffer.edit(
11494                        edits,
11495                        if auto_indent_on_paste {
11496                            Some(AutoindentMode::Block {
11497                                original_indent_columns,
11498                            })
11499                        } else {
11500                            None
11501                        },
11502                        cx,
11503                    );
11504                });
11505
11506                let selections = this.selections.all::<usize>(cx);
11507                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11508                    s.select(selections)
11509                });
11510            } else {
11511                this.insert(&clipboard_text, window, cx);
11512            }
11513        });
11514    }
11515
11516    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11517        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11518        if let Some(item) = cx.read_from_clipboard() {
11519            let entries = item.entries();
11520
11521            match entries.first() {
11522                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11523                // of all the pasted entries.
11524                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11525                    .do_paste(
11526                        clipboard_string.text(),
11527                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11528                        true,
11529                        window,
11530                        cx,
11531                    ),
11532                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11533            }
11534        }
11535    }
11536
11537    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11538        if self.read_only(cx) {
11539            return;
11540        }
11541
11542        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11543
11544        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11545            if let Some((selections, _)) =
11546                self.selection_history.transaction(transaction_id).cloned()
11547            {
11548                self.change_selections(None, window, cx, |s| {
11549                    s.select_anchors(selections.to_vec());
11550                });
11551            } else {
11552                log::error!(
11553                    "No entry in selection_history found for undo. \
11554                     This may correspond to a bug where undo does not update the selection. \
11555                     If this is occurring, please add details to \
11556                     https://github.com/zed-industries/zed/issues/22692"
11557                );
11558            }
11559            self.request_autoscroll(Autoscroll::fit(), cx);
11560            self.unmark_text(window, cx);
11561            self.refresh_inline_completion(true, false, window, cx);
11562            cx.emit(EditorEvent::Edited { transaction_id });
11563            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11564        }
11565    }
11566
11567    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11568        if self.read_only(cx) {
11569            return;
11570        }
11571
11572        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11573
11574        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11575            if let Some((_, Some(selections))) =
11576                self.selection_history.transaction(transaction_id).cloned()
11577            {
11578                self.change_selections(None, window, cx, |s| {
11579                    s.select_anchors(selections.to_vec());
11580                });
11581            } else {
11582                log::error!(
11583                    "No entry in selection_history found for redo. \
11584                     This may correspond to a bug where undo does not update the selection. \
11585                     If this is occurring, please add details to \
11586                     https://github.com/zed-industries/zed/issues/22692"
11587                );
11588            }
11589            self.request_autoscroll(Autoscroll::fit(), cx);
11590            self.unmark_text(window, cx);
11591            self.refresh_inline_completion(true, false, window, cx);
11592            cx.emit(EditorEvent::Edited { transaction_id });
11593        }
11594    }
11595
11596    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11597        self.buffer
11598            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11599    }
11600
11601    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11602        self.buffer
11603            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11604    }
11605
11606    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11607        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11608        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11609            s.move_with(|map, selection| {
11610                let cursor = if selection.is_empty() {
11611                    movement::left(map, selection.start)
11612                } else {
11613                    selection.start
11614                };
11615                selection.collapse_to(cursor, SelectionGoal::None);
11616            });
11617        })
11618    }
11619
11620    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11621        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11622        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11623            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11624        })
11625    }
11626
11627    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11628        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11629        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11630            s.move_with(|map, selection| {
11631                let cursor = if selection.is_empty() {
11632                    movement::right(map, selection.end)
11633                } else {
11634                    selection.end
11635                };
11636                selection.collapse_to(cursor, SelectionGoal::None)
11637            });
11638        })
11639    }
11640
11641    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11642        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11643        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11644            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11645        })
11646    }
11647
11648    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11649        if self.take_rename(true, window, cx).is_some() {
11650            return;
11651        }
11652
11653        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11654            cx.propagate();
11655            return;
11656        }
11657
11658        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11659
11660        let text_layout_details = &self.text_layout_details(window);
11661        let selection_count = self.selections.count();
11662        let first_selection = self.selections.first_anchor();
11663
11664        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11665            s.move_with(|map, selection| {
11666                if !selection.is_empty() {
11667                    selection.goal = SelectionGoal::None;
11668                }
11669                let (cursor, goal) = movement::up(
11670                    map,
11671                    selection.start,
11672                    selection.goal,
11673                    false,
11674                    text_layout_details,
11675                );
11676                selection.collapse_to(cursor, goal);
11677            });
11678        });
11679
11680        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11681        {
11682            cx.propagate();
11683        }
11684    }
11685
11686    pub fn move_up_by_lines(
11687        &mut self,
11688        action: &MoveUpByLines,
11689        window: &mut Window,
11690        cx: &mut Context<Self>,
11691    ) {
11692        if self.take_rename(true, window, cx).is_some() {
11693            return;
11694        }
11695
11696        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11697            cx.propagate();
11698            return;
11699        }
11700
11701        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11702
11703        let text_layout_details = &self.text_layout_details(window);
11704
11705        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11706            s.move_with(|map, selection| {
11707                if !selection.is_empty() {
11708                    selection.goal = SelectionGoal::None;
11709                }
11710                let (cursor, goal) = movement::up_by_rows(
11711                    map,
11712                    selection.start,
11713                    action.lines,
11714                    selection.goal,
11715                    false,
11716                    text_layout_details,
11717                );
11718                selection.collapse_to(cursor, goal);
11719            });
11720        })
11721    }
11722
11723    pub fn move_down_by_lines(
11724        &mut self,
11725        action: &MoveDownByLines,
11726        window: &mut Window,
11727        cx: &mut Context<Self>,
11728    ) {
11729        if self.take_rename(true, window, cx).is_some() {
11730            return;
11731        }
11732
11733        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11734            cx.propagate();
11735            return;
11736        }
11737
11738        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11739
11740        let text_layout_details = &self.text_layout_details(window);
11741
11742        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11743            s.move_with(|map, selection| {
11744                if !selection.is_empty() {
11745                    selection.goal = SelectionGoal::None;
11746                }
11747                let (cursor, goal) = movement::down_by_rows(
11748                    map,
11749                    selection.start,
11750                    action.lines,
11751                    selection.goal,
11752                    false,
11753                    text_layout_details,
11754                );
11755                selection.collapse_to(cursor, goal);
11756            });
11757        })
11758    }
11759
11760    pub fn select_down_by_lines(
11761        &mut self,
11762        action: &SelectDownByLines,
11763        window: &mut Window,
11764        cx: &mut Context<Self>,
11765    ) {
11766        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11767        let text_layout_details = &self.text_layout_details(window);
11768        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11769            s.move_heads_with(|map, head, goal| {
11770                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11771            })
11772        })
11773    }
11774
11775    pub fn select_up_by_lines(
11776        &mut self,
11777        action: &SelectUpByLines,
11778        window: &mut Window,
11779        cx: &mut Context<Self>,
11780    ) {
11781        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11782        let text_layout_details = &self.text_layout_details(window);
11783        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11784            s.move_heads_with(|map, head, goal| {
11785                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11786            })
11787        })
11788    }
11789
11790    pub fn select_page_up(
11791        &mut self,
11792        _: &SelectPageUp,
11793        window: &mut Window,
11794        cx: &mut Context<Self>,
11795    ) {
11796        let Some(row_count) = self.visible_row_count() else {
11797            return;
11798        };
11799
11800        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11801
11802        let text_layout_details = &self.text_layout_details(window);
11803
11804        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11805            s.move_heads_with(|map, head, goal| {
11806                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11807            })
11808        })
11809    }
11810
11811    pub fn move_page_up(
11812        &mut self,
11813        action: &MovePageUp,
11814        window: &mut Window,
11815        cx: &mut Context<Self>,
11816    ) {
11817        if self.take_rename(true, window, cx).is_some() {
11818            return;
11819        }
11820
11821        if self
11822            .context_menu
11823            .borrow_mut()
11824            .as_mut()
11825            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11826            .unwrap_or(false)
11827        {
11828            return;
11829        }
11830
11831        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11832            cx.propagate();
11833            return;
11834        }
11835
11836        let Some(row_count) = self.visible_row_count() else {
11837            return;
11838        };
11839
11840        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11841
11842        let autoscroll = if action.center_cursor {
11843            Autoscroll::center()
11844        } else {
11845            Autoscroll::fit()
11846        };
11847
11848        let text_layout_details = &self.text_layout_details(window);
11849
11850        self.change_selections(Some(autoscroll), window, cx, |s| {
11851            s.move_with(|map, selection| {
11852                if !selection.is_empty() {
11853                    selection.goal = SelectionGoal::None;
11854                }
11855                let (cursor, goal) = movement::up_by_rows(
11856                    map,
11857                    selection.end,
11858                    row_count,
11859                    selection.goal,
11860                    false,
11861                    text_layout_details,
11862                );
11863                selection.collapse_to(cursor, goal);
11864            });
11865        });
11866    }
11867
11868    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11869        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11870        let text_layout_details = &self.text_layout_details(window);
11871        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11872            s.move_heads_with(|map, head, goal| {
11873                movement::up(map, head, goal, false, text_layout_details)
11874            })
11875        })
11876    }
11877
11878    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11879        self.take_rename(true, window, cx);
11880
11881        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11882            cx.propagate();
11883            return;
11884        }
11885
11886        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11887
11888        let text_layout_details = &self.text_layout_details(window);
11889        let selection_count = self.selections.count();
11890        let first_selection = self.selections.first_anchor();
11891
11892        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11893            s.move_with(|map, selection| {
11894                if !selection.is_empty() {
11895                    selection.goal = SelectionGoal::None;
11896                }
11897                let (cursor, goal) = movement::down(
11898                    map,
11899                    selection.end,
11900                    selection.goal,
11901                    false,
11902                    text_layout_details,
11903                );
11904                selection.collapse_to(cursor, goal);
11905            });
11906        });
11907
11908        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11909        {
11910            cx.propagate();
11911        }
11912    }
11913
11914    pub fn select_page_down(
11915        &mut self,
11916        _: &SelectPageDown,
11917        window: &mut Window,
11918        cx: &mut Context<Self>,
11919    ) {
11920        let Some(row_count) = self.visible_row_count() else {
11921            return;
11922        };
11923
11924        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11925
11926        let text_layout_details = &self.text_layout_details(window);
11927
11928        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11929            s.move_heads_with(|map, head, goal| {
11930                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11931            })
11932        })
11933    }
11934
11935    pub fn move_page_down(
11936        &mut self,
11937        action: &MovePageDown,
11938        window: &mut Window,
11939        cx: &mut Context<Self>,
11940    ) {
11941        if self.take_rename(true, window, cx).is_some() {
11942            return;
11943        }
11944
11945        if self
11946            .context_menu
11947            .borrow_mut()
11948            .as_mut()
11949            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11950            .unwrap_or(false)
11951        {
11952            return;
11953        }
11954
11955        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11956            cx.propagate();
11957            return;
11958        }
11959
11960        let Some(row_count) = self.visible_row_count() else {
11961            return;
11962        };
11963
11964        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11965
11966        let autoscroll = if action.center_cursor {
11967            Autoscroll::center()
11968        } else {
11969            Autoscroll::fit()
11970        };
11971
11972        let text_layout_details = &self.text_layout_details(window);
11973        self.change_selections(Some(autoscroll), window, cx, |s| {
11974            s.move_with(|map, selection| {
11975                if !selection.is_empty() {
11976                    selection.goal = SelectionGoal::None;
11977                }
11978                let (cursor, goal) = movement::down_by_rows(
11979                    map,
11980                    selection.end,
11981                    row_count,
11982                    selection.goal,
11983                    false,
11984                    text_layout_details,
11985                );
11986                selection.collapse_to(cursor, goal);
11987            });
11988        });
11989    }
11990
11991    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11992        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11993        let text_layout_details = &self.text_layout_details(window);
11994        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11995            s.move_heads_with(|map, head, goal| {
11996                movement::down(map, head, goal, false, text_layout_details)
11997            })
11998        });
11999    }
12000
12001    pub fn context_menu_first(
12002        &mut self,
12003        _: &ContextMenuFirst,
12004        window: &mut Window,
12005        cx: &mut Context<Self>,
12006    ) {
12007        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12008            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12009        }
12010    }
12011
12012    pub fn context_menu_prev(
12013        &mut self,
12014        _: &ContextMenuPrevious,
12015        window: &mut Window,
12016        cx: &mut Context<Self>,
12017    ) {
12018        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12019            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12020        }
12021    }
12022
12023    pub fn context_menu_next(
12024        &mut self,
12025        _: &ContextMenuNext,
12026        window: &mut Window,
12027        cx: &mut Context<Self>,
12028    ) {
12029        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12030            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12031        }
12032    }
12033
12034    pub fn context_menu_last(
12035        &mut self,
12036        _: &ContextMenuLast,
12037        window: &mut Window,
12038        cx: &mut Context<Self>,
12039    ) {
12040        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12041            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12042        }
12043    }
12044
12045    pub fn move_to_previous_word_start(
12046        &mut self,
12047        _: &MoveToPreviousWordStart,
12048        window: &mut Window,
12049        cx: &mut Context<Self>,
12050    ) {
12051        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12052        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12053            s.move_cursors_with(|map, head, _| {
12054                (
12055                    movement::previous_word_start(map, head),
12056                    SelectionGoal::None,
12057                )
12058            });
12059        })
12060    }
12061
12062    pub fn move_to_previous_subword_start(
12063        &mut self,
12064        _: &MoveToPreviousSubwordStart,
12065        window: &mut Window,
12066        cx: &mut Context<Self>,
12067    ) {
12068        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12069        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12070            s.move_cursors_with(|map, head, _| {
12071                (
12072                    movement::previous_subword_start(map, head),
12073                    SelectionGoal::None,
12074                )
12075            });
12076        })
12077    }
12078
12079    pub fn select_to_previous_word_start(
12080        &mut self,
12081        _: &SelectToPreviousWordStart,
12082        window: &mut Window,
12083        cx: &mut Context<Self>,
12084    ) {
12085        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12086        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12087            s.move_heads_with(|map, head, _| {
12088                (
12089                    movement::previous_word_start(map, head),
12090                    SelectionGoal::None,
12091                )
12092            });
12093        })
12094    }
12095
12096    pub fn select_to_previous_subword_start(
12097        &mut self,
12098        _: &SelectToPreviousSubwordStart,
12099        window: &mut Window,
12100        cx: &mut Context<Self>,
12101    ) {
12102        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12103        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12104            s.move_heads_with(|map, head, _| {
12105                (
12106                    movement::previous_subword_start(map, head),
12107                    SelectionGoal::None,
12108                )
12109            });
12110        })
12111    }
12112
12113    pub fn delete_to_previous_word_start(
12114        &mut self,
12115        action: &DeleteToPreviousWordStart,
12116        window: &mut Window,
12117        cx: &mut Context<Self>,
12118    ) {
12119        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12120        self.transact(window, cx, |this, window, cx| {
12121            this.select_autoclose_pair(window, cx);
12122            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12123                s.move_with(|map, selection| {
12124                    if selection.is_empty() {
12125                        let cursor = if action.ignore_newlines {
12126                            movement::previous_word_start(map, selection.head())
12127                        } else {
12128                            movement::previous_word_start_or_newline(map, selection.head())
12129                        };
12130                        selection.set_head(cursor, SelectionGoal::None);
12131                    }
12132                });
12133            });
12134            this.insert("", window, cx);
12135        });
12136    }
12137
12138    pub fn delete_to_previous_subword_start(
12139        &mut self,
12140        _: &DeleteToPreviousSubwordStart,
12141        window: &mut Window,
12142        cx: &mut Context<Self>,
12143    ) {
12144        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12145        self.transact(window, cx, |this, window, cx| {
12146            this.select_autoclose_pair(window, cx);
12147            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12148                s.move_with(|map, selection| {
12149                    if selection.is_empty() {
12150                        let cursor = movement::previous_subword_start(map, selection.head());
12151                        selection.set_head(cursor, SelectionGoal::None);
12152                    }
12153                });
12154            });
12155            this.insert("", window, cx);
12156        });
12157    }
12158
12159    pub fn move_to_next_word_end(
12160        &mut self,
12161        _: &MoveToNextWordEnd,
12162        window: &mut Window,
12163        cx: &mut Context<Self>,
12164    ) {
12165        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12166        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12167            s.move_cursors_with(|map, head, _| {
12168                (movement::next_word_end(map, head), SelectionGoal::None)
12169            });
12170        })
12171    }
12172
12173    pub fn move_to_next_subword_end(
12174        &mut self,
12175        _: &MoveToNextSubwordEnd,
12176        window: &mut Window,
12177        cx: &mut Context<Self>,
12178    ) {
12179        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12180        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12181            s.move_cursors_with(|map, head, _| {
12182                (movement::next_subword_end(map, head), SelectionGoal::None)
12183            });
12184        })
12185    }
12186
12187    pub fn select_to_next_word_end(
12188        &mut self,
12189        _: &SelectToNextWordEnd,
12190        window: &mut Window,
12191        cx: &mut Context<Self>,
12192    ) {
12193        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12194        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12195            s.move_heads_with(|map, head, _| {
12196                (movement::next_word_end(map, head), SelectionGoal::None)
12197            });
12198        })
12199    }
12200
12201    pub fn select_to_next_subword_end(
12202        &mut self,
12203        _: &SelectToNextSubwordEnd,
12204        window: &mut Window,
12205        cx: &mut Context<Self>,
12206    ) {
12207        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12208        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12209            s.move_heads_with(|map, head, _| {
12210                (movement::next_subword_end(map, head), SelectionGoal::None)
12211            });
12212        })
12213    }
12214
12215    pub fn delete_to_next_word_end(
12216        &mut self,
12217        action: &DeleteToNextWordEnd,
12218        window: &mut Window,
12219        cx: &mut Context<Self>,
12220    ) {
12221        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12222        self.transact(window, cx, |this, window, cx| {
12223            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12224                s.move_with(|map, selection| {
12225                    if selection.is_empty() {
12226                        let cursor = if action.ignore_newlines {
12227                            movement::next_word_end(map, selection.head())
12228                        } else {
12229                            movement::next_word_end_or_newline(map, selection.head())
12230                        };
12231                        selection.set_head(cursor, SelectionGoal::None);
12232                    }
12233                });
12234            });
12235            this.insert("", window, cx);
12236        });
12237    }
12238
12239    pub fn delete_to_next_subword_end(
12240        &mut self,
12241        _: &DeleteToNextSubwordEnd,
12242        window: &mut Window,
12243        cx: &mut Context<Self>,
12244    ) {
12245        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12246        self.transact(window, cx, |this, window, cx| {
12247            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12248                s.move_with(|map, selection| {
12249                    if selection.is_empty() {
12250                        let cursor = movement::next_subword_end(map, selection.head());
12251                        selection.set_head(cursor, SelectionGoal::None);
12252                    }
12253                });
12254            });
12255            this.insert("", window, cx);
12256        });
12257    }
12258
12259    pub fn move_to_beginning_of_line(
12260        &mut self,
12261        action: &MoveToBeginningOfLine,
12262        window: &mut Window,
12263        cx: &mut Context<Self>,
12264    ) {
12265        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12266        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12267            s.move_cursors_with(|map, head, _| {
12268                (
12269                    movement::indented_line_beginning(
12270                        map,
12271                        head,
12272                        action.stop_at_soft_wraps,
12273                        action.stop_at_indent,
12274                    ),
12275                    SelectionGoal::None,
12276                )
12277            });
12278        })
12279    }
12280
12281    pub fn select_to_beginning_of_line(
12282        &mut self,
12283        action: &SelectToBeginningOfLine,
12284        window: &mut Window,
12285        cx: &mut Context<Self>,
12286    ) {
12287        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12288        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12289            s.move_heads_with(|map, head, _| {
12290                (
12291                    movement::indented_line_beginning(
12292                        map,
12293                        head,
12294                        action.stop_at_soft_wraps,
12295                        action.stop_at_indent,
12296                    ),
12297                    SelectionGoal::None,
12298                )
12299            });
12300        });
12301    }
12302
12303    pub fn delete_to_beginning_of_line(
12304        &mut self,
12305        action: &DeleteToBeginningOfLine,
12306        window: &mut Window,
12307        cx: &mut Context<Self>,
12308    ) {
12309        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12310        self.transact(window, cx, |this, window, cx| {
12311            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12312                s.move_with(|_, selection| {
12313                    selection.reversed = true;
12314                });
12315            });
12316
12317            this.select_to_beginning_of_line(
12318                &SelectToBeginningOfLine {
12319                    stop_at_soft_wraps: false,
12320                    stop_at_indent: action.stop_at_indent,
12321                },
12322                window,
12323                cx,
12324            );
12325            this.backspace(&Backspace, window, cx);
12326        });
12327    }
12328
12329    pub fn move_to_end_of_line(
12330        &mut self,
12331        action: &MoveToEndOfLine,
12332        window: &mut Window,
12333        cx: &mut Context<Self>,
12334    ) {
12335        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12336        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12337            s.move_cursors_with(|map, head, _| {
12338                (
12339                    movement::line_end(map, head, action.stop_at_soft_wraps),
12340                    SelectionGoal::None,
12341                )
12342            });
12343        })
12344    }
12345
12346    pub fn select_to_end_of_line(
12347        &mut self,
12348        action: &SelectToEndOfLine,
12349        window: &mut Window,
12350        cx: &mut Context<Self>,
12351    ) {
12352        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12353        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12354            s.move_heads_with(|map, head, _| {
12355                (
12356                    movement::line_end(map, head, action.stop_at_soft_wraps),
12357                    SelectionGoal::None,
12358                )
12359            });
12360        })
12361    }
12362
12363    pub fn delete_to_end_of_line(
12364        &mut self,
12365        _: &DeleteToEndOfLine,
12366        window: &mut Window,
12367        cx: &mut Context<Self>,
12368    ) {
12369        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12370        self.transact(window, cx, |this, window, cx| {
12371            this.select_to_end_of_line(
12372                &SelectToEndOfLine {
12373                    stop_at_soft_wraps: false,
12374                },
12375                window,
12376                cx,
12377            );
12378            this.delete(&Delete, window, cx);
12379        });
12380    }
12381
12382    pub fn cut_to_end_of_line(
12383        &mut self,
12384        _: &CutToEndOfLine,
12385        window: &mut Window,
12386        cx: &mut Context<Self>,
12387    ) {
12388        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12389        self.transact(window, cx, |this, window, cx| {
12390            this.select_to_end_of_line(
12391                &SelectToEndOfLine {
12392                    stop_at_soft_wraps: false,
12393                },
12394                window,
12395                cx,
12396            );
12397            this.cut(&Cut, window, cx);
12398        });
12399    }
12400
12401    pub fn move_to_start_of_paragraph(
12402        &mut self,
12403        _: &MoveToStartOfParagraph,
12404        window: &mut Window,
12405        cx: &mut Context<Self>,
12406    ) {
12407        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12408            cx.propagate();
12409            return;
12410        }
12411        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12412        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12413            s.move_with(|map, selection| {
12414                selection.collapse_to(
12415                    movement::start_of_paragraph(map, selection.head(), 1),
12416                    SelectionGoal::None,
12417                )
12418            });
12419        })
12420    }
12421
12422    pub fn move_to_end_of_paragraph(
12423        &mut self,
12424        _: &MoveToEndOfParagraph,
12425        window: &mut Window,
12426        cx: &mut Context<Self>,
12427    ) {
12428        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12429            cx.propagate();
12430            return;
12431        }
12432        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12433        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12434            s.move_with(|map, selection| {
12435                selection.collapse_to(
12436                    movement::end_of_paragraph(map, selection.head(), 1),
12437                    SelectionGoal::None,
12438                )
12439            });
12440        })
12441    }
12442
12443    pub fn select_to_start_of_paragraph(
12444        &mut self,
12445        _: &SelectToStartOfParagraph,
12446        window: &mut Window,
12447        cx: &mut Context<Self>,
12448    ) {
12449        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12450            cx.propagate();
12451            return;
12452        }
12453        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12454        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12455            s.move_heads_with(|map, head, _| {
12456                (
12457                    movement::start_of_paragraph(map, head, 1),
12458                    SelectionGoal::None,
12459                )
12460            });
12461        })
12462    }
12463
12464    pub fn select_to_end_of_paragraph(
12465        &mut self,
12466        _: &SelectToEndOfParagraph,
12467        window: &mut Window,
12468        cx: &mut Context<Self>,
12469    ) {
12470        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12471            cx.propagate();
12472            return;
12473        }
12474        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12475        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12476            s.move_heads_with(|map, head, _| {
12477                (
12478                    movement::end_of_paragraph(map, head, 1),
12479                    SelectionGoal::None,
12480                )
12481            });
12482        })
12483    }
12484
12485    pub fn move_to_start_of_excerpt(
12486        &mut self,
12487        _: &MoveToStartOfExcerpt,
12488        window: &mut Window,
12489        cx: &mut Context<Self>,
12490    ) {
12491        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12492            cx.propagate();
12493            return;
12494        }
12495        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12496        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12497            s.move_with(|map, selection| {
12498                selection.collapse_to(
12499                    movement::start_of_excerpt(
12500                        map,
12501                        selection.head(),
12502                        workspace::searchable::Direction::Prev,
12503                    ),
12504                    SelectionGoal::None,
12505                )
12506            });
12507        })
12508    }
12509
12510    pub fn move_to_start_of_next_excerpt(
12511        &mut self,
12512        _: &MoveToStartOfNextExcerpt,
12513        window: &mut Window,
12514        cx: &mut Context<Self>,
12515    ) {
12516        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12517            cx.propagate();
12518            return;
12519        }
12520
12521        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12522            s.move_with(|map, selection| {
12523                selection.collapse_to(
12524                    movement::start_of_excerpt(
12525                        map,
12526                        selection.head(),
12527                        workspace::searchable::Direction::Next,
12528                    ),
12529                    SelectionGoal::None,
12530                )
12531            });
12532        })
12533    }
12534
12535    pub fn move_to_end_of_excerpt(
12536        &mut self,
12537        _: &MoveToEndOfExcerpt,
12538        window: &mut Window,
12539        cx: &mut Context<Self>,
12540    ) {
12541        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12542            cx.propagate();
12543            return;
12544        }
12545        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12546        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12547            s.move_with(|map, selection| {
12548                selection.collapse_to(
12549                    movement::end_of_excerpt(
12550                        map,
12551                        selection.head(),
12552                        workspace::searchable::Direction::Next,
12553                    ),
12554                    SelectionGoal::None,
12555                )
12556            });
12557        })
12558    }
12559
12560    pub fn move_to_end_of_previous_excerpt(
12561        &mut self,
12562        _: &MoveToEndOfPreviousExcerpt,
12563        window: &mut Window,
12564        cx: &mut Context<Self>,
12565    ) {
12566        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12567            cx.propagate();
12568            return;
12569        }
12570        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12571        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12572            s.move_with(|map, selection| {
12573                selection.collapse_to(
12574                    movement::end_of_excerpt(
12575                        map,
12576                        selection.head(),
12577                        workspace::searchable::Direction::Prev,
12578                    ),
12579                    SelectionGoal::None,
12580                )
12581            });
12582        })
12583    }
12584
12585    pub fn select_to_start_of_excerpt(
12586        &mut self,
12587        _: &SelectToStartOfExcerpt,
12588        window: &mut Window,
12589        cx: &mut Context<Self>,
12590    ) {
12591        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12592            cx.propagate();
12593            return;
12594        }
12595        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12596        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12597            s.move_heads_with(|map, head, _| {
12598                (
12599                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12600                    SelectionGoal::None,
12601                )
12602            });
12603        })
12604    }
12605
12606    pub fn select_to_start_of_next_excerpt(
12607        &mut self,
12608        _: &SelectToStartOfNextExcerpt,
12609        window: &mut Window,
12610        cx: &mut Context<Self>,
12611    ) {
12612        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12613            cx.propagate();
12614            return;
12615        }
12616        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12617        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12618            s.move_heads_with(|map, head, _| {
12619                (
12620                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12621                    SelectionGoal::None,
12622                )
12623            });
12624        })
12625    }
12626
12627    pub fn select_to_end_of_excerpt(
12628        &mut self,
12629        _: &SelectToEndOfExcerpt,
12630        window: &mut Window,
12631        cx: &mut Context<Self>,
12632    ) {
12633        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12634            cx.propagate();
12635            return;
12636        }
12637        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12638        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12639            s.move_heads_with(|map, head, _| {
12640                (
12641                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12642                    SelectionGoal::None,
12643                )
12644            });
12645        })
12646    }
12647
12648    pub fn select_to_end_of_previous_excerpt(
12649        &mut self,
12650        _: &SelectToEndOfPreviousExcerpt,
12651        window: &mut Window,
12652        cx: &mut Context<Self>,
12653    ) {
12654        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12655            cx.propagate();
12656            return;
12657        }
12658        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12659        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12660            s.move_heads_with(|map, head, _| {
12661                (
12662                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12663                    SelectionGoal::None,
12664                )
12665            });
12666        })
12667    }
12668
12669    pub fn move_to_beginning(
12670        &mut self,
12671        _: &MoveToBeginning,
12672        window: &mut Window,
12673        cx: &mut Context<Self>,
12674    ) {
12675        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12676            cx.propagate();
12677            return;
12678        }
12679        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12680        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12681            s.select_ranges(vec![0..0]);
12682        });
12683    }
12684
12685    pub fn select_to_beginning(
12686        &mut self,
12687        _: &SelectToBeginning,
12688        window: &mut Window,
12689        cx: &mut Context<Self>,
12690    ) {
12691        let mut selection = self.selections.last::<Point>(cx);
12692        selection.set_head(Point::zero(), SelectionGoal::None);
12693        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12694        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12695            s.select(vec![selection]);
12696        });
12697    }
12698
12699    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12700        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12701            cx.propagate();
12702            return;
12703        }
12704        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12705        let cursor = self.buffer.read(cx).read(cx).len();
12706        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12707            s.select_ranges(vec![cursor..cursor])
12708        });
12709    }
12710
12711    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12712        self.nav_history = nav_history;
12713    }
12714
12715    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12716        self.nav_history.as_ref()
12717    }
12718
12719    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12720        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12721    }
12722
12723    fn push_to_nav_history(
12724        &mut self,
12725        cursor_anchor: Anchor,
12726        new_position: Option<Point>,
12727        is_deactivate: bool,
12728        cx: &mut Context<Self>,
12729    ) {
12730        if let Some(nav_history) = self.nav_history.as_mut() {
12731            let buffer = self.buffer.read(cx).read(cx);
12732            let cursor_position = cursor_anchor.to_point(&buffer);
12733            let scroll_state = self.scroll_manager.anchor();
12734            let scroll_top_row = scroll_state.top_row(&buffer);
12735            drop(buffer);
12736
12737            if let Some(new_position) = new_position {
12738                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12739                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12740                    return;
12741                }
12742            }
12743
12744            nav_history.push(
12745                Some(NavigationData {
12746                    cursor_anchor,
12747                    cursor_position,
12748                    scroll_anchor: scroll_state,
12749                    scroll_top_row,
12750                }),
12751                cx,
12752            );
12753            cx.emit(EditorEvent::PushedToNavHistory {
12754                anchor: cursor_anchor,
12755                is_deactivate,
12756            })
12757        }
12758    }
12759
12760    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12761        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12762        let buffer = self.buffer.read(cx).snapshot(cx);
12763        let mut selection = self.selections.first::<usize>(cx);
12764        selection.set_head(buffer.len(), SelectionGoal::None);
12765        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12766            s.select(vec![selection]);
12767        });
12768    }
12769
12770    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12771        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12772        let end = self.buffer.read(cx).read(cx).len();
12773        self.change_selections(None, window, cx, |s| {
12774            s.select_ranges(vec![0..end]);
12775        });
12776    }
12777
12778    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12779        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12780        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12781        let mut selections = self.selections.all::<Point>(cx);
12782        let max_point = display_map.buffer_snapshot.max_point();
12783        for selection in &mut selections {
12784            let rows = selection.spanned_rows(true, &display_map);
12785            selection.start = Point::new(rows.start.0, 0);
12786            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12787            selection.reversed = false;
12788        }
12789        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12790            s.select(selections);
12791        });
12792    }
12793
12794    pub fn split_selection_into_lines(
12795        &mut self,
12796        _: &SplitSelectionIntoLines,
12797        window: &mut Window,
12798        cx: &mut Context<Self>,
12799    ) {
12800        let selections = self
12801            .selections
12802            .all::<Point>(cx)
12803            .into_iter()
12804            .map(|selection| selection.start..selection.end)
12805            .collect::<Vec<_>>();
12806        self.unfold_ranges(&selections, true, true, cx);
12807
12808        let mut new_selection_ranges = Vec::new();
12809        {
12810            let buffer = self.buffer.read(cx).read(cx);
12811            for selection in selections {
12812                for row in selection.start.row..selection.end.row {
12813                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12814                    new_selection_ranges.push(cursor..cursor);
12815                }
12816
12817                let is_multiline_selection = selection.start.row != selection.end.row;
12818                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12819                // so this action feels more ergonomic when paired with other selection operations
12820                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12821                if !should_skip_last {
12822                    new_selection_ranges.push(selection.end..selection.end);
12823                }
12824            }
12825        }
12826        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12827            s.select_ranges(new_selection_ranges);
12828        });
12829    }
12830
12831    pub fn add_selection_above(
12832        &mut self,
12833        _: &AddSelectionAbove,
12834        window: &mut Window,
12835        cx: &mut Context<Self>,
12836    ) {
12837        self.add_selection(true, window, cx);
12838    }
12839
12840    pub fn add_selection_below(
12841        &mut self,
12842        _: &AddSelectionBelow,
12843        window: &mut Window,
12844        cx: &mut Context<Self>,
12845    ) {
12846        self.add_selection(false, window, cx);
12847    }
12848
12849    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12850        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12851
12852        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12853        let all_selections = self.selections.all::<Point>(cx);
12854        let text_layout_details = self.text_layout_details(window);
12855
12856        let (mut columnar_selections, new_selections_to_columnarize) = {
12857            if let Some(state) = self.add_selections_state.as_ref() {
12858                let columnar_selection_ids: HashSet<_> = state
12859                    .groups
12860                    .iter()
12861                    .flat_map(|group| group.stack.iter())
12862                    .copied()
12863                    .collect();
12864
12865                all_selections
12866                    .into_iter()
12867                    .partition(|s| columnar_selection_ids.contains(&s.id))
12868            } else {
12869                (Vec::new(), all_selections)
12870            }
12871        };
12872
12873        let mut state = self
12874            .add_selections_state
12875            .take()
12876            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12877
12878        for selection in new_selections_to_columnarize {
12879            let range = selection.display_range(&display_map).sorted();
12880            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12881            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12882            let positions = start_x.min(end_x)..start_x.max(end_x);
12883            let mut stack = Vec::new();
12884            for row in range.start.row().0..=range.end.row().0 {
12885                if let Some(selection) = self.selections.build_columnar_selection(
12886                    &display_map,
12887                    DisplayRow(row),
12888                    &positions,
12889                    selection.reversed,
12890                    &text_layout_details,
12891                ) {
12892                    stack.push(selection.id);
12893                    columnar_selections.push(selection);
12894                }
12895            }
12896            if !stack.is_empty() {
12897                if above {
12898                    stack.reverse();
12899                }
12900                state.groups.push(AddSelectionsGroup { above, stack });
12901            }
12902        }
12903
12904        let mut final_selections = Vec::new();
12905        let end_row = if above {
12906            DisplayRow(0)
12907        } else {
12908            display_map.max_point().row()
12909        };
12910
12911        let mut last_added_item_per_group = HashMap::default();
12912        for group in state.groups.iter_mut() {
12913            if let Some(last_id) = group.stack.last() {
12914                last_added_item_per_group.insert(*last_id, group);
12915            }
12916        }
12917
12918        for selection in columnar_selections {
12919            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
12920                if above == group.above {
12921                    let range = selection.display_range(&display_map).sorted();
12922                    debug_assert_eq!(range.start.row(), range.end.row());
12923                    let mut row = range.start.row();
12924                    let positions =
12925                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12926                            px(start)..px(end)
12927                        } else {
12928                            let start_x =
12929                                display_map.x_for_display_point(range.start, &text_layout_details);
12930                            let end_x =
12931                                display_map.x_for_display_point(range.end, &text_layout_details);
12932                            start_x.min(end_x)..start_x.max(end_x)
12933                        };
12934
12935                    let mut maybe_new_selection = None;
12936                    while row != end_row {
12937                        if above {
12938                            row.0 -= 1;
12939                        } else {
12940                            row.0 += 1;
12941                        }
12942                        if let Some(new_selection) = self.selections.build_columnar_selection(
12943                            &display_map,
12944                            row,
12945                            &positions,
12946                            selection.reversed,
12947                            &text_layout_details,
12948                        ) {
12949                            maybe_new_selection = Some(new_selection);
12950                            break;
12951                        }
12952                    }
12953
12954                    if let Some(new_selection) = maybe_new_selection {
12955                        group.stack.push(new_selection.id);
12956                        if above {
12957                            final_selections.push(new_selection);
12958                            final_selections.push(selection);
12959                        } else {
12960                            final_selections.push(selection);
12961                            final_selections.push(new_selection);
12962                        }
12963                    } else {
12964                        final_selections.push(selection);
12965                    }
12966                } else {
12967                    group.stack.pop();
12968                }
12969            } else {
12970                final_selections.push(selection);
12971            }
12972        }
12973
12974        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12975            s.select(final_selections);
12976        });
12977
12978        let final_selection_ids: HashSet<_> = self
12979            .selections
12980            .all::<Point>(cx)
12981            .iter()
12982            .map(|s| s.id)
12983            .collect();
12984        state.groups.retain_mut(|group| {
12985            // selections might get merged above so we remove invalid items from stacks
12986            group.stack.retain(|id| final_selection_ids.contains(id));
12987
12988            // single selection in stack can be treated as initial state
12989            group.stack.len() > 1
12990        });
12991
12992        if !state.groups.is_empty() {
12993            self.add_selections_state = Some(state);
12994        }
12995    }
12996
12997    fn select_match_ranges(
12998        &mut self,
12999        range: Range<usize>,
13000        reversed: bool,
13001        replace_newest: bool,
13002        auto_scroll: Option<Autoscroll>,
13003        window: &mut Window,
13004        cx: &mut Context<Editor>,
13005    ) {
13006        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13007        self.change_selections(auto_scroll, window, cx, |s| {
13008            if replace_newest {
13009                s.delete(s.newest_anchor().id);
13010            }
13011            if reversed {
13012                s.insert_range(range.end..range.start);
13013            } else {
13014                s.insert_range(range);
13015            }
13016        });
13017    }
13018
13019    pub fn select_next_match_internal(
13020        &mut self,
13021        display_map: &DisplaySnapshot,
13022        replace_newest: bool,
13023        autoscroll: Option<Autoscroll>,
13024        window: &mut Window,
13025        cx: &mut Context<Self>,
13026    ) -> Result<()> {
13027        let buffer = &display_map.buffer_snapshot;
13028        let mut selections = self.selections.all::<usize>(cx);
13029        if let Some(mut select_next_state) = self.select_next_state.take() {
13030            let query = &select_next_state.query;
13031            if !select_next_state.done {
13032                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13033                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13034                let mut next_selected_range = None;
13035
13036                let bytes_after_last_selection =
13037                    buffer.bytes_in_range(last_selection.end..buffer.len());
13038                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13039                let query_matches = query
13040                    .stream_find_iter(bytes_after_last_selection)
13041                    .map(|result| (last_selection.end, result))
13042                    .chain(
13043                        query
13044                            .stream_find_iter(bytes_before_first_selection)
13045                            .map(|result| (0, result)),
13046                    );
13047
13048                for (start_offset, query_match) in query_matches {
13049                    let query_match = query_match.unwrap(); // can only fail due to I/O
13050                    let offset_range =
13051                        start_offset + query_match.start()..start_offset + query_match.end();
13052                    let display_range = offset_range.start.to_display_point(display_map)
13053                        ..offset_range.end.to_display_point(display_map);
13054
13055                    if !select_next_state.wordwise
13056                        || (!movement::is_inside_word(display_map, display_range.start)
13057                            && !movement::is_inside_word(display_map, display_range.end))
13058                    {
13059                        // TODO: This is n^2, because we might check all the selections
13060                        if !selections
13061                            .iter()
13062                            .any(|selection| selection.range().overlaps(&offset_range))
13063                        {
13064                            next_selected_range = Some(offset_range);
13065                            break;
13066                        }
13067                    }
13068                }
13069
13070                if let Some(next_selected_range) = next_selected_range {
13071                    self.select_match_ranges(
13072                        next_selected_range,
13073                        last_selection.reversed,
13074                        replace_newest,
13075                        autoscroll,
13076                        window,
13077                        cx,
13078                    );
13079                } else {
13080                    select_next_state.done = true;
13081                }
13082            }
13083
13084            self.select_next_state = Some(select_next_state);
13085        } else {
13086            let mut only_carets = true;
13087            let mut same_text_selected = true;
13088            let mut selected_text = None;
13089
13090            let mut selections_iter = selections.iter().peekable();
13091            while let Some(selection) = selections_iter.next() {
13092                if selection.start != selection.end {
13093                    only_carets = false;
13094                }
13095
13096                if same_text_selected {
13097                    if selected_text.is_none() {
13098                        selected_text =
13099                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13100                    }
13101
13102                    if let Some(next_selection) = selections_iter.peek() {
13103                        if next_selection.range().len() == selection.range().len() {
13104                            let next_selected_text = buffer
13105                                .text_for_range(next_selection.range())
13106                                .collect::<String>();
13107                            if Some(next_selected_text) != selected_text {
13108                                same_text_selected = false;
13109                                selected_text = None;
13110                            }
13111                        } else {
13112                            same_text_selected = false;
13113                            selected_text = None;
13114                        }
13115                    }
13116                }
13117            }
13118
13119            if only_carets {
13120                for selection in &mut selections {
13121                    let word_range = movement::surrounding_word(
13122                        display_map,
13123                        selection.start.to_display_point(display_map),
13124                    );
13125                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13126                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13127                    selection.goal = SelectionGoal::None;
13128                    selection.reversed = false;
13129                    self.select_match_ranges(
13130                        selection.start..selection.end,
13131                        selection.reversed,
13132                        replace_newest,
13133                        autoscroll,
13134                        window,
13135                        cx,
13136                    );
13137                }
13138
13139                if selections.len() == 1 {
13140                    let selection = selections
13141                        .last()
13142                        .expect("ensured that there's only one selection");
13143                    let query = buffer
13144                        .text_for_range(selection.start..selection.end)
13145                        .collect::<String>();
13146                    let is_empty = query.is_empty();
13147                    let select_state = SelectNextState {
13148                        query: AhoCorasick::new(&[query])?,
13149                        wordwise: true,
13150                        done: is_empty,
13151                    };
13152                    self.select_next_state = Some(select_state);
13153                } else {
13154                    self.select_next_state = None;
13155                }
13156            } else if let Some(selected_text) = selected_text {
13157                self.select_next_state = Some(SelectNextState {
13158                    query: AhoCorasick::new(&[selected_text])?,
13159                    wordwise: false,
13160                    done: false,
13161                });
13162                self.select_next_match_internal(
13163                    display_map,
13164                    replace_newest,
13165                    autoscroll,
13166                    window,
13167                    cx,
13168                )?;
13169            }
13170        }
13171        Ok(())
13172    }
13173
13174    pub fn select_all_matches(
13175        &mut self,
13176        _action: &SelectAllMatches,
13177        window: &mut Window,
13178        cx: &mut Context<Self>,
13179    ) -> Result<()> {
13180        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13181
13182        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13183
13184        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13185        let Some(select_next_state) = self.select_next_state.as_mut() else {
13186            return Ok(());
13187        };
13188        if select_next_state.done {
13189            return Ok(());
13190        }
13191
13192        let mut new_selections = Vec::new();
13193
13194        let reversed = self.selections.oldest::<usize>(cx).reversed;
13195        let buffer = &display_map.buffer_snapshot;
13196        let query_matches = select_next_state
13197            .query
13198            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13199
13200        for query_match in query_matches.into_iter() {
13201            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13202            let offset_range = if reversed {
13203                query_match.end()..query_match.start()
13204            } else {
13205                query_match.start()..query_match.end()
13206            };
13207            let display_range = offset_range.start.to_display_point(&display_map)
13208                ..offset_range.end.to_display_point(&display_map);
13209
13210            if !select_next_state.wordwise
13211                || (!movement::is_inside_word(&display_map, display_range.start)
13212                    && !movement::is_inside_word(&display_map, display_range.end))
13213            {
13214                new_selections.push(offset_range.start..offset_range.end);
13215            }
13216        }
13217
13218        select_next_state.done = true;
13219        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13220        self.change_selections(None, window, cx, |selections| {
13221            selections.select_ranges(new_selections)
13222        });
13223
13224        Ok(())
13225    }
13226
13227    pub fn select_next(
13228        &mut self,
13229        action: &SelectNext,
13230        window: &mut Window,
13231        cx: &mut Context<Self>,
13232    ) -> Result<()> {
13233        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13234        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13235        self.select_next_match_internal(
13236            &display_map,
13237            action.replace_newest,
13238            Some(Autoscroll::newest()),
13239            window,
13240            cx,
13241        )?;
13242        Ok(())
13243    }
13244
13245    pub fn select_previous(
13246        &mut self,
13247        action: &SelectPrevious,
13248        window: &mut Window,
13249        cx: &mut Context<Self>,
13250    ) -> Result<()> {
13251        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13252        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13253        let buffer = &display_map.buffer_snapshot;
13254        let mut selections = self.selections.all::<usize>(cx);
13255        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13256            let query = &select_prev_state.query;
13257            if !select_prev_state.done {
13258                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13259                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13260                let mut next_selected_range = None;
13261                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13262                let bytes_before_last_selection =
13263                    buffer.reversed_bytes_in_range(0..last_selection.start);
13264                let bytes_after_first_selection =
13265                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13266                let query_matches = query
13267                    .stream_find_iter(bytes_before_last_selection)
13268                    .map(|result| (last_selection.start, result))
13269                    .chain(
13270                        query
13271                            .stream_find_iter(bytes_after_first_selection)
13272                            .map(|result| (buffer.len(), result)),
13273                    );
13274                for (end_offset, query_match) in query_matches {
13275                    let query_match = query_match.unwrap(); // can only fail due to I/O
13276                    let offset_range =
13277                        end_offset - query_match.end()..end_offset - query_match.start();
13278                    let display_range = offset_range.start.to_display_point(&display_map)
13279                        ..offset_range.end.to_display_point(&display_map);
13280
13281                    if !select_prev_state.wordwise
13282                        || (!movement::is_inside_word(&display_map, display_range.start)
13283                            && !movement::is_inside_word(&display_map, display_range.end))
13284                    {
13285                        next_selected_range = Some(offset_range);
13286                        break;
13287                    }
13288                }
13289
13290                if let Some(next_selected_range) = next_selected_range {
13291                    self.select_match_ranges(
13292                        next_selected_range,
13293                        last_selection.reversed,
13294                        action.replace_newest,
13295                        Some(Autoscroll::newest()),
13296                        window,
13297                        cx,
13298                    );
13299                } else {
13300                    select_prev_state.done = true;
13301                }
13302            }
13303
13304            self.select_prev_state = Some(select_prev_state);
13305        } else {
13306            let mut only_carets = true;
13307            let mut same_text_selected = true;
13308            let mut selected_text = None;
13309
13310            let mut selections_iter = selections.iter().peekable();
13311            while let Some(selection) = selections_iter.next() {
13312                if selection.start != selection.end {
13313                    only_carets = false;
13314                }
13315
13316                if same_text_selected {
13317                    if selected_text.is_none() {
13318                        selected_text =
13319                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13320                    }
13321
13322                    if let Some(next_selection) = selections_iter.peek() {
13323                        if next_selection.range().len() == selection.range().len() {
13324                            let next_selected_text = buffer
13325                                .text_for_range(next_selection.range())
13326                                .collect::<String>();
13327                            if Some(next_selected_text) != selected_text {
13328                                same_text_selected = false;
13329                                selected_text = None;
13330                            }
13331                        } else {
13332                            same_text_selected = false;
13333                            selected_text = None;
13334                        }
13335                    }
13336                }
13337            }
13338
13339            if only_carets {
13340                for selection in &mut selections {
13341                    let word_range = movement::surrounding_word(
13342                        &display_map,
13343                        selection.start.to_display_point(&display_map),
13344                    );
13345                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13346                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13347                    selection.goal = SelectionGoal::None;
13348                    selection.reversed = false;
13349                    self.select_match_ranges(
13350                        selection.start..selection.end,
13351                        selection.reversed,
13352                        action.replace_newest,
13353                        Some(Autoscroll::newest()),
13354                        window,
13355                        cx,
13356                    );
13357                }
13358                if selections.len() == 1 {
13359                    let selection = selections
13360                        .last()
13361                        .expect("ensured that there's only one selection");
13362                    let query = buffer
13363                        .text_for_range(selection.start..selection.end)
13364                        .collect::<String>();
13365                    let is_empty = query.is_empty();
13366                    let select_state = SelectNextState {
13367                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13368                        wordwise: true,
13369                        done: is_empty,
13370                    };
13371                    self.select_prev_state = Some(select_state);
13372                } else {
13373                    self.select_prev_state = None;
13374                }
13375            } else if let Some(selected_text) = selected_text {
13376                self.select_prev_state = Some(SelectNextState {
13377                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13378                    wordwise: false,
13379                    done: false,
13380                });
13381                self.select_previous(action, window, cx)?;
13382            }
13383        }
13384        Ok(())
13385    }
13386
13387    pub fn find_next_match(
13388        &mut self,
13389        _: &FindNextMatch,
13390        window: &mut Window,
13391        cx: &mut Context<Self>,
13392    ) -> Result<()> {
13393        let selections = self.selections.disjoint_anchors();
13394        match selections.first() {
13395            Some(first) if selections.len() >= 2 => {
13396                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13397                    s.select_ranges([first.range()]);
13398                });
13399            }
13400            _ => self.select_next(
13401                &SelectNext {
13402                    replace_newest: true,
13403                },
13404                window,
13405                cx,
13406            )?,
13407        }
13408        Ok(())
13409    }
13410
13411    pub fn find_previous_match(
13412        &mut self,
13413        _: &FindPreviousMatch,
13414        window: &mut Window,
13415        cx: &mut Context<Self>,
13416    ) -> Result<()> {
13417        let selections = self.selections.disjoint_anchors();
13418        match selections.last() {
13419            Some(last) if selections.len() >= 2 => {
13420                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13421                    s.select_ranges([last.range()]);
13422                });
13423            }
13424            _ => self.select_previous(
13425                &SelectPrevious {
13426                    replace_newest: true,
13427                },
13428                window,
13429                cx,
13430            )?,
13431        }
13432        Ok(())
13433    }
13434
13435    pub fn toggle_comments(
13436        &mut self,
13437        action: &ToggleComments,
13438        window: &mut Window,
13439        cx: &mut Context<Self>,
13440    ) {
13441        if self.read_only(cx) {
13442            return;
13443        }
13444        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13445        let text_layout_details = &self.text_layout_details(window);
13446        self.transact(window, cx, |this, window, cx| {
13447            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13448            let mut edits = Vec::new();
13449            let mut selection_edit_ranges = Vec::new();
13450            let mut last_toggled_row = None;
13451            let snapshot = this.buffer.read(cx).read(cx);
13452            let empty_str: Arc<str> = Arc::default();
13453            let mut suffixes_inserted = Vec::new();
13454            let ignore_indent = action.ignore_indent;
13455
13456            fn comment_prefix_range(
13457                snapshot: &MultiBufferSnapshot,
13458                row: MultiBufferRow,
13459                comment_prefix: &str,
13460                comment_prefix_whitespace: &str,
13461                ignore_indent: bool,
13462            ) -> Range<Point> {
13463                let indent_size = if ignore_indent {
13464                    0
13465                } else {
13466                    snapshot.indent_size_for_line(row).len
13467                };
13468
13469                let start = Point::new(row.0, indent_size);
13470
13471                let mut line_bytes = snapshot
13472                    .bytes_in_range(start..snapshot.max_point())
13473                    .flatten()
13474                    .copied();
13475
13476                // If this line currently begins with the line comment prefix, then record
13477                // the range containing the prefix.
13478                if line_bytes
13479                    .by_ref()
13480                    .take(comment_prefix.len())
13481                    .eq(comment_prefix.bytes())
13482                {
13483                    // Include any whitespace that matches the comment prefix.
13484                    let matching_whitespace_len = line_bytes
13485                        .zip(comment_prefix_whitespace.bytes())
13486                        .take_while(|(a, b)| a == b)
13487                        .count() as u32;
13488                    let end = Point::new(
13489                        start.row,
13490                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13491                    );
13492                    start..end
13493                } else {
13494                    start..start
13495                }
13496            }
13497
13498            fn comment_suffix_range(
13499                snapshot: &MultiBufferSnapshot,
13500                row: MultiBufferRow,
13501                comment_suffix: &str,
13502                comment_suffix_has_leading_space: bool,
13503            ) -> Range<Point> {
13504                let end = Point::new(row.0, snapshot.line_len(row));
13505                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13506
13507                let mut line_end_bytes = snapshot
13508                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13509                    .flatten()
13510                    .copied();
13511
13512                let leading_space_len = if suffix_start_column > 0
13513                    && line_end_bytes.next() == Some(b' ')
13514                    && comment_suffix_has_leading_space
13515                {
13516                    1
13517                } else {
13518                    0
13519                };
13520
13521                // If this line currently begins with the line comment prefix, then record
13522                // the range containing the prefix.
13523                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13524                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13525                    start..end
13526                } else {
13527                    end..end
13528                }
13529            }
13530
13531            // TODO: Handle selections that cross excerpts
13532            for selection in &mut selections {
13533                let start_column = snapshot
13534                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13535                    .len;
13536                let language = if let Some(language) =
13537                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13538                {
13539                    language
13540                } else {
13541                    continue;
13542                };
13543
13544                selection_edit_ranges.clear();
13545
13546                // If multiple selections contain a given row, avoid processing that
13547                // row more than once.
13548                let mut start_row = MultiBufferRow(selection.start.row);
13549                if last_toggled_row == Some(start_row) {
13550                    start_row = start_row.next_row();
13551                }
13552                let end_row =
13553                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13554                        MultiBufferRow(selection.end.row - 1)
13555                    } else {
13556                        MultiBufferRow(selection.end.row)
13557                    };
13558                last_toggled_row = Some(end_row);
13559
13560                if start_row > end_row {
13561                    continue;
13562                }
13563
13564                // If the language has line comments, toggle those.
13565                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13566
13567                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13568                if ignore_indent {
13569                    full_comment_prefixes = full_comment_prefixes
13570                        .into_iter()
13571                        .map(|s| Arc::from(s.trim_end()))
13572                        .collect();
13573                }
13574
13575                if !full_comment_prefixes.is_empty() {
13576                    let first_prefix = full_comment_prefixes
13577                        .first()
13578                        .expect("prefixes is non-empty");
13579                    let prefix_trimmed_lengths = full_comment_prefixes
13580                        .iter()
13581                        .map(|p| p.trim_end_matches(' ').len())
13582                        .collect::<SmallVec<[usize; 4]>>();
13583
13584                    let mut all_selection_lines_are_comments = true;
13585
13586                    for row in start_row.0..=end_row.0 {
13587                        let row = MultiBufferRow(row);
13588                        if start_row < end_row && snapshot.is_line_blank(row) {
13589                            continue;
13590                        }
13591
13592                        let prefix_range = full_comment_prefixes
13593                            .iter()
13594                            .zip(prefix_trimmed_lengths.iter().copied())
13595                            .map(|(prefix, trimmed_prefix_len)| {
13596                                comment_prefix_range(
13597                                    snapshot.deref(),
13598                                    row,
13599                                    &prefix[..trimmed_prefix_len],
13600                                    &prefix[trimmed_prefix_len..],
13601                                    ignore_indent,
13602                                )
13603                            })
13604                            .max_by_key(|range| range.end.column - range.start.column)
13605                            .expect("prefixes is non-empty");
13606
13607                        if prefix_range.is_empty() {
13608                            all_selection_lines_are_comments = false;
13609                        }
13610
13611                        selection_edit_ranges.push(prefix_range);
13612                    }
13613
13614                    if all_selection_lines_are_comments {
13615                        edits.extend(
13616                            selection_edit_ranges
13617                                .iter()
13618                                .cloned()
13619                                .map(|range| (range, empty_str.clone())),
13620                        );
13621                    } else {
13622                        let min_column = selection_edit_ranges
13623                            .iter()
13624                            .map(|range| range.start.column)
13625                            .min()
13626                            .unwrap_or(0);
13627                        edits.extend(selection_edit_ranges.iter().map(|range| {
13628                            let position = Point::new(range.start.row, min_column);
13629                            (position..position, first_prefix.clone())
13630                        }));
13631                    }
13632                } else if let Some((full_comment_prefix, comment_suffix)) =
13633                    language.block_comment_delimiters()
13634                {
13635                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13636                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13637                    let prefix_range = comment_prefix_range(
13638                        snapshot.deref(),
13639                        start_row,
13640                        comment_prefix,
13641                        comment_prefix_whitespace,
13642                        ignore_indent,
13643                    );
13644                    let suffix_range = comment_suffix_range(
13645                        snapshot.deref(),
13646                        end_row,
13647                        comment_suffix.trim_start_matches(' '),
13648                        comment_suffix.starts_with(' '),
13649                    );
13650
13651                    if prefix_range.is_empty() || suffix_range.is_empty() {
13652                        edits.push((
13653                            prefix_range.start..prefix_range.start,
13654                            full_comment_prefix.clone(),
13655                        ));
13656                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13657                        suffixes_inserted.push((end_row, comment_suffix.len()));
13658                    } else {
13659                        edits.push((prefix_range, empty_str.clone()));
13660                        edits.push((suffix_range, empty_str.clone()));
13661                    }
13662                } else {
13663                    continue;
13664                }
13665            }
13666
13667            drop(snapshot);
13668            this.buffer.update(cx, |buffer, cx| {
13669                buffer.edit(edits, None, cx);
13670            });
13671
13672            // Adjust selections so that they end before any comment suffixes that
13673            // were inserted.
13674            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13675            let mut selections = this.selections.all::<Point>(cx);
13676            let snapshot = this.buffer.read(cx).read(cx);
13677            for selection in &mut selections {
13678                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13679                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13680                        Ordering::Less => {
13681                            suffixes_inserted.next();
13682                            continue;
13683                        }
13684                        Ordering::Greater => break,
13685                        Ordering::Equal => {
13686                            if selection.end.column == snapshot.line_len(row) {
13687                                if selection.is_empty() {
13688                                    selection.start.column -= suffix_len as u32;
13689                                }
13690                                selection.end.column -= suffix_len as u32;
13691                            }
13692                            break;
13693                        }
13694                    }
13695                }
13696            }
13697
13698            drop(snapshot);
13699            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13700                s.select(selections)
13701            });
13702
13703            let selections = this.selections.all::<Point>(cx);
13704            let selections_on_single_row = selections.windows(2).all(|selections| {
13705                selections[0].start.row == selections[1].start.row
13706                    && selections[0].end.row == selections[1].end.row
13707                    && selections[0].start.row == selections[0].end.row
13708            });
13709            let selections_selecting = selections
13710                .iter()
13711                .any(|selection| selection.start != selection.end);
13712            let advance_downwards = action.advance_downwards
13713                && selections_on_single_row
13714                && !selections_selecting
13715                && !matches!(this.mode, EditorMode::SingleLine { .. });
13716
13717            if advance_downwards {
13718                let snapshot = this.buffer.read(cx).snapshot(cx);
13719
13720                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13721                    s.move_cursors_with(|display_snapshot, display_point, _| {
13722                        let mut point = display_point.to_point(display_snapshot);
13723                        point.row += 1;
13724                        point = snapshot.clip_point(point, Bias::Left);
13725                        let display_point = point.to_display_point(display_snapshot);
13726                        let goal = SelectionGoal::HorizontalPosition(
13727                            display_snapshot
13728                                .x_for_display_point(display_point, text_layout_details)
13729                                .into(),
13730                        );
13731                        (display_point, goal)
13732                    })
13733                });
13734            }
13735        });
13736    }
13737
13738    pub fn select_enclosing_symbol(
13739        &mut self,
13740        _: &SelectEnclosingSymbol,
13741        window: &mut Window,
13742        cx: &mut Context<Self>,
13743    ) {
13744        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13745
13746        let buffer = self.buffer.read(cx).snapshot(cx);
13747        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13748
13749        fn update_selection(
13750            selection: &Selection<usize>,
13751            buffer_snap: &MultiBufferSnapshot,
13752        ) -> Option<Selection<usize>> {
13753            let cursor = selection.head();
13754            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13755            for symbol in symbols.iter().rev() {
13756                let start = symbol.range.start.to_offset(buffer_snap);
13757                let end = symbol.range.end.to_offset(buffer_snap);
13758                let new_range = start..end;
13759                if start < selection.start || end > selection.end {
13760                    return Some(Selection {
13761                        id: selection.id,
13762                        start: new_range.start,
13763                        end: new_range.end,
13764                        goal: SelectionGoal::None,
13765                        reversed: selection.reversed,
13766                    });
13767                }
13768            }
13769            None
13770        }
13771
13772        let mut selected_larger_symbol = false;
13773        let new_selections = old_selections
13774            .iter()
13775            .map(|selection| match update_selection(selection, &buffer) {
13776                Some(new_selection) => {
13777                    if new_selection.range() != selection.range() {
13778                        selected_larger_symbol = true;
13779                    }
13780                    new_selection
13781                }
13782                None => selection.clone(),
13783            })
13784            .collect::<Vec<_>>();
13785
13786        if selected_larger_symbol {
13787            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13788                s.select(new_selections);
13789            });
13790        }
13791    }
13792
13793    pub fn select_larger_syntax_node(
13794        &mut self,
13795        _: &SelectLargerSyntaxNode,
13796        window: &mut Window,
13797        cx: &mut Context<Self>,
13798    ) {
13799        let Some(visible_row_count) = self.visible_row_count() else {
13800            return;
13801        };
13802        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13803        if old_selections.is_empty() {
13804            return;
13805        }
13806
13807        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13808
13809        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13810        let buffer = self.buffer.read(cx).snapshot(cx);
13811
13812        let mut selected_larger_node = false;
13813        let mut new_selections = old_selections
13814            .iter()
13815            .map(|selection| {
13816                let old_range = selection.start..selection.end;
13817
13818                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13819                    // manually select word at selection
13820                    if ["string_content", "inline"].contains(&node.kind()) {
13821                        let word_range = {
13822                            let display_point = buffer
13823                                .offset_to_point(old_range.start)
13824                                .to_display_point(&display_map);
13825                            let Range { start, end } =
13826                                movement::surrounding_word(&display_map, display_point);
13827                            start.to_point(&display_map).to_offset(&buffer)
13828                                ..end.to_point(&display_map).to_offset(&buffer)
13829                        };
13830                        // ignore if word is already selected
13831                        if !word_range.is_empty() && old_range != word_range {
13832                            let last_word_range = {
13833                                let display_point = buffer
13834                                    .offset_to_point(old_range.end)
13835                                    .to_display_point(&display_map);
13836                                let Range { start, end } =
13837                                    movement::surrounding_word(&display_map, display_point);
13838                                start.to_point(&display_map).to_offset(&buffer)
13839                                    ..end.to_point(&display_map).to_offset(&buffer)
13840                            };
13841                            // only select word if start and end point belongs to same word
13842                            if word_range == last_word_range {
13843                                selected_larger_node = true;
13844                                return Selection {
13845                                    id: selection.id,
13846                                    start: word_range.start,
13847                                    end: word_range.end,
13848                                    goal: SelectionGoal::None,
13849                                    reversed: selection.reversed,
13850                                };
13851                            }
13852                        }
13853                    }
13854                }
13855
13856                let mut new_range = old_range.clone();
13857                while let Some((_node, containing_range)) =
13858                    buffer.syntax_ancestor(new_range.clone())
13859                {
13860                    new_range = match containing_range {
13861                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13862                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13863                    };
13864                    if !display_map.intersects_fold(new_range.start)
13865                        && !display_map.intersects_fold(new_range.end)
13866                    {
13867                        break;
13868                    }
13869                }
13870
13871                selected_larger_node |= new_range != old_range;
13872                Selection {
13873                    id: selection.id,
13874                    start: new_range.start,
13875                    end: new_range.end,
13876                    goal: SelectionGoal::None,
13877                    reversed: selection.reversed,
13878                }
13879            })
13880            .collect::<Vec<_>>();
13881
13882        if !selected_larger_node {
13883            return; // don't put this call in the history
13884        }
13885
13886        // scroll based on transformation done to the last selection created by the user
13887        let (last_old, last_new) = old_selections
13888            .last()
13889            .zip(new_selections.last().cloned())
13890            .expect("old_selections isn't empty");
13891
13892        // revert selection
13893        let is_selection_reversed = {
13894            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13895            new_selections.last_mut().expect("checked above").reversed =
13896                should_newest_selection_be_reversed;
13897            should_newest_selection_be_reversed
13898        };
13899
13900        if selected_larger_node {
13901            self.select_syntax_node_history.disable_clearing = true;
13902            self.change_selections(None, window, cx, |s| {
13903                s.select(new_selections.clone());
13904            });
13905            self.select_syntax_node_history.disable_clearing = false;
13906        }
13907
13908        let start_row = last_new.start.to_display_point(&display_map).row().0;
13909        let end_row = last_new.end.to_display_point(&display_map).row().0;
13910        let selection_height = end_row - start_row + 1;
13911        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13912
13913        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13914        let scroll_behavior = if fits_on_the_screen {
13915            self.request_autoscroll(Autoscroll::fit(), cx);
13916            SelectSyntaxNodeScrollBehavior::FitSelection
13917        } else if is_selection_reversed {
13918            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13919            SelectSyntaxNodeScrollBehavior::CursorTop
13920        } else {
13921            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13922            SelectSyntaxNodeScrollBehavior::CursorBottom
13923        };
13924
13925        self.select_syntax_node_history.push((
13926            old_selections,
13927            scroll_behavior,
13928            is_selection_reversed,
13929        ));
13930    }
13931
13932    pub fn select_smaller_syntax_node(
13933        &mut self,
13934        _: &SelectSmallerSyntaxNode,
13935        window: &mut Window,
13936        cx: &mut Context<Self>,
13937    ) {
13938        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13939
13940        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13941            self.select_syntax_node_history.pop()
13942        {
13943            if let Some(selection) = selections.last_mut() {
13944                selection.reversed = is_selection_reversed;
13945            }
13946
13947            self.select_syntax_node_history.disable_clearing = true;
13948            self.change_selections(None, window, cx, |s| {
13949                s.select(selections.to_vec());
13950            });
13951            self.select_syntax_node_history.disable_clearing = false;
13952
13953            match scroll_behavior {
13954                SelectSyntaxNodeScrollBehavior::CursorTop => {
13955                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13956                }
13957                SelectSyntaxNodeScrollBehavior::FitSelection => {
13958                    self.request_autoscroll(Autoscroll::fit(), cx);
13959                }
13960                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13961                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13962                }
13963            }
13964        }
13965    }
13966
13967    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13968        if !EditorSettings::get_global(cx).gutter.runnables {
13969            self.clear_tasks();
13970            return Task::ready(());
13971        }
13972        let project = self.project.as_ref().map(Entity::downgrade);
13973        let task_sources = self.lsp_task_sources(cx);
13974        let multi_buffer = self.buffer.downgrade();
13975        cx.spawn_in(window, async move |editor, cx| {
13976            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13977            let Some(project) = project.and_then(|p| p.upgrade()) else {
13978                return;
13979            };
13980            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13981                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13982            }) else {
13983                return;
13984            };
13985
13986            let hide_runnables = project
13987                .update(cx, |project, cx| {
13988                    // Do not display any test indicators in non-dev server remote projects.
13989                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13990                })
13991                .unwrap_or(true);
13992            if hide_runnables {
13993                return;
13994            }
13995            let new_rows =
13996                cx.background_spawn({
13997                    let snapshot = display_snapshot.clone();
13998                    async move {
13999                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14000                    }
14001                })
14002                    .await;
14003            let Ok(lsp_tasks) =
14004                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14005            else {
14006                return;
14007            };
14008            let lsp_tasks = lsp_tasks.await;
14009
14010            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14011                lsp_tasks
14012                    .into_iter()
14013                    .flat_map(|(kind, tasks)| {
14014                        tasks.into_iter().filter_map(move |(location, task)| {
14015                            Some((kind.clone(), location?, task))
14016                        })
14017                    })
14018                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14019                        let buffer = location.target.buffer;
14020                        let buffer_snapshot = buffer.read(cx).snapshot();
14021                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14022                            |(excerpt_id, snapshot, _)| {
14023                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14024                                    display_snapshot
14025                                        .buffer_snapshot
14026                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14027                                } else {
14028                                    None
14029                                }
14030                            },
14031                        );
14032                        if let Some(offset) = offset {
14033                            let task_buffer_range =
14034                                location.target.range.to_point(&buffer_snapshot);
14035                            let context_buffer_range =
14036                                task_buffer_range.to_offset(&buffer_snapshot);
14037                            let context_range = BufferOffset(context_buffer_range.start)
14038                                ..BufferOffset(context_buffer_range.end);
14039
14040                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14041                                .or_insert_with(|| RunnableTasks {
14042                                    templates: Vec::new(),
14043                                    offset,
14044                                    column: task_buffer_range.start.column,
14045                                    extra_variables: HashMap::default(),
14046                                    context_range,
14047                                })
14048                                .templates
14049                                .push((kind, task.original_task().clone()));
14050                        }
14051
14052                        acc
14053                    })
14054            }) else {
14055                return;
14056            };
14057
14058            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14059                buffer.language_settings(cx).tasks.prefer_lsp
14060            }) else {
14061                return;
14062            };
14063
14064            let rows = Self::runnable_rows(
14065                project,
14066                display_snapshot,
14067                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14068                new_rows,
14069                cx.clone(),
14070            )
14071            .await;
14072            editor
14073                .update(cx, |editor, _| {
14074                    editor.clear_tasks();
14075                    for (key, mut value) in rows {
14076                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14077                            value.templates.extend(lsp_tasks.templates);
14078                        }
14079
14080                        editor.insert_tasks(key, value);
14081                    }
14082                    for (key, value) in lsp_tasks_by_rows {
14083                        editor.insert_tasks(key, value);
14084                    }
14085                })
14086                .ok();
14087        })
14088    }
14089    fn fetch_runnable_ranges(
14090        snapshot: &DisplaySnapshot,
14091        range: Range<Anchor>,
14092    ) -> Vec<language::RunnableRange> {
14093        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14094    }
14095
14096    fn runnable_rows(
14097        project: Entity<Project>,
14098        snapshot: DisplaySnapshot,
14099        prefer_lsp: bool,
14100        runnable_ranges: Vec<RunnableRange>,
14101        cx: AsyncWindowContext,
14102    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14103        cx.spawn(async move |cx| {
14104            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14105            for mut runnable in runnable_ranges {
14106                let Some(tasks) = cx
14107                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14108                    .ok()
14109                else {
14110                    continue;
14111                };
14112                let mut tasks = tasks.await;
14113
14114                if prefer_lsp {
14115                    tasks.retain(|(task_kind, _)| {
14116                        !matches!(task_kind, TaskSourceKind::Language { .. })
14117                    });
14118                }
14119                if tasks.is_empty() {
14120                    continue;
14121                }
14122
14123                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14124                let Some(row) = snapshot
14125                    .buffer_snapshot
14126                    .buffer_line_for_row(MultiBufferRow(point.row))
14127                    .map(|(_, range)| range.start.row)
14128                else {
14129                    continue;
14130                };
14131
14132                let context_range =
14133                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14134                runnable_rows.push((
14135                    (runnable.buffer_id, row),
14136                    RunnableTasks {
14137                        templates: tasks,
14138                        offset: snapshot
14139                            .buffer_snapshot
14140                            .anchor_before(runnable.run_range.start),
14141                        context_range,
14142                        column: point.column,
14143                        extra_variables: runnable.extra_captures,
14144                    },
14145                ));
14146            }
14147            runnable_rows
14148        })
14149    }
14150
14151    fn templates_with_tags(
14152        project: &Entity<Project>,
14153        runnable: &mut Runnable,
14154        cx: &mut App,
14155    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14156        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14157            let (worktree_id, file) = project
14158                .buffer_for_id(runnable.buffer, cx)
14159                .and_then(|buffer| buffer.read(cx).file())
14160                .map(|file| (file.worktree_id(cx), file.clone()))
14161                .unzip();
14162
14163            (
14164                project.task_store().read(cx).task_inventory().cloned(),
14165                worktree_id,
14166                file,
14167            )
14168        });
14169
14170        let tags = mem::take(&mut runnable.tags);
14171        let language = runnable.language.clone();
14172        cx.spawn(async move |cx| {
14173            let mut templates_with_tags = Vec::new();
14174            if let Some(inventory) = inventory {
14175                for RunnableTag(tag) in tags {
14176                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14177                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14178                    }) else {
14179                        return templates_with_tags;
14180                    };
14181                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14182                        move |(_, template)| {
14183                            template.tags.iter().any(|source_tag| source_tag == &tag)
14184                        },
14185                    ));
14186                }
14187            }
14188            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14189
14190            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14191                // Strongest source wins; if we have worktree tag binding, prefer that to
14192                // global and language bindings;
14193                // if we have a global binding, prefer that to language binding.
14194                let first_mismatch = templates_with_tags
14195                    .iter()
14196                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14197                if let Some(index) = first_mismatch {
14198                    templates_with_tags.truncate(index);
14199                }
14200            }
14201
14202            templates_with_tags
14203        })
14204    }
14205
14206    pub fn move_to_enclosing_bracket(
14207        &mut self,
14208        _: &MoveToEnclosingBracket,
14209        window: &mut Window,
14210        cx: &mut Context<Self>,
14211    ) {
14212        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14213        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14214            s.move_offsets_with(|snapshot, selection| {
14215                let Some(enclosing_bracket_ranges) =
14216                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14217                else {
14218                    return;
14219                };
14220
14221                let mut best_length = usize::MAX;
14222                let mut best_inside = false;
14223                let mut best_in_bracket_range = false;
14224                let mut best_destination = None;
14225                for (open, close) in enclosing_bracket_ranges {
14226                    let close = close.to_inclusive();
14227                    let length = close.end() - open.start;
14228                    let inside = selection.start >= open.end && selection.end <= *close.start();
14229                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14230                        || close.contains(&selection.head());
14231
14232                    // If best is next to a bracket and current isn't, skip
14233                    if !in_bracket_range && best_in_bracket_range {
14234                        continue;
14235                    }
14236
14237                    // Prefer smaller lengths unless best is inside and current isn't
14238                    if length > best_length && (best_inside || !inside) {
14239                        continue;
14240                    }
14241
14242                    best_length = length;
14243                    best_inside = inside;
14244                    best_in_bracket_range = in_bracket_range;
14245                    best_destination = Some(
14246                        if close.contains(&selection.start) && close.contains(&selection.end) {
14247                            if inside { open.end } else { open.start }
14248                        } else if inside {
14249                            *close.start()
14250                        } else {
14251                            *close.end()
14252                        },
14253                    );
14254                }
14255
14256                if let Some(destination) = best_destination {
14257                    selection.collapse_to(destination, SelectionGoal::None);
14258                }
14259            })
14260        });
14261    }
14262
14263    pub fn undo_selection(
14264        &mut self,
14265        _: &UndoSelection,
14266        window: &mut Window,
14267        cx: &mut Context<Self>,
14268    ) {
14269        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14270        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14271            self.selection_history.mode = SelectionHistoryMode::Undoing;
14272            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14273                this.end_selection(window, cx);
14274                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14275                    s.select_anchors(entry.selections.to_vec())
14276                });
14277            });
14278            self.selection_history.mode = SelectionHistoryMode::Normal;
14279
14280            self.select_next_state = entry.select_next_state;
14281            self.select_prev_state = entry.select_prev_state;
14282            self.add_selections_state = entry.add_selections_state;
14283        }
14284    }
14285
14286    pub fn redo_selection(
14287        &mut self,
14288        _: &RedoSelection,
14289        window: &mut Window,
14290        cx: &mut Context<Self>,
14291    ) {
14292        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14293        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14294            self.selection_history.mode = SelectionHistoryMode::Redoing;
14295            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14296                this.end_selection(window, cx);
14297                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14298                    s.select_anchors(entry.selections.to_vec())
14299                });
14300            });
14301            self.selection_history.mode = SelectionHistoryMode::Normal;
14302
14303            self.select_next_state = entry.select_next_state;
14304            self.select_prev_state = entry.select_prev_state;
14305            self.add_selections_state = entry.add_selections_state;
14306        }
14307    }
14308
14309    pub fn expand_excerpts(
14310        &mut self,
14311        action: &ExpandExcerpts,
14312        _: &mut Window,
14313        cx: &mut Context<Self>,
14314    ) {
14315        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14316    }
14317
14318    pub fn expand_excerpts_down(
14319        &mut self,
14320        action: &ExpandExcerptsDown,
14321        _: &mut Window,
14322        cx: &mut Context<Self>,
14323    ) {
14324        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14325    }
14326
14327    pub fn expand_excerpts_up(
14328        &mut self,
14329        action: &ExpandExcerptsUp,
14330        _: &mut Window,
14331        cx: &mut Context<Self>,
14332    ) {
14333        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14334    }
14335
14336    pub fn expand_excerpts_for_direction(
14337        &mut self,
14338        lines: u32,
14339        direction: ExpandExcerptDirection,
14340
14341        cx: &mut Context<Self>,
14342    ) {
14343        let selections = self.selections.disjoint_anchors();
14344
14345        let lines = if lines == 0 {
14346            EditorSettings::get_global(cx).expand_excerpt_lines
14347        } else {
14348            lines
14349        };
14350
14351        self.buffer.update(cx, |buffer, cx| {
14352            let snapshot = buffer.snapshot(cx);
14353            let mut excerpt_ids = selections
14354                .iter()
14355                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14356                .collect::<Vec<_>>();
14357            excerpt_ids.sort();
14358            excerpt_ids.dedup();
14359            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14360        })
14361    }
14362
14363    pub fn expand_excerpt(
14364        &mut self,
14365        excerpt: ExcerptId,
14366        direction: ExpandExcerptDirection,
14367        window: &mut Window,
14368        cx: &mut Context<Self>,
14369    ) {
14370        let current_scroll_position = self.scroll_position(cx);
14371        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14372        let mut should_scroll_up = false;
14373
14374        if direction == ExpandExcerptDirection::Down {
14375            let multi_buffer = self.buffer.read(cx);
14376            let snapshot = multi_buffer.snapshot(cx);
14377            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14378                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14379                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14380                        let buffer_snapshot = buffer.read(cx).snapshot();
14381                        let excerpt_end_row =
14382                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14383                        let last_row = buffer_snapshot.max_point().row;
14384                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14385                        should_scroll_up = lines_below >= lines_to_expand;
14386                    }
14387                }
14388            }
14389        }
14390
14391        self.buffer.update(cx, |buffer, cx| {
14392            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14393        });
14394
14395        if should_scroll_up {
14396            let new_scroll_position =
14397                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14398            self.set_scroll_position(new_scroll_position, window, cx);
14399        }
14400    }
14401
14402    pub fn go_to_singleton_buffer_point(
14403        &mut self,
14404        point: Point,
14405        window: &mut Window,
14406        cx: &mut Context<Self>,
14407    ) {
14408        self.go_to_singleton_buffer_range(point..point, window, cx);
14409    }
14410
14411    pub fn go_to_singleton_buffer_range(
14412        &mut self,
14413        range: Range<Point>,
14414        window: &mut Window,
14415        cx: &mut Context<Self>,
14416    ) {
14417        let multibuffer = self.buffer().read(cx);
14418        let Some(buffer) = multibuffer.as_singleton() else {
14419            return;
14420        };
14421        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14422            return;
14423        };
14424        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14425            return;
14426        };
14427        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14428            s.select_anchor_ranges([start..end])
14429        });
14430    }
14431
14432    pub fn go_to_diagnostic(
14433        &mut self,
14434        _: &GoToDiagnostic,
14435        window: &mut Window,
14436        cx: &mut Context<Self>,
14437    ) {
14438        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14439        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14440    }
14441
14442    pub fn go_to_prev_diagnostic(
14443        &mut self,
14444        _: &GoToPreviousDiagnostic,
14445        window: &mut Window,
14446        cx: &mut Context<Self>,
14447    ) {
14448        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14449        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14450    }
14451
14452    pub fn go_to_diagnostic_impl(
14453        &mut self,
14454        direction: Direction,
14455        window: &mut Window,
14456        cx: &mut Context<Self>,
14457    ) {
14458        let buffer = self.buffer.read(cx).snapshot(cx);
14459        let selection = self.selections.newest::<usize>(cx);
14460
14461        let mut active_group_id = None;
14462        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14463            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14464                active_group_id = Some(active_group.group_id);
14465            }
14466        }
14467
14468        fn filtered(
14469            snapshot: EditorSnapshot,
14470            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14471        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14472            diagnostics
14473                .filter(|entry| entry.range.start != entry.range.end)
14474                .filter(|entry| !entry.diagnostic.is_unnecessary)
14475                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14476        }
14477
14478        let snapshot = self.snapshot(window, cx);
14479        let before = filtered(
14480            snapshot.clone(),
14481            buffer
14482                .diagnostics_in_range(0..selection.start)
14483                .filter(|entry| entry.range.start <= selection.start),
14484        );
14485        let after = filtered(
14486            snapshot,
14487            buffer
14488                .diagnostics_in_range(selection.start..buffer.len())
14489                .filter(|entry| entry.range.start >= selection.start),
14490        );
14491
14492        let mut found: Option<DiagnosticEntry<usize>> = None;
14493        if direction == Direction::Prev {
14494            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14495            {
14496                for diagnostic in prev_diagnostics.into_iter().rev() {
14497                    if diagnostic.range.start != selection.start
14498                        || active_group_id
14499                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14500                    {
14501                        found = Some(diagnostic);
14502                        break 'outer;
14503                    }
14504                }
14505            }
14506        } else {
14507            for diagnostic in after.chain(before) {
14508                if diagnostic.range.start != selection.start
14509                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14510                {
14511                    found = Some(diagnostic);
14512                    break;
14513                }
14514            }
14515        }
14516        let Some(next_diagnostic) = found else {
14517            return;
14518        };
14519
14520        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14521            return;
14522        };
14523        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14524            s.select_ranges(vec![
14525                next_diagnostic.range.start..next_diagnostic.range.start,
14526            ])
14527        });
14528        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14529        self.refresh_inline_completion(false, true, window, cx);
14530    }
14531
14532    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14533        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14534        let snapshot = self.snapshot(window, cx);
14535        let selection = self.selections.newest::<Point>(cx);
14536        self.go_to_hunk_before_or_after_position(
14537            &snapshot,
14538            selection.head(),
14539            Direction::Next,
14540            window,
14541            cx,
14542        );
14543    }
14544
14545    pub fn go_to_hunk_before_or_after_position(
14546        &mut self,
14547        snapshot: &EditorSnapshot,
14548        position: Point,
14549        direction: Direction,
14550        window: &mut Window,
14551        cx: &mut Context<Editor>,
14552    ) {
14553        let row = if direction == Direction::Next {
14554            self.hunk_after_position(snapshot, position)
14555                .map(|hunk| hunk.row_range.start)
14556        } else {
14557            self.hunk_before_position(snapshot, position)
14558        };
14559
14560        if let Some(row) = row {
14561            let destination = Point::new(row.0, 0);
14562            let autoscroll = Autoscroll::center();
14563
14564            self.unfold_ranges(&[destination..destination], false, false, cx);
14565            self.change_selections(Some(autoscroll), window, cx, |s| {
14566                s.select_ranges([destination..destination]);
14567            });
14568        }
14569    }
14570
14571    fn hunk_after_position(
14572        &mut self,
14573        snapshot: &EditorSnapshot,
14574        position: Point,
14575    ) -> Option<MultiBufferDiffHunk> {
14576        snapshot
14577            .buffer_snapshot
14578            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14579            .find(|hunk| hunk.row_range.start.0 > position.row)
14580            .or_else(|| {
14581                snapshot
14582                    .buffer_snapshot
14583                    .diff_hunks_in_range(Point::zero()..position)
14584                    .find(|hunk| hunk.row_range.end.0 < position.row)
14585            })
14586    }
14587
14588    fn go_to_prev_hunk(
14589        &mut self,
14590        _: &GoToPreviousHunk,
14591        window: &mut Window,
14592        cx: &mut Context<Self>,
14593    ) {
14594        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14595        let snapshot = self.snapshot(window, cx);
14596        let selection = self.selections.newest::<Point>(cx);
14597        self.go_to_hunk_before_or_after_position(
14598            &snapshot,
14599            selection.head(),
14600            Direction::Prev,
14601            window,
14602            cx,
14603        );
14604    }
14605
14606    fn hunk_before_position(
14607        &mut self,
14608        snapshot: &EditorSnapshot,
14609        position: Point,
14610    ) -> Option<MultiBufferRow> {
14611        snapshot
14612            .buffer_snapshot
14613            .diff_hunk_before(position)
14614            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14615    }
14616
14617    fn go_to_next_change(
14618        &mut self,
14619        _: &GoToNextChange,
14620        window: &mut Window,
14621        cx: &mut Context<Self>,
14622    ) {
14623        if let Some(selections) = self
14624            .change_list
14625            .next_change(1, Direction::Next)
14626            .map(|s| s.to_vec())
14627        {
14628            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14629                let map = s.display_map();
14630                s.select_display_ranges(selections.iter().map(|a| {
14631                    let point = a.to_display_point(&map);
14632                    point..point
14633                }))
14634            })
14635        }
14636    }
14637
14638    fn go_to_previous_change(
14639        &mut self,
14640        _: &GoToPreviousChange,
14641        window: &mut Window,
14642        cx: &mut Context<Self>,
14643    ) {
14644        if let Some(selections) = self
14645            .change_list
14646            .next_change(1, Direction::Prev)
14647            .map(|s| s.to_vec())
14648        {
14649            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14650                let map = s.display_map();
14651                s.select_display_ranges(selections.iter().map(|a| {
14652                    let point = a.to_display_point(&map);
14653                    point..point
14654                }))
14655            })
14656        }
14657    }
14658
14659    fn go_to_line<T: 'static>(
14660        &mut self,
14661        position: Anchor,
14662        highlight_color: Option<Hsla>,
14663        window: &mut Window,
14664        cx: &mut Context<Self>,
14665    ) {
14666        let snapshot = self.snapshot(window, cx).display_snapshot;
14667        let position = position.to_point(&snapshot.buffer_snapshot);
14668        let start = snapshot
14669            .buffer_snapshot
14670            .clip_point(Point::new(position.row, 0), Bias::Left);
14671        let end = start + Point::new(1, 0);
14672        let start = snapshot.buffer_snapshot.anchor_before(start);
14673        let end = snapshot.buffer_snapshot.anchor_before(end);
14674
14675        self.highlight_rows::<T>(
14676            start..end,
14677            highlight_color
14678                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14679            Default::default(),
14680            cx,
14681        );
14682
14683        if self.buffer.read(cx).is_singleton() {
14684            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14685        }
14686    }
14687
14688    pub fn go_to_definition(
14689        &mut self,
14690        _: &GoToDefinition,
14691        window: &mut Window,
14692        cx: &mut Context<Self>,
14693    ) -> Task<Result<Navigated>> {
14694        let definition =
14695            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14696        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14697        cx.spawn_in(window, async move |editor, cx| {
14698            if definition.await? == Navigated::Yes {
14699                return Ok(Navigated::Yes);
14700            }
14701            match fallback_strategy {
14702                GoToDefinitionFallback::None => Ok(Navigated::No),
14703                GoToDefinitionFallback::FindAllReferences => {
14704                    match editor.update_in(cx, |editor, window, cx| {
14705                        editor.find_all_references(&FindAllReferences, window, cx)
14706                    })? {
14707                        Some(references) => references.await,
14708                        None => Ok(Navigated::No),
14709                    }
14710                }
14711            }
14712        })
14713    }
14714
14715    pub fn go_to_declaration(
14716        &mut self,
14717        _: &GoToDeclaration,
14718        window: &mut Window,
14719        cx: &mut Context<Self>,
14720    ) -> Task<Result<Navigated>> {
14721        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14722    }
14723
14724    pub fn go_to_declaration_split(
14725        &mut self,
14726        _: &GoToDeclaration,
14727        window: &mut Window,
14728        cx: &mut Context<Self>,
14729    ) -> Task<Result<Navigated>> {
14730        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14731    }
14732
14733    pub fn go_to_implementation(
14734        &mut self,
14735        _: &GoToImplementation,
14736        window: &mut Window,
14737        cx: &mut Context<Self>,
14738    ) -> Task<Result<Navigated>> {
14739        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14740    }
14741
14742    pub fn go_to_implementation_split(
14743        &mut self,
14744        _: &GoToImplementationSplit,
14745        window: &mut Window,
14746        cx: &mut Context<Self>,
14747    ) -> Task<Result<Navigated>> {
14748        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14749    }
14750
14751    pub fn go_to_type_definition(
14752        &mut self,
14753        _: &GoToTypeDefinition,
14754        window: &mut Window,
14755        cx: &mut Context<Self>,
14756    ) -> Task<Result<Navigated>> {
14757        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14758    }
14759
14760    pub fn go_to_definition_split(
14761        &mut self,
14762        _: &GoToDefinitionSplit,
14763        window: &mut Window,
14764        cx: &mut Context<Self>,
14765    ) -> Task<Result<Navigated>> {
14766        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14767    }
14768
14769    pub fn go_to_type_definition_split(
14770        &mut self,
14771        _: &GoToTypeDefinitionSplit,
14772        window: &mut Window,
14773        cx: &mut Context<Self>,
14774    ) -> Task<Result<Navigated>> {
14775        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14776    }
14777
14778    fn go_to_definition_of_kind(
14779        &mut self,
14780        kind: GotoDefinitionKind,
14781        split: bool,
14782        window: &mut Window,
14783        cx: &mut Context<Self>,
14784    ) -> Task<Result<Navigated>> {
14785        let Some(provider) = self.semantics_provider.clone() else {
14786            return Task::ready(Ok(Navigated::No));
14787        };
14788        let head = self.selections.newest::<usize>(cx).head();
14789        let buffer = self.buffer.read(cx);
14790        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14791            text_anchor
14792        } else {
14793            return Task::ready(Ok(Navigated::No));
14794        };
14795
14796        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14797            return Task::ready(Ok(Navigated::No));
14798        };
14799
14800        cx.spawn_in(window, async move |editor, cx| {
14801            let definitions = definitions.await?;
14802            let navigated = editor
14803                .update_in(cx, |editor, window, cx| {
14804                    editor.navigate_to_hover_links(
14805                        Some(kind),
14806                        definitions
14807                            .into_iter()
14808                            .filter(|location| {
14809                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14810                            })
14811                            .map(HoverLink::Text)
14812                            .collect::<Vec<_>>(),
14813                        split,
14814                        window,
14815                        cx,
14816                    )
14817                })?
14818                .await?;
14819            anyhow::Ok(navigated)
14820        })
14821    }
14822
14823    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14824        let selection = self.selections.newest_anchor();
14825        let head = selection.head();
14826        let tail = selection.tail();
14827
14828        let Some((buffer, start_position)) =
14829            self.buffer.read(cx).text_anchor_for_position(head, cx)
14830        else {
14831            return;
14832        };
14833
14834        let end_position = if head != tail {
14835            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14836                return;
14837            };
14838            Some(pos)
14839        } else {
14840            None
14841        };
14842
14843        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14844            let url = if let Some(end_pos) = end_position {
14845                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14846            } else {
14847                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14848            };
14849
14850            if let Some(url) = url {
14851                editor.update(cx, |_, cx| {
14852                    cx.open_url(&url);
14853                })
14854            } else {
14855                Ok(())
14856            }
14857        });
14858
14859        url_finder.detach();
14860    }
14861
14862    pub fn open_selected_filename(
14863        &mut self,
14864        _: &OpenSelectedFilename,
14865        window: &mut Window,
14866        cx: &mut Context<Self>,
14867    ) {
14868        let Some(workspace) = self.workspace() else {
14869            return;
14870        };
14871
14872        let position = self.selections.newest_anchor().head();
14873
14874        let Some((buffer, buffer_position)) =
14875            self.buffer.read(cx).text_anchor_for_position(position, cx)
14876        else {
14877            return;
14878        };
14879
14880        let project = self.project.clone();
14881
14882        cx.spawn_in(window, async move |_, cx| {
14883            let result = find_file(&buffer, project, buffer_position, cx).await;
14884
14885            if let Some((_, path)) = result {
14886                workspace
14887                    .update_in(cx, |workspace, window, cx| {
14888                        workspace.open_resolved_path(path, window, cx)
14889                    })?
14890                    .await?;
14891            }
14892            anyhow::Ok(())
14893        })
14894        .detach();
14895    }
14896
14897    pub(crate) fn navigate_to_hover_links(
14898        &mut self,
14899        kind: Option<GotoDefinitionKind>,
14900        mut definitions: Vec<HoverLink>,
14901        split: bool,
14902        window: &mut Window,
14903        cx: &mut Context<Editor>,
14904    ) -> Task<Result<Navigated>> {
14905        // If there is one definition, just open it directly
14906        if definitions.len() == 1 {
14907            let definition = definitions.pop().unwrap();
14908
14909            enum TargetTaskResult {
14910                Location(Option<Location>),
14911                AlreadyNavigated,
14912            }
14913
14914            let target_task = match definition {
14915                HoverLink::Text(link) => {
14916                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14917                }
14918                HoverLink::InlayHint(lsp_location, server_id) => {
14919                    let computation =
14920                        self.compute_target_location(lsp_location, server_id, window, cx);
14921                    cx.background_spawn(async move {
14922                        let location = computation.await?;
14923                        Ok(TargetTaskResult::Location(location))
14924                    })
14925                }
14926                HoverLink::Url(url) => {
14927                    cx.open_url(&url);
14928                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14929                }
14930                HoverLink::File(path) => {
14931                    if let Some(workspace) = self.workspace() {
14932                        cx.spawn_in(window, async move |_, cx| {
14933                            workspace
14934                                .update_in(cx, |workspace, window, cx| {
14935                                    workspace.open_resolved_path(path, window, cx)
14936                                })?
14937                                .await
14938                                .map(|_| TargetTaskResult::AlreadyNavigated)
14939                        })
14940                    } else {
14941                        Task::ready(Ok(TargetTaskResult::Location(None)))
14942                    }
14943                }
14944            };
14945            cx.spawn_in(window, async move |editor, cx| {
14946                let target = match target_task.await.context("target resolution task")? {
14947                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14948                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14949                    TargetTaskResult::Location(Some(target)) => target,
14950                };
14951
14952                editor.update_in(cx, |editor, window, cx| {
14953                    let Some(workspace) = editor.workspace() else {
14954                        return Navigated::No;
14955                    };
14956                    let pane = workspace.read(cx).active_pane().clone();
14957
14958                    let range = target.range.to_point(target.buffer.read(cx));
14959                    let range = editor.range_for_match(&range);
14960                    let range = collapse_multiline_range(range);
14961
14962                    if !split
14963                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14964                    {
14965                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14966                    } else {
14967                        window.defer(cx, move |window, cx| {
14968                            let target_editor: Entity<Self> =
14969                                workspace.update(cx, |workspace, cx| {
14970                                    let pane = if split {
14971                                        workspace.adjacent_pane(window, cx)
14972                                    } else {
14973                                        workspace.active_pane().clone()
14974                                    };
14975
14976                                    workspace.open_project_item(
14977                                        pane,
14978                                        target.buffer.clone(),
14979                                        true,
14980                                        true,
14981                                        window,
14982                                        cx,
14983                                    )
14984                                });
14985                            target_editor.update(cx, |target_editor, cx| {
14986                                // When selecting a definition in a different buffer, disable the nav history
14987                                // to avoid creating a history entry at the previous cursor location.
14988                                pane.update(cx, |pane, _| pane.disable_history());
14989                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14990                                pane.update(cx, |pane, _| pane.enable_history());
14991                            });
14992                        });
14993                    }
14994                    Navigated::Yes
14995                })
14996            })
14997        } else if !definitions.is_empty() {
14998            cx.spawn_in(window, async move |editor, cx| {
14999                let (title, location_tasks, workspace) = editor
15000                    .update_in(cx, |editor, window, cx| {
15001                        let tab_kind = match kind {
15002                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15003                            _ => "Definitions",
15004                        };
15005                        let title = definitions
15006                            .iter()
15007                            .find_map(|definition| match definition {
15008                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15009                                    let buffer = origin.buffer.read(cx);
15010                                    format!(
15011                                        "{} for {}",
15012                                        tab_kind,
15013                                        buffer
15014                                            .text_for_range(origin.range.clone())
15015                                            .collect::<String>()
15016                                    )
15017                                }),
15018                                HoverLink::InlayHint(_, _) => None,
15019                                HoverLink::Url(_) => None,
15020                                HoverLink::File(_) => None,
15021                            })
15022                            .unwrap_or(tab_kind.to_string());
15023                        let location_tasks = definitions
15024                            .into_iter()
15025                            .map(|definition| match definition {
15026                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15027                                HoverLink::InlayHint(lsp_location, server_id) => editor
15028                                    .compute_target_location(lsp_location, server_id, window, cx),
15029                                HoverLink::Url(_) => Task::ready(Ok(None)),
15030                                HoverLink::File(_) => Task::ready(Ok(None)),
15031                            })
15032                            .collect::<Vec<_>>();
15033                        (title, location_tasks, editor.workspace().clone())
15034                    })
15035                    .context("location tasks preparation")?;
15036
15037                let locations = future::join_all(location_tasks)
15038                    .await
15039                    .into_iter()
15040                    .filter_map(|location| location.transpose())
15041                    .collect::<Result<_>>()
15042                    .context("location tasks")?;
15043
15044                let Some(workspace) = workspace else {
15045                    return Ok(Navigated::No);
15046                };
15047                let opened = workspace
15048                    .update_in(cx, |workspace, window, cx| {
15049                        Self::open_locations_in_multibuffer(
15050                            workspace,
15051                            locations,
15052                            title,
15053                            split,
15054                            MultibufferSelectionMode::First,
15055                            window,
15056                            cx,
15057                        )
15058                    })
15059                    .ok();
15060
15061                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15062            })
15063        } else {
15064            Task::ready(Ok(Navigated::No))
15065        }
15066    }
15067
15068    fn compute_target_location(
15069        &self,
15070        lsp_location: lsp::Location,
15071        server_id: LanguageServerId,
15072        window: &mut Window,
15073        cx: &mut Context<Self>,
15074    ) -> Task<anyhow::Result<Option<Location>>> {
15075        let Some(project) = self.project.clone() else {
15076            return Task::ready(Ok(None));
15077        };
15078
15079        cx.spawn_in(window, async move |editor, cx| {
15080            let location_task = editor.update(cx, |_, cx| {
15081                project.update(cx, |project, cx| {
15082                    let language_server_name = project
15083                        .language_server_statuses(cx)
15084                        .find(|(id, _)| server_id == *id)
15085                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15086                    language_server_name.map(|language_server_name| {
15087                        project.open_local_buffer_via_lsp(
15088                            lsp_location.uri.clone(),
15089                            server_id,
15090                            language_server_name,
15091                            cx,
15092                        )
15093                    })
15094                })
15095            })?;
15096            let location = match location_task {
15097                Some(task) => Some({
15098                    let target_buffer_handle = task.await.context("open local buffer")?;
15099                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15100                        let target_start = target_buffer
15101                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15102                        let target_end = target_buffer
15103                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15104                        target_buffer.anchor_after(target_start)
15105                            ..target_buffer.anchor_before(target_end)
15106                    })?;
15107                    Location {
15108                        buffer: target_buffer_handle,
15109                        range,
15110                    }
15111                }),
15112                None => None,
15113            };
15114            Ok(location)
15115        })
15116    }
15117
15118    pub fn find_all_references(
15119        &mut self,
15120        _: &FindAllReferences,
15121        window: &mut Window,
15122        cx: &mut Context<Self>,
15123    ) -> Option<Task<Result<Navigated>>> {
15124        let selection = self.selections.newest::<usize>(cx);
15125        let multi_buffer = self.buffer.read(cx);
15126        let head = selection.head();
15127
15128        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15129        let head_anchor = multi_buffer_snapshot.anchor_at(
15130            head,
15131            if head < selection.tail() {
15132                Bias::Right
15133            } else {
15134                Bias::Left
15135            },
15136        );
15137
15138        match self
15139            .find_all_references_task_sources
15140            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15141        {
15142            Ok(_) => {
15143                log::info!(
15144                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15145                );
15146                return None;
15147            }
15148            Err(i) => {
15149                self.find_all_references_task_sources.insert(i, head_anchor);
15150            }
15151        }
15152
15153        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15154        let workspace = self.workspace()?;
15155        let project = workspace.read(cx).project().clone();
15156        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15157        Some(cx.spawn_in(window, async move |editor, cx| {
15158            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15159                if let Ok(i) = editor
15160                    .find_all_references_task_sources
15161                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15162                {
15163                    editor.find_all_references_task_sources.remove(i);
15164                }
15165            });
15166
15167            let locations = references.await?;
15168            if locations.is_empty() {
15169                return anyhow::Ok(Navigated::No);
15170            }
15171
15172            workspace.update_in(cx, |workspace, window, cx| {
15173                let title = locations
15174                    .first()
15175                    .as_ref()
15176                    .map(|location| {
15177                        let buffer = location.buffer.read(cx);
15178                        format!(
15179                            "References to `{}`",
15180                            buffer
15181                                .text_for_range(location.range.clone())
15182                                .collect::<String>()
15183                        )
15184                    })
15185                    .unwrap();
15186                Self::open_locations_in_multibuffer(
15187                    workspace,
15188                    locations,
15189                    title,
15190                    false,
15191                    MultibufferSelectionMode::First,
15192                    window,
15193                    cx,
15194                );
15195                Navigated::Yes
15196            })
15197        }))
15198    }
15199
15200    /// Opens a multibuffer with the given project locations in it
15201    pub fn open_locations_in_multibuffer(
15202        workspace: &mut Workspace,
15203        mut locations: Vec<Location>,
15204        title: String,
15205        split: bool,
15206        multibuffer_selection_mode: MultibufferSelectionMode,
15207        window: &mut Window,
15208        cx: &mut Context<Workspace>,
15209    ) {
15210        // If there are multiple definitions, open them in a multibuffer
15211        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15212        let mut locations = locations.into_iter().peekable();
15213        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15214        let capability = workspace.project().read(cx).capability();
15215
15216        let excerpt_buffer = cx.new(|cx| {
15217            let mut multibuffer = MultiBuffer::new(capability);
15218            while let Some(location) = locations.next() {
15219                let buffer = location.buffer.read(cx);
15220                let mut ranges_for_buffer = Vec::new();
15221                let range = location.range.to_point(buffer);
15222                ranges_for_buffer.push(range.clone());
15223
15224                while let Some(next_location) = locations.peek() {
15225                    if next_location.buffer == location.buffer {
15226                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15227                        locations.next();
15228                    } else {
15229                        break;
15230                    }
15231                }
15232
15233                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15234                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15235                    PathKey::for_buffer(&location.buffer, cx),
15236                    location.buffer.clone(),
15237                    ranges_for_buffer,
15238                    DEFAULT_MULTIBUFFER_CONTEXT,
15239                    cx,
15240                );
15241                ranges.extend(new_ranges)
15242            }
15243
15244            multibuffer.with_title(title)
15245        });
15246
15247        let editor = cx.new(|cx| {
15248            Editor::for_multibuffer(
15249                excerpt_buffer,
15250                Some(workspace.project().clone()),
15251                window,
15252                cx,
15253            )
15254        });
15255        editor.update(cx, |editor, cx| {
15256            match multibuffer_selection_mode {
15257                MultibufferSelectionMode::First => {
15258                    if let Some(first_range) = ranges.first() {
15259                        editor.change_selections(None, window, cx, |selections| {
15260                            selections.clear_disjoint();
15261                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15262                        });
15263                    }
15264                    editor.highlight_background::<Self>(
15265                        &ranges,
15266                        |theme| theme.editor_highlighted_line_background,
15267                        cx,
15268                    );
15269                }
15270                MultibufferSelectionMode::All => {
15271                    editor.change_selections(None, window, cx, |selections| {
15272                        selections.clear_disjoint();
15273                        selections.select_anchor_ranges(ranges);
15274                    });
15275                }
15276            }
15277            editor.register_buffers_with_language_servers(cx);
15278        });
15279
15280        let item = Box::new(editor);
15281        let item_id = item.item_id();
15282
15283        if split {
15284            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15285        } else {
15286            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15287                let (preview_item_id, preview_item_idx) =
15288                    workspace.active_pane().read_with(cx, |pane, _| {
15289                        (pane.preview_item_id(), pane.preview_item_idx())
15290                    });
15291
15292                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15293
15294                if let Some(preview_item_id) = preview_item_id {
15295                    workspace.active_pane().update(cx, |pane, cx| {
15296                        pane.remove_item(preview_item_id, false, false, window, cx);
15297                    });
15298                }
15299            } else {
15300                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15301            }
15302        }
15303        workspace.active_pane().update(cx, |pane, cx| {
15304            pane.set_preview_item_id(Some(item_id), cx);
15305        });
15306    }
15307
15308    pub fn rename(
15309        &mut self,
15310        _: &Rename,
15311        window: &mut Window,
15312        cx: &mut Context<Self>,
15313    ) -> Option<Task<Result<()>>> {
15314        use language::ToOffset as _;
15315
15316        let provider = self.semantics_provider.clone()?;
15317        let selection = self.selections.newest_anchor().clone();
15318        let (cursor_buffer, cursor_buffer_position) = self
15319            .buffer
15320            .read(cx)
15321            .text_anchor_for_position(selection.head(), cx)?;
15322        let (tail_buffer, cursor_buffer_position_end) = self
15323            .buffer
15324            .read(cx)
15325            .text_anchor_for_position(selection.tail(), cx)?;
15326        if tail_buffer != cursor_buffer {
15327            return None;
15328        }
15329
15330        let snapshot = cursor_buffer.read(cx).snapshot();
15331        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15332        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15333        let prepare_rename = provider
15334            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15335            .unwrap_or_else(|| Task::ready(Ok(None)));
15336        drop(snapshot);
15337
15338        Some(cx.spawn_in(window, async move |this, cx| {
15339            let rename_range = if let Some(range) = prepare_rename.await? {
15340                Some(range)
15341            } else {
15342                this.update(cx, |this, cx| {
15343                    let buffer = this.buffer.read(cx).snapshot(cx);
15344                    let mut buffer_highlights = this
15345                        .document_highlights_for_position(selection.head(), &buffer)
15346                        .filter(|highlight| {
15347                            highlight.start.excerpt_id == selection.head().excerpt_id
15348                                && highlight.end.excerpt_id == selection.head().excerpt_id
15349                        });
15350                    buffer_highlights
15351                        .next()
15352                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15353                })?
15354            };
15355            if let Some(rename_range) = rename_range {
15356                this.update_in(cx, |this, window, cx| {
15357                    let snapshot = cursor_buffer.read(cx).snapshot();
15358                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15359                    let cursor_offset_in_rename_range =
15360                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15361                    let cursor_offset_in_rename_range_end =
15362                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15363
15364                    this.take_rename(false, window, cx);
15365                    let buffer = this.buffer.read(cx).read(cx);
15366                    let cursor_offset = selection.head().to_offset(&buffer);
15367                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15368                    let rename_end = rename_start + rename_buffer_range.len();
15369                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15370                    let mut old_highlight_id = None;
15371                    let old_name: Arc<str> = buffer
15372                        .chunks(rename_start..rename_end, true)
15373                        .map(|chunk| {
15374                            if old_highlight_id.is_none() {
15375                                old_highlight_id = chunk.syntax_highlight_id;
15376                            }
15377                            chunk.text
15378                        })
15379                        .collect::<String>()
15380                        .into();
15381
15382                    drop(buffer);
15383
15384                    // Position the selection in the rename editor so that it matches the current selection.
15385                    this.show_local_selections = false;
15386                    let rename_editor = cx.new(|cx| {
15387                        let mut editor = Editor::single_line(window, cx);
15388                        editor.buffer.update(cx, |buffer, cx| {
15389                            buffer.edit([(0..0, old_name.clone())], None, cx)
15390                        });
15391                        let rename_selection_range = match cursor_offset_in_rename_range
15392                            .cmp(&cursor_offset_in_rename_range_end)
15393                        {
15394                            Ordering::Equal => {
15395                                editor.select_all(&SelectAll, window, cx);
15396                                return editor;
15397                            }
15398                            Ordering::Less => {
15399                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15400                            }
15401                            Ordering::Greater => {
15402                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15403                            }
15404                        };
15405                        if rename_selection_range.end > old_name.len() {
15406                            editor.select_all(&SelectAll, window, cx);
15407                        } else {
15408                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15409                                s.select_ranges([rename_selection_range]);
15410                            });
15411                        }
15412                        editor
15413                    });
15414                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15415                        if e == &EditorEvent::Focused {
15416                            cx.emit(EditorEvent::FocusedIn)
15417                        }
15418                    })
15419                    .detach();
15420
15421                    let write_highlights =
15422                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15423                    let read_highlights =
15424                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15425                    let ranges = write_highlights
15426                        .iter()
15427                        .flat_map(|(_, ranges)| ranges.iter())
15428                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15429                        .cloned()
15430                        .collect();
15431
15432                    this.highlight_text::<Rename>(
15433                        ranges,
15434                        HighlightStyle {
15435                            fade_out: Some(0.6),
15436                            ..Default::default()
15437                        },
15438                        cx,
15439                    );
15440                    let rename_focus_handle = rename_editor.focus_handle(cx);
15441                    window.focus(&rename_focus_handle);
15442                    let block_id = this.insert_blocks(
15443                        [BlockProperties {
15444                            style: BlockStyle::Flex,
15445                            placement: BlockPlacement::Below(range.start),
15446                            height: Some(1),
15447                            render: Arc::new({
15448                                let rename_editor = rename_editor.clone();
15449                                move |cx: &mut BlockContext| {
15450                                    let mut text_style = cx.editor_style.text.clone();
15451                                    if let Some(highlight_style) = old_highlight_id
15452                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15453                                    {
15454                                        text_style = text_style.highlight(highlight_style);
15455                                    }
15456                                    div()
15457                                        .block_mouse_except_scroll()
15458                                        .pl(cx.anchor_x)
15459                                        .child(EditorElement::new(
15460                                            &rename_editor,
15461                                            EditorStyle {
15462                                                background: cx.theme().system().transparent,
15463                                                local_player: cx.editor_style.local_player,
15464                                                text: text_style,
15465                                                scrollbar_width: cx.editor_style.scrollbar_width,
15466                                                syntax: cx.editor_style.syntax.clone(),
15467                                                status: cx.editor_style.status.clone(),
15468                                                inlay_hints_style: HighlightStyle {
15469                                                    font_weight: Some(FontWeight::BOLD),
15470                                                    ..make_inlay_hints_style(cx.app)
15471                                                },
15472                                                inline_completion_styles: make_suggestion_styles(
15473                                                    cx.app,
15474                                                ),
15475                                                ..EditorStyle::default()
15476                                            },
15477                                        ))
15478                                        .into_any_element()
15479                                }
15480                            }),
15481                            priority: 0,
15482                            render_in_minimap: true,
15483                        }],
15484                        Some(Autoscroll::fit()),
15485                        cx,
15486                    )[0];
15487                    this.pending_rename = Some(RenameState {
15488                        range,
15489                        old_name,
15490                        editor: rename_editor,
15491                        block_id,
15492                    });
15493                })?;
15494            }
15495
15496            Ok(())
15497        }))
15498    }
15499
15500    pub fn confirm_rename(
15501        &mut self,
15502        _: &ConfirmRename,
15503        window: &mut Window,
15504        cx: &mut Context<Self>,
15505    ) -> Option<Task<Result<()>>> {
15506        let rename = self.take_rename(false, window, cx)?;
15507        let workspace = self.workspace()?.downgrade();
15508        let (buffer, start) = self
15509            .buffer
15510            .read(cx)
15511            .text_anchor_for_position(rename.range.start, cx)?;
15512        let (end_buffer, _) = self
15513            .buffer
15514            .read(cx)
15515            .text_anchor_for_position(rename.range.end, cx)?;
15516        if buffer != end_buffer {
15517            return None;
15518        }
15519
15520        let old_name = rename.old_name;
15521        let new_name = rename.editor.read(cx).text(cx);
15522
15523        let rename = self.semantics_provider.as_ref()?.perform_rename(
15524            &buffer,
15525            start,
15526            new_name.clone(),
15527            cx,
15528        )?;
15529
15530        Some(cx.spawn_in(window, async move |editor, cx| {
15531            let project_transaction = rename.await?;
15532            Self::open_project_transaction(
15533                &editor,
15534                workspace,
15535                project_transaction,
15536                format!("Rename: {}{}", old_name, new_name),
15537                cx,
15538            )
15539            .await?;
15540
15541            editor.update(cx, |editor, cx| {
15542                editor.refresh_document_highlights(cx);
15543            })?;
15544            Ok(())
15545        }))
15546    }
15547
15548    fn take_rename(
15549        &mut self,
15550        moving_cursor: bool,
15551        window: &mut Window,
15552        cx: &mut Context<Self>,
15553    ) -> Option<RenameState> {
15554        let rename = self.pending_rename.take()?;
15555        if rename.editor.focus_handle(cx).is_focused(window) {
15556            window.focus(&self.focus_handle);
15557        }
15558
15559        self.remove_blocks(
15560            [rename.block_id].into_iter().collect(),
15561            Some(Autoscroll::fit()),
15562            cx,
15563        );
15564        self.clear_highlights::<Rename>(cx);
15565        self.show_local_selections = true;
15566
15567        if moving_cursor {
15568            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15569                editor.selections.newest::<usize>(cx).head()
15570            });
15571
15572            // Update the selection to match the position of the selection inside
15573            // the rename editor.
15574            let snapshot = self.buffer.read(cx).read(cx);
15575            let rename_range = rename.range.to_offset(&snapshot);
15576            let cursor_in_editor = snapshot
15577                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15578                .min(rename_range.end);
15579            drop(snapshot);
15580
15581            self.change_selections(None, window, cx, |s| {
15582                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15583            });
15584        } else {
15585            self.refresh_document_highlights(cx);
15586        }
15587
15588        Some(rename)
15589    }
15590
15591    pub fn pending_rename(&self) -> Option<&RenameState> {
15592        self.pending_rename.as_ref()
15593    }
15594
15595    fn format(
15596        &mut self,
15597        _: &Format,
15598        window: &mut Window,
15599        cx: &mut Context<Self>,
15600    ) -> Option<Task<Result<()>>> {
15601        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15602
15603        let project = match &self.project {
15604            Some(project) => project.clone(),
15605            None => return None,
15606        };
15607
15608        Some(self.perform_format(
15609            project,
15610            FormatTrigger::Manual,
15611            FormatTarget::Buffers,
15612            window,
15613            cx,
15614        ))
15615    }
15616
15617    fn format_selections(
15618        &mut self,
15619        _: &FormatSelections,
15620        window: &mut Window,
15621        cx: &mut Context<Self>,
15622    ) -> Option<Task<Result<()>>> {
15623        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15624
15625        let project = match &self.project {
15626            Some(project) => project.clone(),
15627            None => return None,
15628        };
15629
15630        let ranges = self
15631            .selections
15632            .all_adjusted(cx)
15633            .into_iter()
15634            .map(|selection| selection.range())
15635            .collect_vec();
15636
15637        Some(self.perform_format(
15638            project,
15639            FormatTrigger::Manual,
15640            FormatTarget::Ranges(ranges),
15641            window,
15642            cx,
15643        ))
15644    }
15645
15646    fn perform_format(
15647        &mut self,
15648        project: Entity<Project>,
15649        trigger: FormatTrigger,
15650        target: FormatTarget,
15651        window: &mut Window,
15652        cx: &mut Context<Self>,
15653    ) -> Task<Result<()>> {
15654        let buffer = self.buffer.clone();
15655        let (buffers, target) = match target {
15656            FormatTarget::Buffers => {
15657                let mut buffers = buffer.read(cx).all_buffers();
15658                if trigger == FormatTrigger::Save {
15659                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15660                }
15661                (buffers, LspFormatTarget::Buffers)
15662            }
15663            FormatTarget::Ranges(selection_ranges) => {
15664                let multi_buffer = buffer.read(cx);
15665                let snapshot = multi_buffer.read(cx);
15666                let mut buffers = HashSet::default();
15667                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15668                    BTreeMap::new();
15669                for selection_range in selection_ranges {
15670                    for (buffer, buffer_range, _) in
15671                        snapshot.range_to_buffer_ranges(selection_range)
15672                    {
15673                        let buffer_id = buffer.remote_id();
15674                        let start = buffer.anchor_before(buffer_range.start);
15675                        let end = buffer.anchor_after(buffer_range.end);
15676                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15677                        buffer_id_to_ranges
15678                            .entry(buffer_id)
15679                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15680                            .or_insert_with(|| vec![start..end]);
15681                    }
15682                }
15683                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15684            }
15685        };
15686
15687        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15688        let selections_prev = transaction_id_prev
15689            .and_then(|transaction_id_prev| {
15690                // default to selections as they were after the last edit, if we have them,
15691                // instead of how they are now.
15692                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15693                // will take you back to where you made the last edit, instead of staying where you scrolled
15694                self.selection_history
15695                    .transaction(transaction_id_prev)
15696                    .map(|t| t.0.clone())
15697            })
15698            .unwrap_or_else(|| {
15699                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15700                self.selections.disjoint_anchors()
15701            });
15702
15703        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15704        let format = project.update(cx, |project, cx| {
15705            project.format(buffers, target, true, trigger, cx)
15706        });
15707
15708        cx.spawn_in(window, async move |editor, cx| {
15709            let transaction = futures::select_biased! {
15710                transaction = format.log_err().fuse() => transaction,
15711                () = timeout => {
15712                    log::warn!("timed out waiting for formatting");
15713                    None
15714                }
15715            };
15716
15717            buffer
15718                .update(cx, |buffer, cx| {
15719                    if let Some(transaction) = transaction {
15720                        if !buffer.is_singleton() {
15721                            buffer.push_transaction(&transaction.0, cx);
15722                        }
15723                    }
15724                    cx.notify();
15725                })
15726                .ok();
15727
15728            if let Some(transaction_id_now) =
15729                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15730            {
15731                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15732                if has_new_transaction {
15733                    _ = editor.update(cx, |editor, _| {
15734                        editor
15735                            .selection_history
15736                            .insert_transaction(transaction_id_now, selections_prev);
15737                    });
15738                }
15739            }
15740
15741            Ok(())
15742        })
15743    }
15744
15745    fn organize_imports(
15746        &mut self,
15747        _: &OrganizeImports,
15748        window: &mut Window,
15749        cx: &mut Context<Self>,
15750    ) -> Option<Task<Result<()>>> {
15751        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15752        let project = match &self.project {
15753            Some(project) => project.clone(),
15754            None => return None,
15755        };
15756        Some(self.perform_code_action_kind(
15757            project,
15758            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15759            window,
15760            cx,
15761        ))
15762    }
15763
15764    fn perform_code_action_kind(
15765        &mut self,
15766        project: Entity<Project>,
15767        kind: CodeActionKind,
15768        window: &mut Window,
15769        cx: &mut Context<Self>,
15770    ) -> Task<Result<()>> {
15771        let buffer = self.buffer.clone();
15772        let buffers = buffer.read(cx).all_buffers();
15773        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15774        let apply_action = project.update(cx, |project, cx| {
15775            project.apply_code_action_kind(buffers, kind, true, cx)
15776        });
15777        cx.spawn_in(window, async move |_, cx| {
15778            let transaction = futures::select_biased! {
15779                () = timeout => {
15780                    log::warn!("timed out waiting for executing code action");
15781                    None
15782                }
15783                transaction = apply_action.log_err().fuse() => transaction,
15784            };
15785            buffer
15786                .update(cx, |buffer, cx| {
15787                    // check if we need this
15788                    if let Some(transaction) = transaction {
15789                        if !buffer.is_singleton() {
15790                            buffer.push_transaction(&transaction.0, cx);
15791                        }
15792                    }
15793                    cx.notify();
15794                })
15795                .ok();
15796            Ok(())
15797        })
15798    }
15799
15800    fn restart_language_server(
15801        &mut self,
15802        _: &RestartLanguageServer,
15803        _: &mut Window,
15804        cx: &mut Context<Self>,
15805    ) {
15806        if let Some(project) = self.project.clone() {
15807            self.buffer.update(cx, |multi_buffer, cx| {
15808                project.update(cx, |project, cx| {
15809                    project.restart_language_servers_for_buffers(
15810                        multi_buffer.all_buffers().into_iter().collect(),
15811                        cx,
15812                    );
15813                });
15814            })
15815        }
15816    }
15817
15818    fn stop_language_server(
15819        &mut self,
15820        _: &StopLanguageServer,
15821        _: &mut Window,
15822        cx: &mut Context<Self>,
15823    ) {
15824        if let Some(project) = self.project.clone() {
15825            self.buffer.update(cx, |multi_buffer, cx| {
15826                project.update(cx, |project, cx| {
15827                    project.stop_language_servers_for_buffers(
15828                        multi_buffer.all_buffers().into_iter().collect(),
15829                        cx,
15830                    );
15831                    cx.emit(project::Event::RefreshInlayHints);
15832                });
15833            });
15834        }
15835    }
15836
15837    fn cancel_language_server_work(
15838        workspace: &mut Workspace,
15839        _: &actions::CancelLanguageServerWork,
15840        _: &mut Window,
15841        cx: &mut Context<Workspace>,
15842    ) {
15843        let project = workspace.project();
15844        let buffers = workspace
15845            .active_item(cx)
15846            .and_then(|item| item.act_as::<Editor>(cx))
15847            .map_or(HashSet::default(), |editor| {
15848                editor.read(cx).buffer.read(cx).all_buffers()
15849            });
15850        project.update(cx, |project, cx| {
15851            project.cancel_language_server_work_for_buffers(buffers, cx);
15852        });
15853    }
15854
15855    fn show_character_palette(
15856        &mut self,
15857        _: &ShowCharacterPalette,
15858        window: &mut Window,
15859        _: &mut Context<Self>,
15860    ) {
15861        window.show_character_palette();
15862    }
15863
15864    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15865        if self.mode.is_minimap() {
15866            return;
15867        }
15868
15869        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15870            let buffer = self.buffer.read(cx).snapshot(cx);
15871            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15872            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15873            let is_valid = buffer
15874                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15875                .any(|entry| {
15876                    entry.diagnostic.is_primary
15877                        && !entry.range.is_empty()
15878                        && entry.range.start == primary_range_start
15879                        && entry.diagnostic.message == active_diagnostics.active_message
15880                });
15881
15882            if !is_valid {
15883                self.dismiss_diagnostics(cx);
15884            }
15885        }
15886    }
15887
15888    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15889        match &self.active_diagnostics {
15890            ActiveDiagnostic::Group(group) => Some(group),
15891            _ => None,
15892        }
15893    }
15894
15895    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15896        self.dismiss_diagnostics(cx);
15897        self.active_diagnostics = ActiveDiagnostic::All;
15898    }
15899
15900    fn activate_diagnostics(
15901        &mut self,
15902        buffer_id: BufferId,
15903        diagnostic: DiagnosticEntry<usize>,
15904        window: &mut Window,
15905        cx: &mut Context<Self>,
15906    ) {
15907        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15908            return;
15909        }
15910        self.dismiss_diagnostics(cx);
15911        let snapshot = self.snapshot(window, cx);
15912        let buffer = self.buffer.read(cx).snapshot(cx);
15913        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15914            return;
15915        };
15916
15917        let diagnostic_group = buffer
15918            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15919            .collect::<Vec<_>>();
15920
15921        let blocks =
15922            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15923
15924        let blocks = self.display_map.update(cx, |display_map, cx| {
15925            display_map.insert_blocks(blocks, cx).into_iter().collect()
15926        });
15927        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15928            active_range: buffer.anchor_before(diagnostic.range.start)
15929                ..buffer.anchor_after(diagnostic.range.end),
15930            active_message: diagnostic.diagnostic.message.clone(),
15931            group_id: diagnostic.diagnostic.group_id,
15932            blocks,
15933        });
15934        cx.notify();
15935    }
15936
15937    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15938        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15939            return;
15940        };
15941
15942        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15943        if let ActiveDiagnostic::Group(group) = prev {
15944            self.display_map.update(cx, |display_map, cx| {
15945                display_map.remove_blocks(group.blocks, cx);
15946            });
15947            cx.notify();
15948        }
15949    }
15950
15951    /// Disable inline diagnostics rendering for this editor.
15952    pub fn disable_inline_diagnostics(&mut self) {
15953        self.inline_diagnostics_enabled = false;
15954        self.inline_diagnostics_update = Task::ready(());
15955        self.inline_diagnostics.clear();
15956    }
15957
15958    pub fn diagnostics_enabled(&self) -> bool {
15959        self.mode.is_full()
15960    }
15961
15962    pub fn inline_diagnostics_enabled(&self) -> bool {
15963        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15964    }
15965
15966    pub fn show_inline_diagnostics(&self) -> bool {
15967        self.show_inline_diagnostics
15968    }
15969
15970    pub fn toggle_inline_diagnostics(
15971        &mut self,
15972        _: &ToggleInlineDiagnostics,
15973        window: &mut Window,
15974        cx: &mut Context<Editor>,
15975    ) {
15976        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15977        self.refresh_inline_diagnostics(false, window, cx);
15978    }
15979
15980    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15981        self.diagnostics_max_severity = severity;
15982        self.display_map.update(cx, |display_map, _| {
15983            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15984        });
15985    }
15986
15987    pub fn toggle_diagnostics(
15988        &mut self,
15989        _: &ToggleDiagnostics,
15990        window: &mut Window,
15991        cx: &mut Context<Editor>,
15992    ) {
15993        if !self.diagnostics_enabled() {
15994            return;
15995        }
15996
15997        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15998            EditorSettings::get_global(cx)
15999                .diagnostics_max_severity
16000                .filter(|severity| severity != &DiagnosticSeverity::Off)
16001                .unwrap_or(DiagnosticSeverity::Hint)
16002        } else {
16003            DiagnosticSeverity::Off
16004        };
16005        self.set_max_diagnostics_severity(new_severity, cx);
16006        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16007            self.active_diagnostics = ActiveDiagnostic::None;
16008            self.inline_diagnostics_update = Task::ready(());
16009            self.inline_diagnostics.clear();
16010        } else {
16011            self.refresh_inline_diagnostics(false, window, cx);
16012        }
16013
16014        cx.notify();
16015    }
16016
16017    pub fn toggle_minimap(
16018        &mut self,
16019        _: &ToggleMinimap,
16020        window: &mut Window,
16021        cx: &mut Context<Editor>,
16022    ) {
16023        if self.supports_minimap(cx) {
16024            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16025        }
16026    }
16027
16028    fn refresh_inline_diagnostics(
16029        &mut self,
16030        debounce: bool,
16031        window: &mut Window,
16032        cx: &mut Context<Self>,
16033    ) {
16034        let max_severity = ProjectSettings::get_global(cx)
16035            .diagnostics
16036            .inline
16037            .max_severity
16038            .unwrap_or(self.diagnostics_max_severity);
16039
16040        if !self.inline_diagnostics_enabled()
16041            || !self.show_inline_diagnostics
16042            || max_severity == DiagnosticSeverity::Off
16043        {
16044            self.inline_diagnostics_update = Task::ready(());
16045            self.inline_diagnostics.clear();
16046            return;
16047        }
16048
16049        let debounce_ms = ProjectSettings::get_global(cx)
16050            .diagnostics
16051            .inline
16052            .update_debounce_ms;
16053        let debounce = if debounce && debounce_ms > 0 {
16054            Some(Duration::from_millis(debounce_ms))
16055        } else {
16056            None
16057        };
16058        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16059            if let Some(debounce) = debounce {
16060                cx.background_executor().timer(debounce).await;
16061            }
16062            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16063                editor
16064                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16065                    .ok()
16066            }) else {
16067                return;
16068            };
16069
16070            let new_inline_diagnostics = cx
16071                .background_spawn(async move {
16072                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16073                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16074                        let message = diagnostic_entry
16075                            .diagnostic
16076                            .message
16077                            .split_once('\n')
16078                            .map(|(line, _)| line)
16079                            .map(SharedString::new)
16080                            .unwrap_or_else(|| {
16081                                SharedString::from(diagnostic_entry.diagnostic.message)
16082                            });
16083                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16084                        let (Ok(i) | Err(i)) = inline_diagnostics
16085                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16086                        inline_diagnostics.insert(
16087                            i,
16088                            (
16089                                start_anchor,
16090                                InlineDiagnostic {
16091                                    message,
16092                                    group_id: diagnostic_entry.diagnostic.group_id,
16093                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16094                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16095                                    severity: diagnostic_entry.diagnostic.severity,
16096                                },
16097                            ),
16098                        );
16099                    }
16100                    inline_diagnostics
16101                })
16102                .await;
16103
16104            editor
16105                .update(cx, |editor, cx| {
16106                    editor.inline_diagnostics = new_inline_diagnostics;
16107                    cx.notify();
16108                })
16109                .ok();
16110        });
16111    }
16112
16113    fn pull_diagnostics(
16114        &mut self,
16115        buffer_id: Option<BufferId>,
16116        window: &Window,
16117        cx: &mut Context<Self>,
16118    ) -> Option<()> {
16119        if !self.mode().is_full() {
16120            return None;
16121        }
16122        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16123            .diagnostics
16124            .lsp_pull_diagnostics;
16125        if !pull_diagnostics_settings.enabled {
16126            return None;
16127        }
16128        let project = self.project.as_ref()?.downgrade();
16129        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16130        let mut buffers = self.buffer.read(cx).all_buffers();
16131        if let Some(buffer_id) = buffer_id {
16132            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16133        }
16134
16135        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16136            cx.background_executor().timer(debounce).await;
16137
16138            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16139                buffers
16140                    .into_iter()
16141                    .flat_map(|buffer| {
16142                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16143                    })
16144                    .collect::<FuturesUnordered<_>>()
16145            }) else {
16146                return;
16147            };
16148
16149            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16150                match pull_task {
16151                    Ok(()) => {
16152                        if editor
16153                            .update_in(cx, |editor, window, cx| {
16154                                editor.update_diagnostics_state(window, cx);
16155                            })
16156                            .is_err()
16157                        {
16158                            return;
16159                        }
16160                    }
16161                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16162                }
16163            }
16164        });
16165
16166        Some(())
16167    }
16168
16169    pub fn set_selections_from_remote(
16170        &mut self,
16171        selections: Vec<Selection<Anchor>>,
16172        pending_selection: Option<Selection<Anchor>>,
16173        window: &mut Window,
16174        cx: &mut Context<Self>,
16175    ) {
16176        let old_cursor_position = self.selections.newest_anchor().head();
16177        self.selections.change_with(cx, |s| {
16178            s.select_anchors(selections);
16179            if let Some(pending_selection) = pending_selection {
16180                s.set_pending(pending_selection, SelectMode::Character);
16181            } else {
16182                s.clear_pending();
16183            }
16184        });
16185        self.selections_did_change(false, &old_cursor_position, true, window, cx);
16186    }
16187
16188    pub fn transact(
16189        &mut self,
16190        window: &mut Window,
16191        cx: &mut Context<Self>,
16192        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16193    ) -> Option<TransactionId> {
16194        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16195            this.start_transaction_at(Instant::now(), window, cx);
16196            update(this, window, cx);
16197            this.end_transaction_at(Instant::now(), cx)
16198        })
16199    }
16200
16201    pub fn start_transaction_at(
16202        &mut self,
16203        now: Instant,
16204        window: &mut Window,
16205        cx: &mut Context<Self>,
16206    ) {
16207        self.end_selection(window, cx);
16208        if let Some(tx_id) = self
16209            .buffer
16210            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16211        {
16212            self.selection_history
16213                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16214            cx.emit(EditorEvent::TransactionBegun {
16215                transaction_id: tx_id,
16216            })
16217        }
16218    }
16219
16220    pub fn end_transaction_at(
16221        &mut self,
16222        now: Instant,
16223        cx: &mut Context<Self>,
16224    ) -> Option<TransactionId> {
16225        if let Some(transaction_id) = self
16226            .buffer
16227            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16228        {
16229            if let Some((_, end_selections)) =
16230                self.selection_history.transaction_mut(transaction_id)
16231            {
16232                *end_selections = Some(self.selections.disjoint_anchors());
16233            } else {
16234                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16235            }
16236
16237            cx.emit(EditorEvent::Edited { transaction_id });
16238            Some(transaction_id)
16239        } else {
16240            None
16241        }
16242    }
16243
16244    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16245        if self.selection_mark_mode {
16246            self.change_selections(None, window, cx, |s| {
16247                s.move_with(|_, sel| {
16248                    sel.collapse_to(sel.head(), SelectionGoal::None);
16249                });
16250            })
16251        }
16252        self.selection_mark_mode = true;
16253        cx.notify();
16254    }
16255
16256    pub fn swap_selection_ends(
16257        &mut self,
16258        _: &actions::SwapSelectionEnds,
16259        window: &mut Window,
16260        cx: &mut Context<Self>,
16261    ) {
16262        self.change_selections(None, window, cx, |s| {
16263            s.move_with(|_, sel| {
16264                if sel.start != sel.end {
16265                    sel.reversed = !sel.reversed
16266                }
16267            });
16268        });
16269        self.request_autoscroll(Autoscroll::newest(), cx);
16270        cx.notify();
16271    }
16272
16273    pub fn toggle_fold(
16274        &mut self,
16275        _: &actions::ToggleFold,
16276        window: &mut Window,
16277        cx: &mut Context<Self>,
16278    ) {
16279        if self.is_singleton(cx) {
16280            let selection = self.selections.newest::<Point>(cx);
16281
16282            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16283            let range = if selection.is_empty() {
16284                let point = selection.head().to_display_point(&display_map);
16285                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16286                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16287                    .to_point(&display_map);
16288                start..end
16289            } else {
16290                selection.range()
16291            };
16292            if display_map.folds_in_range(range).next().is_some() {
16293                self.unfold_lines(&Default::default(), window, cx)
16294            } else {
16295                self.fold(&Default::default(), window, cx)
16296            }
16297        } else {
16298            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16299            let buffer_ids: HashSet<_> = self
16300                .selections
16301                .disjoint_anchor_ranges()
16302                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16303                .collect();
16304
16305            let should_unfold = buffer_ids
16306                .iter()
16307                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16308
16309            for buffer_id in buffer_ids {
16310                if should_unfold {
16311                    self.unfold_buffer(buffer_id, cx);
16312                } else {
16313                    self.fold_buffer(buffer_id, cx);
16314                }
16315            }
16316        }
16317    }
16318
16319    pub fn toggle_fold_recursive(
16320        &mut self,
16321        _: &actions::ToggleFoldRecursive,
16322        window: &mut Window,
16323        cx: &mut Context<Self>,
16324    ) {
16325        let selection = self.selections.newest::<Point>(cx);
16326
16327        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16328        let range = if selection.is_empty() {
16329            let point = selection.head().to_display_point(&display_map);
16330            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16331            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16332                .to_point(&display_map);
16333            start..end
16334        } else {
16335            selection.range()
16336        };
16337        if display_map.folds_in_range(range).next().is_some() {
16338            self.unfold_recursive(&Default::default(), window, cx)
16339        } else {
16340            self.fold_recursive(&Default::default(), window, cx)
16341        }
16342    }
16343
16344    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16345        if self.is_singleton(cx) {
16346            let mut to_fold = Vec::new();
16347            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16348            let selections = self.selections.all_adjusted(cx);
16349
16350            for selection in selections {
16351                let range = selection.range().sorted();
16352                let buffer_start_row = range.start.row;
16353
16354                if range.start.row != range.end.row {
16355                    let mut found = false;
16356                    let mut row = range.start.row;
16357                    while row <= range.end.row {
16358                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16359                        {
16360                            found = true;
16361                            row = crease.range().end.row + 1;
16362                            to_fold.push(crease);
16363                        } else {
16364                            row += 1
16365                        }
16366                    }
16367                    if found {
16368                        continue;
16369                    }
16370                }
16371
16372                for row in (0..=range.start.row).rev() {
16373                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16374                        if crease.range().end.row >= buffer_start_row {
16375                            to_fold.push(crease);
16376                            if row <= range.start.row {
16377                                break;
16378                            }
16379                        }
16380                    }
16381                }
16382            }
16383
16384            self.fold_creases(to_fold, true, window, cx);
16385        } else {
16386            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16387            let buffer_ids = self
16388                .selections
16389                .disjoint_anchor_ranges()
16390                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16391                .collect::<HashSet<_>>();
16392            for buffer_id in buffer_ids {
16393                self.fold_buffer(buffer_id, cx);
16394            }
16395        }
16396    }
16397
16398    fn fold_at_level(
16399        &mut self,
16400        fold_at: &FoldAtLevel,
16401        window: &mut Window,
16402        cx: &mut Context<Self>,
16403    ) {
16404        if !self.buffer.read(cx).is_singleton() {
16405            return;
16406        }
16407
16408        let fold_at_level = fold_at.0;
16409        let snapshot = self.buffer.read(cx).snapshot(cx);
16410        let mut to_fold = Vec::new();
16411        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16412
16413        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16414            while start_row < end_row {
16415                match self
16416                    .snapshot(window, cx)
16417                    .crease_for_buffer_row(MultiBufferRow(start_row))
16418                {
16419                    Some(crease) => {
16420                        let nested_start_row = crease.range().start.row + 1;
16421                        let nested_end_row = crease.range().end.row;
16422
16423                        if current_level < fold_at_level {
16424                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16425                        } else if current_level == fold_at_level {
16426                            to_fold.push(crease);
16427                        }
16428
16429                        start_row = nested_end_row + 1;
16430                    }
16431                    None => start_row += 1,
16432                }
16433            }
16434        }
16435
16436        self.fold_creases(to_fold, true, window, cx);
16437    }
16438
16439    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16440        if self.buffer.read(cx).is_singleton() {
16441            let mut fold_ranges = Vec::new();
16442            let snapshot = self.buffer.read(cx).snapshot(cx);
16443
16444            for row in 0..snapshot.max_row().0 {
16445                if let Some(foldable_range) = self
16446                    .snapshot(window, cx)
16447                    .crease_for_buffer_row(MultiBufferRow(row))
16448                {
16449                    fold_ranges.push(foldable_range);
16450                }
16451            }
16452
16453            self.fold_creases(fold_ranges, true, window, cx);
16454        } else {
16455            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16456                editor
16457                    .update_in(cx, |editor, _, cx| {
16458                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16459                            editor.fold_buffer(buffer_id, cx);
16460                        }
16461                    })
16462                    .ok();
16463            });
16464        }
16465    }
16466
16467    pub fn fold_function_bodies(
16468        &mut self,
16469        _: &actions::FoldFunctionBodies,
16470        window: &mut Window,
16471        cx: &mut Context<Self>,
16472    ) {
16473        let snapshot = self.buffer.read(cx).snapshot(cx);
16474
16475        let ranges = snapshot
16476            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16477            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16478            .collect::<Vec<_>>();
16479
16480        let creases = ranges
16481            .into_iter()
16482            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16483            .collect();
16484
16485        self.fold_creases(creases, true, window, cx);
16486    }
16487
16488    pub fn fold_recursive(
16489        &mut self,
16490        _: &actions::FoldRecursive,
16491        window: &mut Window,
16492        cx: &mut Context<Self>,
16493    ) {
16494        let mut to_fold = Vec::new();
16495        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16496        let selections = self.selections.all_adjusted(cx);
16497
16498        for selection in selections {
16499            let range = selection.range().sorted();
16500            let buffer_start_row = range.start.row;
16501
16502            if range.start.row != range.end.row {
16503                let mut found = false;
16504                for row in range.start.row..=range.end.row {
16505                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16506                        found = true;
16507                        to_fold.push(crease);
16508                    }
16509                }
16510                if found {
16511                    continue;
16512                }
16513            }
16514
16515            for row in (0..=range.start.row).rev() {
16516                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16517                    if crease.range().end.row >= buffer_start_row {
16518                        to_fold.push(crease);
16519                    } else {
16520                        break;
16521                    }
16522                }
16523            }
16524        }
16525
16526        self.fold_creases(to_fold, true, window, cx);
16527    }
16528
16529    pub fn fold_at(
16530        &mut self,
16531        buffer_row: MultiBufferRow,
16532        window: &mut Window,
16533        cx: &mut Context<Self>,
16534    ) {
16535        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16536
16537        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16538            let autoscroll = self
16539                .selections
16540                .all::<Point>(cx)
16541                .iter()
16542                .any(|selection| crease.range().overlaps(&selection.range()));
16543
16544            self.fold_creases(vec![crease], autoscroll, window, cx);
16545        }
16546    }
16547
16548    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16549        if self.is_singleton(cx) {
16550            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16551            let buffer = &display_map.buffer_snapshot;
16552            let selections = self.selections.all::<Point>(cx);
16553            let ranges = selections
16554                .iter()
16555                .map(|s| {
16556                    let range = s.display_range(&display_map).sorted();
16557                    let mut start = range.start.to_point(&display_map);
16558                    let mut end = range.end.to_point(&display_map);
16559                    start.column = 0;
16560                    end.column = buffer.line_len(MultiBufferRow(end.row));
16561                    start..end
16562                })
16563                .collect::<Vec<_>>();
16564
16565            self.unfold_ranges(&ranges, true, true, cx);
16566        } else {
16567            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16568            let buffer_ids = self
16569                .selections
16570                .disjoint_anchor_ranges()
16571                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16572                .collect::<HashSet<_>>();
16573            for buffer_id in buffer_ids {
16574                self.unfold_buffer(buffer_id, cx);
16575            }
16576        }
16577    }
16578
16579    pub fn unfold_recursive(
16580        &mut self,
16581        _: &UnfoldRecursive,
16582        _window: &mut Window,
16583        cx: &mut Context<Self>,
16584    ) {
16585        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16586        let selections = self.selections.all::<Point>(cx);
16587        let ranges = selections
16588            .iter()
16589            .map(|s| {
16590                let mut range = s.display_range(&display_map).sorted();
16591                *range.start.column_mut() = 0;
16592                *range.end.column_mut() = display_map.line_len(range.end.row());
16593                let start = range.start.to_point(&display_map);
16594                let end = range.end.to_point(&display_map);
16595                start..end
16596            })
16597            .collect::<Vec<_>>();
16598
16599        self.unfold_ranges(&ranges, true, true, cx);
16600    }
16601
16602    pub fn unfold_at(
16603        &mut self,
16604        buffer_row: MultiBufferRow,
16605        _window: &mut Window,
16606        cx: &mut Context<Self>,
16607    ) {
16608        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16609
16610        let intersection_range = Point::new(buffer_row.0, 0)
16611            ..Point::new(
16612                buffer_row.0,
16613                display_map.buffer_snapshot.line_len(buffer_row),
16614            );
16615
16616        let autoscroll = self
16617            .selections
16618            .all::<Point>(cx)
16619            .iter()
16620            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16621
16622        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16623    }
16624
16625    pub fn unfold_all(
16626        &mut self,
16627        _: &actions::UnfoldAll,
16628        _window: &mut Window,
16629        cx: &mut Context<Self>,
16630    ) {
16631        if self.buffer.read(cx).is_singleton() {
16632            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16633            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16634        } else {
16635            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16636                editor
16637                    .update(cx, |editor, cx| {
16638                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16639                            editor.unfold_buffer(buffer_id, cx);
16640                        }
16641                    })
16642                    .ok();
16643            });
16644        }
16645    }
16646
16647    pub fn fold_selected_ranges(
16648        &mut self,
16649        _: &FoldSelectedRanges,
16650        window: &mut Window,
16651        cx: &mut Context<Self>,
16652    ) {
16653        let selections = self.selections.all_adjusted(cx);
16654        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16655        let ranges = selections
16656            .into_iter()
16657            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16658            .collect::<Vec<_>>();
16659        self.fold_creases(ranges, true, window, cx);
16660    }
16661
16662    pub fn fold_ranges<T: ToOffset + Clone>(
16663        &mut self,
16664        ranges: Vec<Range<T>>,
16665        auto_scroll: bool,
16666        window: &mut Window,
16667        cx: &mut Context<Self>,
16668    ) {
16669        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16670        let ranges = ranges
16671            .into_iter()
16672            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16673            .collect::<Vec<_>>();
16674        self.fold_creases(ranges, auto_scroll, window, cx);
16675    }
16676
16677    pub fn fold_creases<T: ToOffset + Clone>(
16678        &mut self,
16679        creases: Vec<Crease<T>>,
16680        auto_scroll: bool,
16681        _window: &mut Window,
16682        cx: &mut Context<Self>,
16683    ) {
16684        if creases.is_empty() {
16685            return;
16686        }
16687
16688        let mut buffers_affected = HashSet::default();
16689        let multi_buffer = self.buffer().read(cx);
16690        for crease in &creases {
16691            if let Some((_, buffer, _)) =
16692                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16693            {
16694                buffers_affected.insert(buffer.read(cx).remote_id());
16695            };
16696        }
16697
16698        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16699
16700        if auto_scroll {
16701            self.request_autoscroll(Autoscroll::fit(), cx);
16702        }
16703
16704        cx.notify();
16705
16706        self.scrollbar_marker_state.dirty = true;
16707        self.folds_did_change(cx);
16708    }
16709
16710    /// Removes any folds whose ranges intersect any of the given ranges.
16711    pub fn unfold_ranges<T: ToOffset + Clone>(
16712        &mut self,
16713        ranges: &[Range<T>],
16714        inclusive: bool,
16715        auto_scroll: bool,
16716        cx: &mut Context<Self>,
16717    ) {
16718        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16719            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16720        });
16721        self.folds_did_change(cx);
16722    }
16723
16724    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16725        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16726            return;
16727        }
16728        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16729        self.display_map.update(cx, |display_map, cx| {
16730            display_map.fold_buffers([buffer_id], cx)
16731        });
16732        cx.emit(EditorEvent::BufferFoldToggled {
16733            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16734            folded: true,
16735        });
16736        cx.notify();
16737    }
16738
16739    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16740        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16741            return;
16742        }
16743        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16744        self.display_map.update(cx, |display_map, cx| {
16745            display_map.unfold_buffers([buffer_id], cx);
16746        });
16747        cx.emit(EditorEvent::BufferFoldToggled {
16748            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16749            folded: false,
16750        });
16751        cx.notify();
16752    }
16753
16754    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16755        self.display_map.read(cx).is_buffer_folded(buffer)
16756    }
16757
16758    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16759        self.display_map.read(cx).folded_buffers()
16760    }
16761
16762    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16763        self.display_map.update(cx, |display_map, cx| {
16764            display_map.disable_header_for_buffer(buffer_id, cx);
16765        });
16766        cx.notify();
16767    }
16768
16769    /// Removes any folds with the given ranges.
16770    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16771        &mut self,
16772        ranges: &[Range<T>],
16773        type_id: TypeId,
16774        auto_scroll: bool,
16775        cx: &mut Context<Self>,
16776    ) {
16777        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16778            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16779        });
16780        self.folds_did_change(cx);
16781    }
16782
16783    fn remove_folds_with<T: ToOffset + Clone>(
16784        &mut self,
16785        ranges: &[Range<T>],
16786        auto_scroll: bool,
16787        cx: &mut Context<Self>,
16788        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16789    ) {
16790        if ranges.is_empty() {
16791            return;
16792        }
16793
16794        let mut buffers_affected = HashSet::default();
16795        let multi_buffer = self.buffer().read(cx);
16796        for range in ranges {
16797            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16798                buffers_affected.insert(buffer.read(cx).remote_id());
16799            };
16800        }
16801
16802        self.display_map.update(cx, update);
16803
16804        if auto_scroll {
16805            self.request_autoscroll(Autoscroll::fit(), cx);
16806        }
16807
16808        cx.notify();
16809        self.scrollbar_marker_state.dirty = true;
16810        self.active_indent_guides_state.dirty = true;
16811    }
16812
16813    pub fn update_fold_widths(
16814        &mut self,
16815        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16816        cx: &mut Context<Self>,
16817    ) -> bool {
16818        self.display_map
16819            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16820    }
16821
16822    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16823        self.display_map.read(cx).fold_placeholder.clone()
16824    }
16825
16826    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16827        self.buffer.update(cx, |buffer, cx| {
16828            buffer.set_all_diff_hunks_expanded(cx);
16829        });
16830    }
16831
16832    pub fn expand_all_diff_hunks(
16833        &mut self,
16834        _: &ExpandAllDiffHunks,
16835        _window: &mut Window,
16836        cx: &mut Context<Self>,
16837    ) {
16838        self.buffer.update(cx, |buffer, cx| {
16839            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16840        });
16841    }
16842
16843    pub fn toggle_selected_diff_hunks(
16844        &mut self,
16845        _: &ToggleSelectedDiffHunks,
16846        _window: &mut Window,
16847        cx: &mut Context<Self>,
16848    ) {
16849        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16850        self.toggle_diff_hunks_in_ranges(ranges, cx);
16851    }
16852
16853    pub fn diff_hunks_in_ranges<'a>(
16854        &'a self,
16855        ranges: &'a [Range<Anchor>],
16856        buffer: &'a MultiBufferSnapshot,
16857    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16858        ranges.iter().flat_map(move |range| {
16859            let end_excerpt_id = range.end.excerpt_id;
16860            let range = range.to_point(buffer);
16861            let mut peek_end = range.end;
16862            if range.end.row < buffer.max_row().0 {
16863                peek_end = Point::new(range.end.row + 1, 0);
16864            }
16865            buffer
16866                .diff_hunks_in_range(range.start..peek_end)
16867                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16868        })
16869    }
16870
16871    pub fn has_stageable_diff_hunks_in_ranges(
16872        &self,
16873        ranges: &[Range<Anchor>],
16874        snapshot: &MultiBufferSnapshot,
16875    ) -> bool {
16876        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16877        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16878    }
16879
16880    pub fn toggle_staged_selected_diff_hunks(
16881        &mut self,
16882        _: &::git::ToggleStaged,
16883        _: &mut Window,
16884        cx: &mut Context<Self>,
16885    ) {
16886        let snapshot = self.buffer.read(cx).snapshot(cx);
16887        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16888        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16889        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16890    }
16891
16892    pub fn set_render_diff_hunk_controls(
16893        &mut self,
16894        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16895        cx: &mut Context<Self>,
16896    ) {
16897        self.render_diff_hunk_controls = render_diff_hunk_controls;
16898        cx.notify();
16899    }
16900
16901    pub fn stage_and_next(
16902        &mut self,
16903        _: &::git::StageAndNext,
16904        window: &mut Window,
16905        cx: &mut Context<Self>,
16906    ) {
16907        self.do_stage_or_unstage_and_next(true, window, cx);
16908    }
16909
16910    pub fn unstage_and_next(
16911        &mut self,
16912        _: &::git::UnstageAndNext,
16913        window: &mut Window,
16914        cx: &mut Context<Self>,
16915    ) {
16916        self.do_stage_or_unstage_and_next(false, window, cx);
16917    }
16918
16919    pub fn stage_or_unstage_diff_hunks(
16920        &mut self,
16921        stage: bool,
16922        ranges: Vec<Range<Anchor>>,
16923        cx: &mut Context<Self>,
16924    ) {
16925        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16926        cx.spawn(async move |this, cx| {
16927            task.await?;
16928            this.update(cx, |this, cx| {
16929                let snapshot = this.buffer.read(cx).snapshot(cx);
16930                let chunk_by = this
16931                    .diff_hunks_in_ranges(&ranges, &snapshot)
16932                    .chunk_by(|hunk| hunk.buffer_id);
16933                for (buffer_id, hunks) in &chunk_by {
16934                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16935                }
16936            })
16937        })
16938        .detach_and_log_err(cx);
16939    }
16940
16941    fn save_buffers_for_ranges_if_needed(
16942        &mut self,
16943        ranges: &[Range<Anchor>],
16944        cx: &mut Context<Editor>,
16945    ) -> Task<Result<()>> {
16946        let multibuffer = self.buffer.read(cx);
16947        let snapshot = multibuffer.read(cx);
16948        let buffer_ids: HashSet<_> = ranges
16949            .iter()
16950            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16951            .collect();
16952        drop(snapshot);
16953
16954        let mut buffers = HashSet::default();
16955        for buffer_id in buffer_ids {
16956            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16957                let buffer = buffer_entity.read(cx);
16958                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16959                {
16960                    buffers.insert(buffer_entity);
16961                }
16962            }
16963        }
16964
16965        if let Some(project) = &self.project {
16966            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16967        } else {
16968            Task::ready(Ok(()))
16969        }
16970    }
16971
16972    fn do_stage_or_unstage_and_next(
16973        &mut self,
16974        stage: bool,
16975        window: &mut Window,
16976        cx: &mut Context<Self>,
16977    ) {
16978        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16979
16980        if ranges.iter().any(|range| range.start != range.end) {
16981            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16982            return;
16983        }
16984
16985        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16986        let snapshot = self.snapshot(window, cx);
16987        let position = self.selections.newest::<Point>(cx).head();
16988        let mut row = snapshot
16989            .buffer_snapshot
16990            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16991            .find(|hunk| hunk.row_range.start.0 > position.row)
16992            .map(|hunk| hunk.row_range.start);
16993
16994        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16995        // Outside of the project diff editor, wrap around to the beginning.
16996        if !all_diff_hunks_expanded {
16997            row = row.or_else(|| {
16998                snapshot
16999                    .buffer_snapshot
17000                    .diff_hunks_in_range(Point::zero()..position)
17001                    .find(|hunk| hunk.row_range.end.0 < position.row)
17002                    .map(|hunk| hunk.row_range.start)
17003            });
17004        }
17005
17006        if let Some(row) = row {
17007            let destination = Point::new(row.0, 0);
17008            let autoscroll = Autoscroll::center();
17009
17010            self.unfold_ranges(&[destination..destination], false, false, cx);
17011            self.change_selections(Some(autoscroll), window, cx, |s| {
17012                s.select_ranges([destination..destination]);
17013            });
17014        }
17015    }
17016
17017    fn do_stage_or_unstage(
17018        &self,
17019        stage: bool,
17020        buffer_id: BufferId,
17021        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17022        cx: &mut App,
17023    ) -> Option<()> {
17024        let project = self.project.as_ref()?;
17025        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17026        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17027        let buffer_snapshot = buffer.read(cx).snapshot();
17028        let file_exists = buffer_snapshot
17029            .file()
17030            .is_some_and(|file| file.disk_state().exists());
17031        diff.update(cx, |diff, cx| {
17032            diff.stage_or_unstage_hunks(
17033                stage,
17034                &hunks
17035                    .map(|hunk| buffer_diff::DiffHunk {
17036                        buffer_range: hunk.buffer_range,
17037                        diff_base_byte_range: hunk.diff_base_byte_range,
17038                        secondary_status: hunk.secondary_status,
17039                        range: Point::zero()..Point::zero(), // unused
17040                    })
17041                    .collect::<Vec<_>>(),
17042                &buffer_snapshot,
17043                file_exists,
17044                cx,
17045            )
17046        });
17047        None
17048    }
17049
17050    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17051        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17052        self.buffer
17053            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17054    }
17055
17056    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17057        self.buffer.update(cx, |buffer, cx| {
17058            let ranges = vec![Anchor::min()..Anchor::max()];
17059            if !buffer.all_diff_hunks_expanded()
17060                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17061            {
17062                buffer.collapse_diff_hunks(ranges, cx);
17063                true
17064            } else {
17065                false
17066            }
17067        })
17068    }
17069
17070    fn toggle_diff_hunks_in_ranges(
17071        &mut self,
17072        ranges: Vec<Range<Anchor>>,
17073        cx: &mut Context<Editor>,
17074    ) {
17075        self.buffer.update(cx, |buffer, cx| {
17076            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17077            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17078        })
17079    }
17080
17081    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17082        self.buffer.update(cx, |buffer, cx| {
17083            let snapshot = buffer.snapshot(cx);
17084            let excerpt_id = range.end.excerpt_id;
17085            let point_range = range.to_point(&snapshot);
17086            let expand = !buffer.single_hunk_is_expanded(range, cx);
17087            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17088        })
17089    }
17090
17091    pub(crate) fn apply_all_diff_hunks(
17092        &mut self,
17093        _: &ApplyAllDiffHunks,
17094        window: &mut Window,
17095        cx: &mut Context<Self>,
17096    ) {
17097        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17098
17099        let buffers = self.buffer.read(cx).all_buffers();
17100        for branch_buffer in buffers {
17101            branch_buffer.update(cx, |branch_buffer, cx| {
17102                branch_buffer.merge_into_base(Vec::new(), cx);
17103            });
17104        }
17105
17106        if let Some(project) = self.project.clone() {
17107            self.save(true, project, window, cx).detach_and_log_err(cx);
17108        }
17109    }
17110
17111    pub(crate) fn apply_selected_diff_hunks(
17112        &mut self,
17113        _: &ApplyDiffHunk,
17114        window: &mut Window,
17115        cx: &mut Context<Self>,
17116    ) {
17117        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17118        let snapshot = self.snapshot(window, cx);
17119        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17120        let mut ranges_by_buffer = HashMap::default();
17121        self.transact(window, cx, |editor, _window, cx| {
17122            for hunk in hunks {
17123                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17124                    ranges_by_buffer
17125                        .entry(buffer.clone())
17126                        .or_insert_with(Vec::new)
17127                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17128                }
17129            }
17130
17131            for (buffer, ranges) in ranges_by_buffer {
17132                buffer.update(cx, |buffer, cx| {
17133                    buffer.merge_into_base(ranges, cx);
17134                });
17135            }
17136        });
17137
17138        if let Some(project) = self.project.clone() {
17139            self.save(true, project, window, cx).detach_and_log_err(cx);
17140        }
17141    }
17142
17143    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17144        if hovered != self.gutter_hovered {
17145            self.gutter_hovered = hovered;
17146            cx.notify();
17147        }
17148    }
17149
17150    pub fn insert_blocks(
17151        &mut self,
17152        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17153        autoscroll: Option<Autoscroll>,
17154        cx: &mut Context<Self>,
17155    ) -> Vec<CustomBlockId> {
17156        let blocks = self
17157            .display_map
17158            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17159        if let Some(autoscroll) = autoscroll {
17160            self.request_autoscroll(autoscroll, cx);
17161        }
17162        cx.notify();
17163        blocks
17164    }
17165
17166    pub fn resize_blocks(
17167        &mut self,
17168        heights: HashMap<CustomBlockId, u32>,
17169        autoscroll: Option<Autoscroll>,
17170        cx: &mut Context<Self>,
17171    ) {
17172        self.display_map
17173            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17174        if let Some(autoscroll) = autoscroll {
17175            self.request_autoscroll(autoscroll, cx);
17176        }
17177        cx.notify();
17178    }
17179
17180    pub fn replace_blocks(
17181        &mut self,
17182        renderers: HashMap<CustomBlockId, RenderBlock>,
17183        autoscroll: Option<Autoscroll>,
17184        cx: &mut Context<Self>,
17185    ) {
17186        self.display_map
17187            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17188        if let Some(autoscroll) = autoscroll {
17189            self.request_autoscroll(autoscroll, cx);
17190        }
17191        cx.notify();
17192    }
17193
17194    pub fn remove_blocks(
17195        &mut self,
17196        block_ids: HashSet<CustomBlockId>,
17197        autoscroll: Option<Autoscroll>,
17198        cx: &mut Context<Self>,
17199    ) {
17200        self.display_map.update(cx, |display_map, cx| {
17201            display_map.remove_blocks(block_ids, cx)
17202        });
17203        if let Some(autoscroll) = autoscroll {
17204            self.request_autoscroll(autoscroll, cx);
17205        }
17206        cx.notify();
17207    }
17208
17209    pub fn row_for_block(
17210        &self,
17211        block_id: CustomBlockId,
17212        cx: &mut Context<Self>,
17213    ) -> Option<DisplayRow> {
17214        self.display_map
17215            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17216    }
17217
17218    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17219        self.focused_block = Some(focused_block);
17220    }
17221
17222    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17223        self.focused_block.take()
17224    }
17225
17226    pub fn insert_creases(
17227        &mut self,
17228        creases: impl IntoIterator<Item = Crease<Anchor>>,
17229        cx: &mut Context<Self>,
17230    ) -> Vec<CreaseId> {
17231        self.display_map
17232            .update(cx, |map, cx| map.insert_creases(creases, cx))
17233    }
17234
17235    pub fn remove_creases(
17236        &mut self,
17237        ids: impl IntoIterator<Item = CreaseId>,
17238        cx: &mut Context<Self>,
17239    ) -> Vec<(CreaseId, Range<Anchor>)> {
17240        self.display_map
17241            .update(cx, |map, cx| map.remove_creases(ids, cx))
17242    }
17243
17244    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17245        self.display_map
17246            .update(cx, |map, cx| map.snapshot(cx))
17247            .longest_row()
17248    }
17249
17250    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17251        self.display_map
17252            .update(cx, |map, cx| map.snapshot(cx))
17253            .max_point()
17254    }
17255
17256    pub fn text(&self, cx: &App) -> String {
17257        self.buffer.read(cx).read(cx).text()
17258    }
17259
17260    pub fn is_empty(&self, cx: &App) -> bool {
17261        self.buffer.read(cx).read(cx).is_empty()
17262    }
17263
17264    pub fn text_option(&self, cx: &App) -> Option<String> {
17265        let text = self.text(cx);
17266        let text = text.trim();
17267
17268        if text.is_empty() {
17269            return None;
17270        }
17271
17272        Some(text.to_string())
17273    }
17274
17275    pub fn set_text(
17276        &mut self,
17277        text: impl Into<Arc<str>>,
17278        window: &mut Window,
17279        cx: &mut Context<Self>,
17280    ) {
17281        self.transact(window, cx, |this, _, cx| {
17282            this.buffer
17283                .read(cx)
17284                .as_singleton()
17285                .expect("you can only call set_text on editors for singleton buffers")
17286                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17287        });
17288    }
17289
17290    pub fn display_text(&self, cx: &mut App) -> String {
17291        self.display_map
17292            .update(cx, |map, cx| map.snapshot(cx))
17293            .text()
17294    }
17295
17296    fn create_minimap(
17297        &self,
17298        minimap_settings: MinimapSettings,
17299        window: &mut Window,
17300        cx: &mut Context<Self>,
17301    ) -> Option<Entity<Self>> {
17302        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17303            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17304    }
17305
17306    fn initialize_new_minimap(
17307        &self,
17308        minimap_settings: MinimapSettings,
17309        window: &mut Window,
17310        cx: &mut Context<Self>,
17311    ) -> Entity<Self> {
17312        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17313
17314        let mut minimap = Editor::new_internal(
17315            EditorMode::Minimap {
17316                parent: cx.weak_entity(),
17317            },
17318            self.buffer.clone(),
17319            self.project.clone(),
17320            Some(self.display_map.clone()),
17321            window,
17322            cx,
17323        );
17324        minimap.scroll_manager.clone_state(&self.scroll_manager);
17325        minimap.set_text_style_refinement(TextStyleRefinement {
17326            font_size: Some(MINIMAP_FONT_SIZE),
17327            font_weight: Some(MINIMAP_FONT_WEIGHT),
17328            ..Default::default()
17329        });
17330        minimap.update_minimap_configuration(minimap_settings, cx);
17331        cx.new(|_| minimap)
17332    }
17333
17334    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17335        let current_line_highlight = minimap_settings
17336            .current_line_highlight
17337            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17338        self.set_current_line_highlight(Some(current_line_highlight));
17339    }
17340
17341    pub fn minimap(&self) -> Option<&Entity<Self>> {
17342        self.minimap
17343            .as_ref()
17344            .filter(|_| self.minimap_visibility.visible())
17345    }
17346
17347    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17348        let mut wrap_guides = smallvec![];
17349
17350        if self.show_wrap_guides == Some(false) {
17351            return wrap_guides;
17352        }
17353
17354        let settings = self.buffer.read(cx).language_settings(cx);
17355        if settings.show_wrap_guides {
17356            match self.soft_wrap_mode(cx) {
17357                SoftWrap::Column(soft_wrap) => {
17358                    wrap_guides.push((soft_wrap as usize, true));
17359                }
17360                SoftWrap::Bounded(soft_wrap) => {
17361                    wrap_guides.push((soft_wrap as usize, true));
17362                }
17363                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17364            }
17365            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17366        }
17367
17368        wrap_guides
17369    }
17370
17371    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17372        let settings = self.buffer.read(cx).language_settings(cx);
17373        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17374        match mode {
17375            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17376                SoftWrap::None
17377            }
17378            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17379            language_settings::SoftWrap::PreferredLineLength => {
17380                SoftWrap::Column(settings.preferred_line_length)
17381            }
17382            language_settings::SoftWrap::Bounded => {
17383                SoftWrap::Bounded(settings.preferred_line_length)
17384            }
17385        }
17386    }
17387
17388    pub fn set_soft_wrap_mode(
17389        &mut self,
17390        mode: language_settings::SoftWrap,
17391
17392        cx: &mut Context<Self>,
17393    ) {
17394        self.soft_wrap_mode_override = Some(mode);
17395        cx.notify();
17396    }
17397
17398    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17399        self.hard_wrap = hard_wrap;
17400        cx.notify();
17401    }
17402
17403    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17404        self.text_style_refinement = Some(style);
17405    }
17406
17407    /// called by the Element so we know what style we were most recently rendered with.
17408    pub(crate) fn set_style(
17409        &mut self,
17410        style: EditorStyle,
17411        window: &mut Window,
17412        cx: &mut Context<Self>,
17413    ) {
17414        // We intentionally do not inform the display map about the minimap style
17415        // so that wrapping is not recalculated and stays consistent for the editor
17416        // and its linked minimap.
17417        if !self.mode.is_minimap() {
17418            let rem_size = window.rem_size();
17419            self.display_map.update(cx, |map, cx| {
17420                map.set_font(
17421                    style.text.font(),
17422                    style.text.font_size.to_pixels(rem_size),
17423                    cx,
17424                )
17425            });
17426        }
17427        self.style = Some(style);
17428    }
17429
17430    pub fn style(&self) -> Option<&EditorStyle> {
17431        self.style.as_ref()
17432    }
17433
17434    // Called by the element. This method is not designed to be called outside of the editor
17435    // element's layout code because it does not notify when rewrapping is computed synchronously.
17436    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17437        self.display_map
17438            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17439    }
17440
17441    pub fn set_soft_wrap(&mut self) {
17442        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17443    }
17444
17445    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17446        if self.soft_wrap_mode_override.is_some() {
17447            self.soft_wrap_mode_override.take();
17448        } else {
17449            let soft_wrap = match self.soft_wrap_mode(cx) {
17450                SoftWrap::GitDiff => return,
17451                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17452                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17453                    language_settings::SoftWrap::None
17454                }
17455            };
17456            self.soft_wrap_mode_override = Some(soft_wrap);
17457        }
17458        cx.notify();
17459    }
17460
17461    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17462        let Some(workspace) = self.workspace() else {
17463            return;
17464        };
17465        let fs = workspace.read(cx).app_state().fs.clone();
17466        let current_show = TabBarSettings::get_global(cx).show;
17467        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17468            setting.show = Some(!current_show);
17469        });
17470    }
17471
17472    pub fn toggle_indent_guides(
17473        &mut self,
17474        _: &ToggleIndentGuides,
17475        _: &mut Window,
17476        cx: &mut Context<Self>,
17477    ) {
17478        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17479            self.buffer
17480                .read(cx)
17481                .language_settings(cx)
17482                .indent_guides
17483                .enabled
17484        });
17485        self.show_indent_guides = Some(!currently_enabled);
17486        cx.notify();
17487    }
17488
17489    fn should_show_indent_guides(&self) -> Option<bool> {
17490        self.show_indent_guides
17491    }
17492
17493    pub fn toggle_line_numbers(
17494        &mut self,
17495        _: &ToggleLineNumbers,
17496        _: &mut Window,
17497        cx: &mut Context<Self>,
17498    ) {
17499        let mut editor_settings = EditorSettings::get_global(cx).clone();
17500        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17501        EditorSettings::override_global(editor_settings, cx);
17502    }
17503
17504    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17505        if let Some(show_line_numbers) = self.show_line_numbers {
17506            return show_line_numbers;
17507        }
17508        EditorSettings::get_global(cx).gutter.line_numbers
17509    }
17510
17511    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17512        self.use_relative_line_numbers
17513            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17514    }
17515
17516    pub fn toggle_relative_line_numbers(
17517        &mut self,
17518        _: &ToggleRelativeLineNumbers,
17519        _: &mut Window,
17520        cx: &mut Context<Self>,
17521    ) {
17522        let is_relative = self.should_use_relative_line_numbers(cx);
17523        self.set_relative_line_number(Some(!is_relative), cx)
17524    }
17525
17526    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17527        self.use_relative_line_numbers = is_relative;
17528        cx.notify();
17529    }
17530
17531    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17532        self.show_gutter = show_gutter;
17533        cx.notify();
17534    }
17535
17536    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17537        self.show_scrollbars = ScrollbarAxes {
17538            horizontal: show,
17539            vertical: show,
17540        };
17541        cx.notify();
17542    }
17543
17544    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17545        self.show_scrollbars.vertical = show;
17546        cx.notify();
17547    }
17548
17549    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17550        self.show_scrollbars.horizontal = show;
17551        cx.notify();
17552    }
17553
17554    pub fn set_minimap_visibility(
17555        &mut self,
17556        minimap_visibility: MinimapVisibility,
17557        window: &mut Window,
17558        cx: &mut Context<Self>,
17559    ) {
17560        if self.minimap_visibility != minimap_visibility {
17561            if minimap_visibility.visible() && self.minimap.is_none() {
17562                let minimap_settings = EditorSettings::get_global(cx).minimap;
17563                self.minimap =
17564                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17565            }
17566            self.minimap_visibility = minimap_visibility;
17567            cx.notify();
17568        }
17569    }
17570
17571    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17572        self.set_show_scrollbars(false, cx);
17573        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17574    }
17575
17576    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17577        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17578    }
17579
17580    /// Normally the text in full mode and auto height editors is padded on the
17581    /// left side by roughly half a character width for improved hit testing.
17582    ///
17583    /// Use this method to disable this for cases where this is not wanted (e.g.
17584    /// if you want to align the editor text with some other text above or below)
17585    /// or if you want to add this padding to single-line editors.
17586    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17587        self.offset_content = offset_content;
17588        cx.notify();
17589    }
17590
17591    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17592        self.show_line_numbers = Some(show_line_numbers);
17593        cx.notify();
17594    }
17595
17596    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17597        self.disable_expand_excerpt_buttons = true;
17598        cx.notify();
17599    }
17600
17601    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17602        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17603        cx.notify();
17604    }
17605
17606    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17607        self.show_code_actions = Some(show_code_actions);
17608        cx.notify();
17609    }
17610
17611    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17612        self.show_runnables = Some(show_runnables);
17613        cx.notify();
17614    }
17615
17616    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17617        self.show_breakpoints = Some(show_breakpoints);
17618        cx.notify();
17619    }
17620
17621    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17622        if self.display_map.read(cx).masked != masked {
17623            self.display_map.update(cx, |map, _| map.masked = masked);
17624        }
17625        cx.notify()
17626    }
17627
17628    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17629        self.show_wrap_guides = Some(show_wrap_guides);
17630        cx.notify();
17631    }
17632
17633    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17634        self.show_indent_guides = Some(show_indent_guides);
17635        cx.notify();
17636    }
17637
17638    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17639        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17640            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17641                if let Some(dir) = file.abs_path(cx).parent() {
17642                    return Some(dir.to_owned());
17643                }
17644            }
17645
17646            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17647                return Some(project_path.path.to_path_buf());
17648            }
17649        }
17650
17651        None
17652    }
17653
17654    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17655        self.active_excerpt(cx)?
17656            .1
17657            .read(cx)
17658            .file()
17659            .and_then(|f| f.as_local())
17660    }
17661
17662    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17663        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17664            let buffer = buffer.read(cx);
17665            if let Some(project_path) = buffer.project_path(cx) {
17666                let project = self.project.as_ref()?.read(cx);
17667                project.absolute_path(&project_path, cx)
17668            } else {
17669                buffer
17670                    .file()
17671                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17672            }
17673        })
17674    }
17675
17676    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17677        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17678            let project_path = buffer.read(cx).project_path(cx)?;
17679            let project = self.project.as_ref()?.read(cx);
17680            let entry = project.entry_for_path(&project_path, cx)?;
17681            let path = entry.path.to_path_buf();
17682            Some(path)
17683        })
17684    }
17685
17686    pub fn reveal_in_finder(
17687        &mut self,
17688        _: &RevealInFileManager,
17689        _window: &mut Window,
17690        cx: &mut Context<Self>,
17691    ) {
17692        if let Some(target) = self.target_file(cx) {
17693            cx.reveal_path(&target.abs_path(cx));
17694        }
17695    }
17696
17697    pub fn copy_path(
17698        &mut self,
17699        _: &zed_actions::workspace::CopyPath,
17700        _window: &mut Window,
17701        cx: &mut Context<Self>,
17702    ) {
17703        if let Some(path) = self.target_file_abs_path(cx) {
17704            if let Some(path) = path.to_str() {
17705                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17706            }
17707        }
17708    }
17709
17710    pub fn copy_relative_path(
17711        &mut self,
17712        _: &zed_actions::workspace::CopyRelativePath,
17713        _window: &mut Window,
17714        cx: &mut Context<Self>,
17715    ) {
17716        if let Some(path) = self.target_file_path(cx) {
17717            if let Some(path) = path.to_str() {
17718                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17719            }
17720        }
17721    }
17722
17723    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17724        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17725            buffer.read(cx).project_path(cx)
17726        } else {
17727            None
17728        }
17729    }
17730
17731    // Returns true if the editor handled a go-to-line request
17732    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17733        maybe!({
17734            let breakpoint_store = self.breakpoint_store.as_ref()?;
17735
17736            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17737            else {
17738                self.clear_row_highlights::<ActiveDebugLine>();
17739                return None;
17740            };
17741
17742            let position = active_stack_frame.position;
17743            let buffer_id = position.buffer_id?;
17744            let snapshot = self
17745                .project
17746                .as_ref()?
17747                .read(cx)
17748                .buffer_for_id(buffer_id, cx)?
17749                .read(cx)
17750                .snapshot();
17751
17752            let mut handled = false;
17753            for (id, ExcerptRange { context, .. }) in
17754                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17755            {
17756                if context.start.cmp(&position, &snapshot).is_ge()
17757                    || context.end.cmp(&position, &snapshot).is_lt()
17758                {
17759                    continue;
17760                }
17761                let snapshot = self.buffer.read(cx).snapshot(cx);
17762                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17763
17764                handled = true;
17765                self.clear_row_highlights::<ActiveDebugLine>();
17766
17767                self.go_to_line::<ActiveDebugLine>(
17768                    multibuffer_anchor,
17769                    Some(cx.theme().colors().editor_debugger_active_line_background),
17770                    window,
17771                    cx,
17772                );
17773
17774                cx.notify();
17775            }
17776
17777            handled.then_some(())
17778        })
17779        .is_some()
17780    }
17781
17782    pub fn copy_file_name_without_extension(
17783        &mut self,
17784        _: &CopyFileNameWithoutExtension,
17785        _: &mut Window,
17786        cx: &mut Context<Self>,
17787    ) {
17788        if let Some(file) = self.target_file(cx) {
17789            if let Some(file_stem) = file.path().file_stem() {
17790                if let Some(name) = file_stem.to_str() {
17791                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17792                }
17793            }
17794        }
17795    }
17796
17797    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17798        if let Some(file) = self.target_file(cx) {
17799            if let Some(file_name) = file.path().file_name() {
17800                if let Some(name) = file_name.to_str() {
17801                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17802                }
17803            }
17804        }
17805    }
17806
17807    pub fn toggle_git_blame(
17808        &mut self,
17809        _: &::git::Blame,
17810        window: &mut Window,
17811        cx: &mut Context<Self>,
17812    ) {
17813        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17814
17815        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17816            self.start_git_blame(true, window, cx);
17817        }
17818
17819        cx.notify();
17820    }
17821
17822    pub fn toggle_git_blame_inline(
17823        &mut self,
17824        _: &ToggleGitBlameInline,
17825        window: &mut Window,
17826        cx: &mut Context<Self>,
17827    ) {
17828        self.toggle_git_blame_inline_internal(true, window, cx);
17829        cx.notify();
17830    }
17831
17832    pub fn open_git_blame_commit(
17833        &mut self,
17834        _: &OpenGitBlameCommit,
17835        window: &mut Window,
17836        cx: &mut Context<Self>,
17837    ) {
17838        self.open_git_blame_commit_internal(window, cx);
17839    }
17840
17841    fn open_git_blame_commit_internal(
17842        &mut self,
17843        window: &mut Window,
17844        cx: &mut Context<Self>,
17845    ) -> Option<()> {
17846        let blame = self.blame.as_ref()?;
17847        let snapshot = self.snapshot(window, cx);
17848        let cursor = self.selections.newest::<Point>(cx).head();
17849        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17850        let blame_entry = blame
17851            .update(cx, |blame, cx| {
17852                blame
17853                    .blame_for_rows(
17854                        &[RowInfo {
17855                            buffer_id: Some(buffer.remote_id()),
17856                            buffer_row: Some(point.row),
17857                            ..Default::default()
17858                        }],
17859                        cx,
17860                    )
17861                    .next()
17862            })
17863            .flatten()?;
17864        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17865        let repo = blame.read(cx).repository(cx)?;
17866        let workspace = self.workspace()?.downgrade();
17867        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17868        None
17869    }
17870
17871    pub fn git_blame_inline_enabled(&self) -> bool {
17872        self.git_blame_inline_enabled
17873    }
17874
17875    pub fn toggle_selection_menu(
17876        &mut self,
17877        _: &ToggleSelectionMenu,
17878        _: &mut Window,
17879        cx: &mut Context<Self>,
17880    ) {
17881        self.show_selection_menu = self
17882            .show_selection_menu
17883            .map(|show_selections_menu| !show_selections_menu)
17884            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17885
17886        cx.notify();
17887    }
17888
17889    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17890        self.show_selection_menu
17891            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17892    }
17893
17894    fn start_git_blame(
17895        &mut self,
17896        user_triggered: bool,
17897        window: &mut Window,
17898        cx: &mut Context<Self>,
17899    ) {
17900        if let Some(project) = self.project.as_ref() {
17901            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17902                return;
17903            };
17904
17905            if buffer.read(cx).file().is_none() {
17906                return;
17907            }
17908
17909            let focused = self.focus_handle(cx).contains_focused(window, cx);
17910
17911            let project = project.clone();
17912            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17913            self.blame_subscription =
17914                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17915            self.blame = Some(blame);
17916        }
17917    }
17918
17919    fn toggle_git_blame_inline_internal(
17920        &mut self,
17921        user_triggered: bool,
17922        window: &mut Window,
17923        cx: &mut Context<Self>,
17924    ) {
17925        if self.git_blame_inline_enabled {
17926            self.git_blame_inline_enabled = false;
17927            self.show_git_blame_inline = false;
17928            self.show_git_blame_inline_delay_task.take();
17929        } else {
17930            self.git_blame_inline_enabled = true;
17931            self.start_git_blame_inline(user_triggered, window, cx);
17932        }
17933
17934        cx.notify();
17935    }
17936
17937    fn start_git_blame_inline(
17938        &mut self,
17939        user_triggered: bool,
17940        window: &mut Window,
17941        cx: &mut Context<Self>,
17942    ) {
17943        self.start_git_blame(user_triggered, window, cx);
17944
17945        if ProjectSettings::get_global(cx)
17946            .git
17947            .inline_blame_delay()
17948            .is_some()
17949        {
17950            self.start_inline_blame_timer(window, cx);
17951        } else {
17952            self.show_git_blame_inline = true
17953        }
17954    }
17955
17956    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17957        self.blame.as_ref()
17958    }
17959
17960    pub fn show_git_blame_gutter(&self) -> bool {
17961        self.show_git_blame_gutter
17962    }
17963
17964    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17965        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17966    }
17967
17968    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17969        self.show_git_blame_inline
17970            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17971            && !self.newest_selection_head_on_empty_line(cx)
17972            && self.has_blame_entries(cx)
17973    }
17974
17975    fn has_blame_entries(&self, cx: &App) -> bool {
17976        self.blame()
17977            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17978    }
17979
17980    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17981        let cursor_anchor = self.selections.newest_anchor().head();
17982
17983        let snapshot = self.buffer.read(cx).snapshot(cx);
17984        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17985
17986        snapshot.line_len(buffer_row) == 0
17987    }
17988
17989    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17990        let buffer_and_selection = maybe!({
17991            let selection = self.selections.newest::<Point>(cx);
17992            let selection_range = selection.range();
17993
17994            let multi_buffer = self.buffer().read(cx);
17995            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17996            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17997
17998            let (buffer, range, _) = if selection.reversed {
17999                buffer_ranges.first()
18000            } else {
18001                buffer_ranges.last()
18002            }?;
18003
18004            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18005                ..text::ToPoint::to_point(&range.end, &buffer).row;
18006            Some((
18007                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18008                selection,
18009            ))
18010        });
18011
18012        let Some((buffer, selection)) = buffer_and_selection else {
18013            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18014        };
18015
18016        let Some(project) = self.project.as_ref() else {
18017            return Task::ready(Err(anyhow!("editor does not have project")));
18018        };
18019
18020        project.update(cx, |project, cx| {
18021            project.get_permalink_to_line(&buffer, selection, cx)
18022        })
18023    }
18024
18025    pub fn copy_permalink_to_line(
18026        &mut self,
18027        _: &CopyPermalinkToLine,
18028        window: &mut Window,
18029        cx: &mut Context<Self>,
18030    ) {
18031        let permalink_task = self.get_permalink_to_line(cx);
18032        let workspace = self.workspace();
18033
18034        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18035            Ok(permalink) => {
18036                cx.update(|_, cx| {
18037                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18038                })
18039                .ok();
18040            }
18041            Err(err) => {
18042                let message = format!("Failed to copy permalink: {err}");
18043
18044                anyhow::Result::<()>::Err(err).log_err();
18045
18046                if let Some(workspace) = workspace {
18047                    workspace
18048                        .update_in(cx, |workspace, _, cx| {
18049                            struct CopyPermalinkToLine;
18050
18051                            workspace.show_toast(
18052                                Toast::new(
18053                                    NotificationId::unique::<CopyPermalinkToLine>(),
18054                                    message,
18055                                ),
18056                                cx,
18057                            )
18058                        })
18059                        .ok();
18060                }
18061            }
18062        })
18063        .detach();
18064    }
18065
18066    pub fn copy_file_location(
18067        &mut self,
18068        _: &CopyFileLocation,
18069        _: &mut Window,
18070        cx: &mut Context<Self>,
18071    ) {
18072        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18073        if let Some(file) = self.target_file(cx) {
18074            if let Some(path) = file.path().to_str() {
18075                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18076            }
18077        }
18078    }
18079
18080    pub fn open_permalink_to_line(
18081        &mut self,
18082        _: &OpenPermalinkToLine,
18083        window: &mut Window,
18084        cx: &mut Context<Self>,
18085    ) {
18086        let permalink_task = self.get_permalink_to_line(cx);
18087        let workspace = self.workspace();
18088
18089        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18090            Ok(permalink) => {
18091                cx.update(|_, cx| {
18092                    cx.open_url(permalink.as_ref());
18093                })
18094                .ok();
18095            }
18096            Err(err) => {
18097                let message = format!("Failed to open permalink: {err}");
18098
18099                anyhow::Result::<()>::Err(err).log_err();
18100
18101                if let Some(workspace) = workspace {
18102                    workspace
18103                        .update(cx, |workspace, cx| {
18104                            struct OpenPermalinkToLine;
18105
18106                            workspace.show_toast(
18107                                Toast::new(
18108                                    NotificationId::unique::<OpenPermalinkToLine>(),
18109                                    message,
18110                                ),
18111                                cx,
18112                            )
18113                        })
18114                        .ok();
18115                }
18116            }
18117        })
18118        .detach();
18119    }
18120
18121    pub fn insert_uuid_v4(
18122        &mut self,
18123        _: &InsertUuidV4,
18124        window: &mut Window,
18125        cx: &mut Context<Self>,
18126    ) {
18127        self.insert_uuid(UuidVersion::V4, window, cx);
18128    }
18129
18130    pub fn insert_uuid_v7(
18131        &mut self,
18132        _: &InsertUuidV7,
18133        window: &mut Window,
18134        cx: &mut Context<Self>,
18135    ) {
18136        self.insert_uuid(UuidVersion::V7, window, cx);
18137    }
18138
18139    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18140        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
18141        self.transact(window, cx, |this, window, cx| {
18142            let edits = this
18143                .selections
18144                .all::<Point>(cx)
18145                .into_iter()
18146                .map(|selection| {
18147                    let uuid = match version {
18148                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18149                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18150                    };
18151
18152                    (selection.range(), uuid.to_string())
18153                });
18154            this.edit(edits, cx);
18155            this.refresh_inline_completion(true, false, window, cx);
18156        });
18157    }
18158
18159    pub fn open_selections_in_multibuffer(
18160        &mut self,
18161        _: &OpenSelectionsInMultibuffer,
18162        window: &mut Window,
18163        cx: &mut Context<Self>,
18164    ) {
18165        let multibuffer = self.buffer.read(cx);
18166
18167        let Some(buffer) = multibuffer.as_singleton() else {
18168            return;
18169        };
18170
18171        let Some(workspace) = self.workspace() else {
18172            return;
18173        };
18174
18175        let locations = self
18176            .selections
18177            .disjoint_anchors()
18178            .iter()
18179            .map(|range| Location {
18180                buffer: buffer.clone(),
18181                range: range.start.text_anchor..range.end.text_anchor,
18182            })
18183            .collect::<Vec<_>>();
18184
18185        let title = multibuffer.title(cx).to_string();
18186
18187        cx.spawn_in(window, async move |_, cx| {
18188            workspace.update_in(cx, |workspace, window, cx| {
18189                Self::open_locations_in_multibuffer(
18190                    workspace,
18191                    locations,
18192                    format!("Selections for '{title}'"),
18193                    false,
18194                    MultibufferSelectionMode::All,
18195                    window,
18196                    cx,
18197                );
18198            })
18199        })
18200        .detach();
18201    }
18202
18203    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18204    /// last highlight added will be used.
18205    ///
18206    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18207    pub fn highlight_rows<T: 'static>(
18208        &mut self,
18209        range: Range<Anchor>,
18210        color: Hsla,
18211        options: RowHighlightOptions,
18212        cx: &mut Context<Self>,
18213    ) {
18214        let snapshot = self.buffer().read(cx).snapshot(cx);
18215        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18216        let ix = row_highlights.binary_search_by(|highlight| {
18217            Ordering::Equal
18218                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18219                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18220        });
18221
18222        if let Err(mut ix) = ix {
18223            let index = post_inc(&mut self.highlight_order);
18224
18225            // If this range intersects with the preceding highlight, then merge it with
18226            // the preceding highlight. Otherwise insert a new highlight.
18227            let mut merged = false;
18228            if ix > 0 {
18229                let prev_highlight = &mut row_highlights[ix - 1];
18230                if prev_highlight
18231                    .range
18232                    .end
18233                    .cmp(&range.start, &snapshot)
18234                    .is_ge()
18235                {
18236                    ix -= 1;
18237                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18238                        prev_highlight.range.end = range.end;
18239                    }
18240                    merged = true;
18241                    prev_highlight.index = index;
18242                    prev_highlight.color = color;
18243                    prev_highlight.options = options;
18244                }
18245            }
18246
18247            if !merged {
18248                row_highlights.insert(
18249                    ix,
18250                    RowHighlight {
18251                        range: range.clone(),
18252                        index,
18253                        color,
18254                        options,
18255                        type_id: TypeId::of::<T>(),
18256                    },
18257                );
18258            }
18259
18260            // If any of the following highlights intersect with this one, merge them.
18261            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18262                let highlight = &row_highlights[ix];
18263                if next_highlight
18264                    .range
18265                    .start
18266                    .cmp(&highlight.range.end, &snapshot)
18267                    .is_le()
18268                {
18269                    if next_highlight
18270                        .range
18271                        .end
18272                        .cmp(&highlight.range.end, &snapshot)
18273                        .is_gt()
18274                    {
18275                        row_highlights[ix].range.end = next_highlight.range.end;
18276                    }
18277                    row_highlights.remove(ix + 1);
18278                } else {
18279                    break;
18280                }
18281            }
18282        }
18283    }
18284
18285    /// Remove any highlighted row ranges of the given type that intersect the
18286    /// given ranges.
18287    pub fn remove_highlighted_rows<T: 'static>(
18288        &mut self,
18289        ranges_to_remove: Vec<Range<Anchor>>,
18290        cx: &mut Context<Self>,
18291    ) {
18292        let snapshot = self.buffer().read(cx).snapshot(cx);
18293        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18294        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18295        row_highlights.retain(|highlight| {
18296            while let Some(range_to_remove) = ranges_to_remove.peek() {
18297                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18298                    Ordering::Less | Ordering::Equal => {
18299                        ranges_to_remove.next();
18300                    }
18301                    Ordering::Greater => {
18302                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18303                            Ordering::Less | Ordering::Equal => {
18304                                return false;
18305                            }
18306                            Ordering::Greater => break,
18307                        }
18308                    }
18309                }
18310            }
18311
18312            true
18313        })
18314    }
18315
18316    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18317    pub fn clear_row_highlights<T: 'static>(&mut self) {
18318        self.highlighted_rows.remove(&TypeId::of::<T>());
18319    }
18320
18321    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18322    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18323        self.highlighted_rows
18324            .get(&TypeId::of::<T>())
18325            .map_or(&[] as &[_], |vec| vec.as_slice())
18326            .iter()
18327            .map(|highlight| (highlight.range.clone(), highlight.color))
18328    }
18329
18330    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18331    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18332    /// Allows to ignore certain kinds of highlights.
18333    pub fn highlighted_display_rows(
18334        &self,
18335        window: &mut Window,
18336        cx: &mut App,
18337    ) -> BTreeMap<DisplayRow, LineHighlight> {
18338        let snapshot = self.snapshot(window, cx);
18339        let mut used_highlight_orders = HashMap::default();
18340        self.highlighted_rows
18341            .iter()
18342            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18343            .fold(
18344                BTreeMap::<DisplayRow, LineHighlight>::new(),
18345                |mut unique_rows, highlight| {
18346                    let start = highlight.range.start.to_display_point(&snapshot);
18347                    let end = highlight.range.end.to_display_point(&snapshot);
18348                    let start_row = start.row().0;
18349                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18350                        && end.column() == 0
18351                    {
18352                        end.row().0.saturating_sub(1)
18353                    } else {
18354                        end.row().0
18355                    };
18356                    for row in start_row..=end_row {
18357                        let used_index =
18358                            used_highlight_orders.entry(row).or_insert(highlight.index);
18359                        if highlight.index >= *used_index {
18360                            *used_index = highlight.index;
18361                            unique_rows.insert(
18362                                DisplayRow(row),
18363                                LineHighlight {
18364                                    include_gutter: highlight.options.include_gutter,
18365                                    border: None,
18366                                    background: highlight.color.into(),
18367                                    type_id: Some(highlight.type_id),
18368                                },
18369                            );
18370                        }
18371                    }
18372                    unique_rows
18373                },
18374            )
18375    }
18376
18377    pub fn highlighted_display_row_for_autoscroll(
18378        &self,
18379        snapshot: &DisplaySnapshot,
18380    ) -> Option<DisplayRow> {
18381        self.highlighted_rows
18382            .values()
18383            .flat_map(|highlighted_rows| highlighted_rows.iter())
18384            .filter_map(|highlight| {
18385                if highlight.options.autoscroll {
18386                    Some(highlight.range.start.to_display_point(snapshot).row())
18387                } else {
18388                    None
18389                }
18390            })
18391            .min()
18392    }
18393
18394    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18395        self.highlight_background::<SearchWithinRange>(
18396            ranges,
18397            |colors| colors.editor_document_highlight_read_background,
18398            cx,
18399        )
18400    }
18401
18402    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18403        self.breadcrumb_header = Some(new_header);
18404    }
18405
18406    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18407        self.clear_background_highlights::<SearchWithinRange>(cx);
18408    }
18409
18410    pub fn highlight_background<T: 'static>(
18411        &mut self,
18412        ranges: &[Range<Anchor>],
18413        color_fetcher: fn(&ThemeColors) -> Hsla,
18414        cx: &mut Context<Self>,
18415    ) {
18416        self.background_highlights
18417            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18418        self.scrollbar_marker_state.dirty = true;
18419        cx.notify();
18420    }
18421
18422    pub fn clear_background_highlights<T: 'static>(
18423        &mut self,
18424        cx: &mut Context<Self>,
18425    ) -> Option<BackgroundHighlight> {
18426        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18427        if !text_highlights.1.is_empty() {
18428            self.scrollbar_marker_state.dirty = true;
18429            cx.notify();
18430        }
18431        Some(text_highlights)
18432    }
18433
18434    pub fn highlight_gutter<T: 'static>(
18435        &mut self,
18436        ranges: impl Into<Vec<Range<Anchor>>>,
18437        color_fetcher: fn(&App) -> Hsla,
18438        cx: &mut Context<Self>,
18439    ) {
18440        self.gutter_highlights
18441            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18442        cx.notify();
18443    }
18444
18445    pub fn clear_gutter_highlights<T: 'static>(
18446        &mut self,
18447        cx: &mut Context<Self>,
18448    ) -> Option<GutterHighlight> {
18449        cx.notify();
18450        self.gutter_highlights.remove(&TypeId::of::<T>())
18451    }
18452
18453    pub fn insert_gutter_highlight<T: 'static>(
18454        &mut self,
18455        range: Range<Anchor>,
18456        color_fetcher: fn(&App) -> Hsla,
18457        cx: &mut Context<Self>,
18458    ) {
18459        let snapshot = self.buffer().read(cx).snapshot(cx);
18460        let mut highlights = self
18461            .gutter_highlights
18462            .remove(&TypeId::of::<T>())
18463            .map(|(_, highlights)| highlights)
18464            .unwrap_or_default();
18465        let ix = highlights.binary_search_by(|highlight| {
18466            Ordering::Equal
18467                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18468                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18469        });
18470        if let Err(ix) = ix {
18471            highlights.insert(ix, range);
18472        }
18473        self.gutter_highlights
18474            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18475    }
18476
18477    pub fn remove_gutter_highlights<T: 'static>(
18478        &mut self,
18479        ranges_to_remove: Vec<Range<Anchor>>,
18480        cx: &mut Context<Self>,
18481    ) {
18482        let snapshot = self.buffer().read(cx).snapshot(cx);
18483        let Some((color_fetcher, mut gutter_highlights)) =
18484            self.gutter_highlights.remove(&TypeId::of::<T>())
18485        else {
18486            return;
18487        };
18488        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18489        gutter_highlights.retain(|highlight| {
18490            while let Some(range_to_remove) = ranges_to_remove.peek() {
18491                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18492                    Ordering::Less | Ordering::Equal => {
18493                        ranges_to_remove.next();
18494                    }
18495                    Ordering::Greater => {
18496                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18497                            Ordering::Less | Ordering::Equal => {
18498                                return false;
18499                            }
18500                            Ordering::Greater => break,
18501                        }
18502                    }
18503                }
18504            }
18505
18506            true
18507        });
18508        self.gutter_highlights
18509            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18510    }
18511
18512    #[cfg(feature = "test-support")]
18513    pub fn all_text_background_highlights(
18514        &self,
18515        window: &mut Window,
18516        cx: &mut Context<Self>,
18517    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18518        let snapshot = self.snapshot(window, cx);
18519        let buffer = &snapshot.buffer_snapshot;
18520        let start = buffer.anchor_before(0);
18521        let end = buffer.anchor_after(buffer.len());
18522        let theme = cx.theme().colors();
18523        self.background_highlights_in_range(start..end, &snapshot, theme)
18524    }
18525
18526    #[cfg(feature = "test-support")]
18527    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18528        let snapshot = self.buffer().read(cx).snapshot(cx);
18529
18530        let highlights = self
18531            .background_highlights
18532            .get(&TypeId::of::<items::BufferSearchHighlights>());
18533
18534        if let Some((_color, ranges)) = highlights {
18535            ranges
18536                .iter()
18537                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18538                .collect_vec()
18539        } else {
18540            vec![]
18541        }
18542    }
18543
18544    fn document_highlights_for_position<'a>(
18545        &'a self,
18546        position: Anchor,
18547        buffer: &'a MultiBufferSnapshot,
18548    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18549        let read_highlights = self
18550            .background_highlights
18551            .get(&TypeId::of::<DocumentHighlightRead>())
18552            .map(|h| &h.1);
18553        let write_highlights = self
18554            .background_highlights
18555            .get(&TypeId::of::<DocumentHighlightWrite>())
18556            .map(|h| &h.1);
18557        let left_position = position.bias_left(buffer);
18558        let right_position = position.bias_right(buffer);
18559        read_highlights
18560            .into_iter()
18561            .chain(write_highlights)
18562            .flat_map(move |ranges| {
18563                let start_ix = match ranges.binary_search_by(|probe| {
18564                    let cmp = probe.end.cmp(&left_position, buffer);
18565                    if cmp.is_ge() {
18566                        Ordering::Greater
18567                    } else {
18568                        Ordering::Less
18569                    }
18570                }) {
18571                    Ok(i) | Err(i) => i,
18572                };
18573
18574                ranges[start_ix..]
18575                    .iter()
18576                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18577            })
18578    }
18579
18580    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18581        self.background_highlights
18582            .get(&TypeId::of::<T>())
18583            .map_or(false, |(_, highlights)| !highlights.is_empty())
18584    }
18585
18586    pub fn background_highlights_in_range(
18587        &self,
18588        search_range: Range<Anchor>,
18589        display_snapshot: &DisplaySnapshot,
18590        theme: &ThemeColors,
18591    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18592        let mut results = Vec::new();
18593        for (color_fetcher, ranges) in self.background_highlights.values() {
18594            let color = color_fetcher(theme);
18595            let start_ix = match ranges.binary_search_by(|probe| {
18596                let cmp = probe
18597                    .end
18598                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18599                if cmp.is_gt() {
18600                    Ordering::Greater
18601                } else {
18602                    Ordering::Less
18603                }
18604            }) {
18605                Ok(i) | Err(i) => i,
18606            };
18607            for range in &ranges[start_ix..] {
18608                if range
18609                    .start
18610                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18611                    .is_ge()
18612                {
18613                    break;
18614                }
18615
18616                let start = range.start.to_display_point(display_snapshot);
18617                let end = range.end.to_display_point(display_snapshot);
18618                results.push((start..end, color))
18619            }
18620        }
18621        results
18622    }
18623
18624    pub fn background_highlight_row_ranges<T: 'static>(
18625        &self,
18626        search_range: Range<Anchor>,
18627        display_snapshot: &DisplaySnapshot,
18628        count: usize,
18629    ) -> Vec<RangeInclusive<DisplayPoint>> {
18630        let mut results = Vec::new();
18631        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18632            return vec![];
18633        };
18634
18635        let start_ix = match ranges.binary_search_by(|probe| {
18636            let cmp = probe
18637                .end
18638                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18639            if cmp.is_gt() {
18640                Ordering::Greater
18641            } else {
18642                Ordering::Less
18643            }
18644        }) {
18645            Ok(i) | Err(i) => i,
18646        };
18647        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18648            if let (Some(start_display), Some(end_display)) = (start, end) {
18649                results.push(
18650                    start_display.to_display_point(display_snapshot)
18651                        ..=end_display.to_display_point(display_snapshot),
18652                );
18653            }
18654        };
18655        let mut start_row: Option<Point> = None;
18656        let mut end_row: Option<Point> = None;
18657        if ranges.len() > count {
18658            return Vec::new();
18659        }
18660        for range in &ranges[start_ix..] {
18661            if range
18662                .start
18663                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18664                .is_ge()
18665            {
18666                break;
18667            }
18668            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18669            if let Some(current_row) = &end_row {
18670                if end.row == current_row.row {
18671                    continue;
18672                }
18673            }
18674            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18675            if start_row.is_none() {
18676                assert_eq!(end_row, None);
18677                start_row = Some(start);
18678                end_row = Some(end);
18679                continue;
18680            }
18681            if let Some(current_end) = end_row.as_mut() {
18682                if start.row > current_end.row + 1 {
18683                    push_region(start_row, end_row);
18684                    start_row = Some(start);
18685                    end_row = Some(end);
18686                } else {
18687                    // Merge two hunks.
18688                    *current_end = end;
18689                }
18690            } else {
18691                unreachable!();
18692            }
18693        }
18694        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18695        push_region(start_row, end_row);
18696        results
18697    }
18698
18699    pub fn gutter_highlights_in_range(
18700        &self,
18701        search_range: Range<Anchor>,
18702        display_snapshot: &DisplaySnapshot,
18703        cx: &App,
18704    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18705        let mut results = Vec::new();
18706        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18707            let color = color_fetcher(cx);
18708            let start_ix = match ranges.binary_search_by(|probe| {
18709                let cmp = probe
18710                    .end
18711                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18712                if cmp.is_gt() {
18713                    Ordering::Greater
18714                } else {
18715                    Ordering::Less
18716                }
18717            }) {
18718                Ok(i) | Err(i) => i,
18719            };
18720            for range in &ranges[start_ix..] {
18721                if range
18722                    .start
18723                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18724                    .is_ge()
18725                {
18726                    break;
18727                }
18728
18729                let start = range.start.to_display_point(display_snapshot);
18730                let end = range.end.to_display_point(display_snapshot);
18731                results.push((start..end, color))
18732            }
18733        }
18734        results
18735    }
18736
18737    /// Get the text ranges corresponding to the redaction query
18738    pub fn redacted_ranges(
18739        &self,
18740        search_range: Range<Anchor>,
18741        display_snapshot: &DisplaySnapshot,
18742        cx: &App,
18743    ) -> Vec<Range<DisplayPoint>> {
18744        display_snapshot
18745            .buffer_snapshot
18746            .redacted_ranges(search_range, |file| {
18747                if let Some(file) = file {
18748                    file.is_private()
18749                        && EditorSettings::get(
18750                            Some(SettingsLocation {
18751                                worktree_id: file.worktree_id(cx),
18752                                path: file.path().as_ref(),
18753                            }),
18754                            cx,
18755                        )
18756                        .redact_private_values
18757                } else {
18758                    false
18759                }
18760            })
18761            .map(|range| {
18762                range.start.to_display_point(display_snapshot)
18763                    ..range.end.to_display_point(display_snapshot)
18764            })
18765            .collect()
18766    }
18767
18768    pub fn highlight_text<T: 'static>(
18769        &mut self,
18770        ranges: Vec<Range<Anchor>>,
18771        style: HighlightStyle,
18772        cx: &mut Context<Self>,
18773    ) {
18774        self.display_map.update(cx, |map, _| {
18775            map.highlight_text(TypeId::of::<T>(), ranges, style)
18776        });
18777        cx.notify();
18778    }
18779
18780    pub(crate) fn highlight_inlays<T: 'static>(
18781        &mut self,
18782        highlights: Vec<InlayHighlight>,
18783        style: HighlightStyle,
18784        cx: &mut Context<Self>,
18785    ) {
18786        self.display_map.update(cx, |map, _| {
18787            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18788        });
18789        cx.notify();
18790    }
18791
18792    pub fn text_highlights<'a, T: 'static>(
18793        &'a self,
18794        cx: &'a App,
18795    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18796        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18797    }
18798
18799    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18800        let cleared = self
18801            .display_map
18802            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18803        if cleared {
18804            cx.notify();
18805        }
18806    }
18807
18808    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18809        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18810            && self.focus_handle.is_focused(window)
18811    }
18812
18813    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18814        self.show_cursor_when_unfocused = is_enabled;
18815        cx.notify();
18816    }
18817
18818    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18819        cx.notify();
18820    }
18821
18822    fn on_debug_session_event(
18823        &mut self,
18824        _session: Entity<Session>,
18825        event: &SessionEvent,
18826        cx: &mut Context<Self>,
18827    ) {
18828        match event {
18829            SessionEvent::InvalidateInlineValue => {
18830                self.refresh_inline_values(cx);
18831            }
18832            _ => {}
18833        }
18834    }
18835
18836    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18837        let Some(project) = self.project.clone() else {
18838            return;
18839        };
18840
18841        if !self.inline_value_cache.enabled {
18842            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18843            self.splice_inlays(&inlays, Vec::new(), cx);
18844            return;
18845        }
18846
18847        let current_execution_position = self
18848            .highlighted_rows
18849            .get(&TypeId::of::<ActiveDebugLine>())
18850            .and_then(|lines| lines.last().map(|line| line.range.start));
18851
18852        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18853            let inline_values = editor
18854                .update(cx, |editor, cx| {
18855                    let Some(current_execution_position) = current_execution_position else {
18856                        return Some(Task::ready(Ok(Vec::new())));
18857                    };
18858
18859                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18860                        let snapshot = buffer.snapshot(cx);
18861
18862                        let excerpt = snapshot.excerpt_containing(
18863                            current_execution_position..current_execution_position,
18864                        )?;
18865
18866                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18867                    })?;
18868
18869                    let range =
18870                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18871
18872                    project.inline_values(buffer, range, cx)
18873                })
18874                .ok()
18875                .flatten()?
18876                .await
18877                .context("refreshing debugger inlays")
18878                .log_err()?;
18879
18880            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18881
18882            for (buffer_id, inline_value) in inline_values
18883                .into_iter()
18884                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18885            {
18886                buffer_inline_values
18887                    .entry(buffer_id)
18888                    .or_default()
18889                    .push(inline_value);
18890            }
18891
18892            editor
18893                .update(cx, |editor, cx| {
18894                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18895                    let mut new_inlays = Vec::default();
18896
18897                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18898                        let buffer_id = buffer_snapshot.remote_id();
18899                        buffer_inline_values
18900                            .get(&buffer_id)
18901                            .into_iter()
18902                            .flatten()
18903                            .for_each(|hint| {
18904                                let inlay = Inlay::debugger_hint(
18905                                    post_inc(&mut editor.next_inlay_id),
18906                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18907                                    hint.text(),
18908                                );
18909
18910                                new_inlays.push(inlay);
18911                            });
18912                    }
18913
18914                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18915                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18916
18917                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18918                })
18919                .ok()?;
18920            Some(())
18921        });
18922    }
18923
18924    fn on_buffer_event(
18925        &mut self,
18926        multibuffer: &Entity<MultiBuffer>,
18927        event: &multi_buffer::Event,
18928        window: &mut Window,
18929        cx: &mut Context<Self>,
18930    ) {
18931        match event {
18932            multi_buffer::Event::Edited {
18933                singleton_buffer_edited,
18934                edited_buffer,
18935            } => {
18936                self.scrollbar_marker_state.dirty = true;
18937                self.active_indent_guides_state.dirty = true;
18938                self.refresh_active_diagnostics(cx);
18939                self.refresh_code_actions(window, cx);
18940                self.refresh_selected_text_highlights(true, window, cx);
18941                refresh_matching_bracket_highlights(self, window, cx);
18942                if self.has_active_inline_completion() {
18943                    self.update_visible_inline_completion(window, cx);
18944                }
18945                if let Some(project) = self.project.as_ref() {
18946                    if let Some(edited_buffer) = edited_buffer {
18947                        project.update(cx, |project, cx| {
18948                            self.registered_buffers
18949                                .entry(edited_buffer.read(cx).remote_id())
18950                                .or_insert_with(|| {
18951                                    project
18952                                        .register_buffer_with_language_servers(&edited_buffer, cx)
18953                                });
18954                        });
18955                        if edited_buffer.read(cx).file().is_some() {
18956                            self.pull_diagnostics(
18957                                Some(edited_buffer.read(cx).remote_id()),
18958                                window,
18959                                cx,
18960                            );
18961                        }
18962                    }
18963                }
18964                cx.emit(EditorEvent::BufferEdited);
18965                cx.emit(SearchEvent::MatchesInvalidated);
18966                if *singleton_buffer_edited {
18967                    if let Some(buffer) = edited_buffer {
18968                        if buffer.read(cx).file().is_none() {
18969                            cx.emit(EditorEvent::TitleChanged);
18970                        }
18971                    }
18972                    if let Some(project) = &self.project {
18973                        #[allow(clippy::mutable_key_type)]
18974                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18975                            multibuffer
18976                                .all_buffers()
18977                                .into_iter()
18978                                .filter_map(|buffer| {
18979                                    buffer.update(cx, |buffer, cx| {
18980                                        let language = buffer.language()?;
18981                                        let should_discard = project.update(cx, |project, cx| {
18982                                            project.is_local()
18983                                                && !project.has_language_servers_for(buffer, cx)
18984                                        });
18985                                        should_discard.not().then_some(language.clone())
18986                                    })
18987                                })
18988                                .collect::<HashSet<_>>()
18989                        });
18990                        if !languages_affected.is_empty() {
18991                            self.refresh_inlay_hints(
18992                                InlayHintRefreshReason::BufferEdited(languages_affected),
18993                                cx,
18994                            );
18995                        }
18996                    }
18997                }
18998
18999                let Some(project) = &self.project else { return };
19000                let (telemetry, is_via_ssh) = {
19001                    let project = project.read(cx);
19002                    let telemetry = project.client().telemetry().clone();
19003                    let is_via_ssh = project.is_via_ssh();
19004                    (telemetry, is_via_ssh)
19005                };
19006                refresh_linked_ranges(self, window, cx);
19007                telemetry.log_edit_event("editor", is_via_ssh);
19008            }
19009            multi_buffer::Event::ExcerptsAdded {
19010                buffer,
19011                predecessor,
19012                excerpts,
19013            } => {
19014                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19015                let buffer_id = buffer.read(cx).remote_id();
19016                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19017                    if let Some(project) = &self.project {
19018                        update_uncommitted_diff_for_buffer(
19019                            cx.entity(),
19020                            project,
19021                            [buffer.clone()],
19022                            self.buffer.clone(),
19023                            cx,
19024                        )
19025                        .detach();
19026                    }
19027                }
19028                cx.emit(EditorEvent::ExcerptsAdded {
19029                    buffer: buffer.clone(),
19030                    predecessor: *predecessor,
19031                    excerpts: excerpts.clone(),
19032                });
19033                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19034            }
19035            multi_buffer::Event::ExcerptsRemoved {
19036                ids,
19037                removed_buffer_ids,
19038            } => {
19039                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19040                let buffer = self.buffer.read(cx);
19041                self.registered_buffers
19042                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19043                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19044                cx.emit(EditorEvent::ExcerptsRemoved {
19045                    ids: ids.clone(),
19046                    removed_buffer_ids: removed_buffer_ids.clone(),
19047                })
19048            }
19049            multi_buffer::Event::ExcerptsEdited {
19050                excerpt_ids,
19051                buffer_ids,
19052            } => {
19053                self.display_map.update(cx, |map, cx| {
19054                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19055                });
19056                cx.emit(EditorEvent::ExcerptsEdited {
19057                    ids: excerpt_ids.clone(),
19058                })
19059            }
19060            multi_buffer::Event::ExcerptsExpanded { ids } => {
19061                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19062                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19063            }
19064            multi_buffer::Event::Reparsed(buffer_id) => {
19065                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19066                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19067
19068                cx.emit(EditorEvent::Reparsed(*buffer_id));
19069            }
19070            multi_buffer::Event::DiffHunksToggled => {
19071                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19072            }
19073            multi_buffer::Event::LanguageChanged(buffer_id) => {
19074                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19075                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19076                cx.emit(EditorEvent::Reparsed(*buffer_id));
19077                cx.notify();
19078            }
19079            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19080            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19081            multi_buffer::Event::FileHandleChanged
19082            | multi_buffer::Event::Reloaded
19083            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19084            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19085            multi_buffer::Event::DiagnosticsUpdated => {
19086                self.update_diagnostics_state(window, cx);
19087            }
19088            _ => {}
19089        };
19090    }
19091
19092    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19093        self.refresh_active_diagnostics(cx);
19094        self.refresh_inline_diagnostics(true, window, cx);
19095        self.scrollbar_marker_state.dirty = true;
19096        cx.notify();
19097    }
19098
19099    pub fn start_temporary_diff_override(&mut self) {
19100        self.load_diff_task.take();
19101        self.temporary_diff_override = true;
19102    }
19103
19104    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19105        self.temporary_diff_override = false;
19106        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19107        self.buffer.update(cx, |buffer, cx| {
19108            buffer.set_all_diff_hunks_collapsed(cx);
19109        });
19110
19111        if let Some(project) = self.project.clone() {
19112            self.load_diff_task = Some(
19113                update_uncommitted_diff_for_buffer(
19114                    cx.entity(),
19115                    &project,
19116                    self.buffer.read(cx).all_buffers(),
19117                    self.buffer.clone(),
19118                    cx,
19119                )
19120                .shared(),
19121            );
19122        }
19123    }
19124
19125    fn on_display_map_changed(
19126        &mut self,
19127        _: Entity<DisplayMap>,
19128        _: &mut Window,
19129        cx: &mut Context<Self>,
19130    ) {
19131        cx.notify();
19132    }
19133
19134    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19135        let new_severity = if self.diagnostics_enabled() {
19136            EditorSettings::get_global(cx)
19137                .diagnostics_max_severity
19138                .unwrap_or(DiagnosticSeverity::Hint)
19139        } else {
19140            DiagnosticSeverity::Off
19141        };
19142        self.set_max_diagnostics_severity(new_severity, cx);
19143        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19144        self.update_edit_prediction_settings(cx);
19145        self.refresh_inline_completion(true, false, window, cx);
19146        self.refresh_inlay_hints(
19147            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19148                self.selections.newest_anchor().head(),
19149                &self.buffer.read(cx).snapshot(cx),
19150                cx,
19151            )),
19152            cx,
19153        );
19154
19155        let old_cursor_shape = self.cursor_shape;
19156
19157        {
19158            let editor_settings = EditorSettings::get_global(cx);
19159            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19160            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19161            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19162            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19163            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19164        }
19165
19166        if old_cursor_shape != self.cursor_shape {
19167            cx.emit(EditorEvent::CursorShapeChanged);
19168        }
19169
19170        let project_settings = ProjectSettings::get_global(cx);
19171        self.serialize_dirty_buffers =
19172            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19173
19174        if self.mode.is_full() {
19175            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19176            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19177            if self.show_inline_diagnostics != show_inline_diagnostics {
19178                self.show_inline_diagnostics = show_inline_diagnostics;
19179                self.refresh_inline_diagnostics(false, window, cx);
19180            }
19181
19182            if self.git_blame_inline_enabled != inline_blame_enabled {
19183                self.toggle_git_blame_inline_internal(false, window, cx);
19184            }
19185
19186            let minimap_settings = EditorSettings::get_global(cx).minimap;
19187            if self.minimap_visibility != MinimapVisibility::Disabled {
19188                if self.minimap_visibility.settings_visibility()
19189                    != minimap_settings.minimap_enabled()
19190                {
19191                    self.set_minimap_visibility(
19192                        MinimapVisibility::for_mode(self.mode(), cx),
19193                        window,
19194                        cx,
19195                    );
19196                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19197                    minimap_entity.update(cx, |minimap_editor, cx| {
19198                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19199                    })
19200                }
19201            }
19202        }
19203
19204        cx.notify();
19205    }
19206
19207    pub fn set_searchable(&mut self, searchable: bool) {
19208        self.searchable = searchable;
19209    }
19210
19211    pub fn searchable(&self) -> bool {
19212        self.searchable
19213    }
19214
19215    fn open_proposed_changes_editor(
19216        &mut self,
19217        _: &OpenProposedChangesEditor,
19218        window: &mut Window,
19219        cx: &mut Context<Self>,
19220    ) {
19221        let Some(workspace) = self.workspace() else {
19222            cx.propagate();
19223            return;
19224        };
19225
19226        let selections = self.selections.all::<usize>(cx);
19227        let multi_buffer = self.buffer.read(cx);
19228        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19229        let mut new_selections_by_buffer = HashMap::default();
19230        for selection in selections {
19231            for (buffer, range, _) in
19232                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19233            {
19234                let mut range = range.to_point(buffer);
19235                range.start.column = 0;
19236                range.end.column = buffer.line_len(range.end.row);
19237                new_selections_by_buffer
19238                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19239                    .or_insert(Vec::new())
19240                    .push(range)
19241            }
19242        }
19243
19244        let proposed_changes_buffers = new_selections_by_buffer
19245            .into_iter()
19246            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19247            .collect::<Vec<_>>();
19248        let proposed_changes_editor = cx.new(|cx| {
19249            ProposedChangesEditor::new(
19250                "Proposed changes",
19251                proposed_changes_buffers,
19252                self.project.clone(),
19253                window,
19254                cx,
19255            )
19256        });
19257
19258        window.defer(cx, move |window, cx| {
19259            workspace.update(cx, |workspace, cx| {
19260                workspace.active_pane().update(cx, |pane, cx| {
19261                    pane.add_item(
19262                        Box::new(proposed_changes_editor),
19263                        true,
19264                        true,
19265                        None,
19266                        window,
19267                        cx,
19268                    );
19269                });
19270            });
19271        });
19272    }
19273
19274    pub fn open_excerpts_in_split(
19275        &mut self,
19276        _: &OpenExcerptsSplit,
19277        window: &mut Window,
19278        cx: &mut Context<Self>,
19279    ) {
19280        self.open_excerpts_common(None, true, window, cx)
19281    }
19282
19283    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19284        self.open_excerpts_common(None, false, window, cx)
19285    }
19286
19287    fn open_excerpts_common(
19288        &mut self,
19289        jump_data: Option<JumpData>,
19290        split: bool,
19291        window: &mut Window,
19292        cx: &mut Context<Self>,
19293    ) {
19294        let Some(workspace) = self.workspace() else {
19295            cx.propagate();
19296            return;
19297        };
19298
19299        if self.buffer.read(cx).is_singleton() {
19300            cx.propagate();
19301            return;
19302        }
19303
19304        let mut new_selections_by_buffer = HashMap::default();
19305        match &jump_data {
19306            Some(JumpData::MultiBufferPoint {
19307                excerpt_id,
19308                position,
19309                anchor,
19310                line_offset_from_top,
19311            }) => {
19312                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19313                if let Some(buffer) = multi_buffer_snapshot
19314                    .buffer_id_for_excerpt(*excerpt_id)
19315                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19316                {
19317                    let buffer_snapshot = buffer.read(cx).snapshot();
19318                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19319                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19320                    } else {
19321                        buffer_snapshot.clip_point(*position, Bias::Left)
19322                    };
19323                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19324                    new_selections_by_buffer.insert(
19325                        buffer,
19326                        (
19327                            vec![jump_to_offset..jump_to_offset],
19328                            Some(*line_offset_from_top),
19329                        ),
19330                    );
19331                }
19332            }
19333            Some(JumpData::MultiBufferRow {
19334                row,
19335                line_offset_from_top,
19336            }) => {
19337                let point = MultiBufferPoint::new(row.0, 0);
19338                if let Some((buffer, buffer_point, _)) =
19339                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19340                {
19341                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19342                    new_selections_by_buffer
19343                        .entry(buffer)
19344                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19345                        .0
19346                        .push(buffer_offset..buffer_offset)
19347                }
19348            }
19349            None => {
19350                let selections = self.selections.all::<usize>(cx);
19351                let multi_buffer = self.buffer.read(cx);
19352                for selection in selections {
19353                    for (snapshot, range, _, anchor) in multi_buffer
19354                        .snapshot(cx)
19355                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19356                    {
19357                        if let Some(anchor) = anchor {
19358                            // selection is in a deleted hunk
19359                            let Some(buffer_id) = anchor.buffer_id else {
19360                                continue;
19361                            };
19362                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19363                                continue;
19364                            };
19365                            let offset = text::ToOffset::to_offset(
19366                                &anchor.text_anchor,
19367                                &buffer_handle.read(cx).snapshot(),
19368                            );
19369                            let range = offset..offset;
19370                            new_selections_by_buffer
19371                                .entry(buffer_handle)
19372                                .or_insert((Vec::new(), None))
19373                                .0
19374                                .push(range)
19375                        } else {
19376                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19377                            else {
19378                                continue;
19379                            };
19380                            new_selections_by_buffer
19381                                .entry(buffer_handle)
19382                                .or_insert((Vec::new(), None))
19383                                .0
19384                                .push(range)
19385                        }
19386                    }
19387                }
19388            }
19389        }
19390
19391        new_selections_by_buffer
19392            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19393
19394        if new_selections_by_buffer.is_empty() {
19395            return;
19396        }
19397
19398        // We defer the pane interaction because we ourselves are a workspace item
19399        // and activating a new item causes the pane to call a method on us reentrantly,
19400        // which panics if we're on the stack.
19401        window.defer(cx, move |window, cx| {
19402            workspace.update(cx, |workspace, cx| {
19403                let pane = if split {
19404                    workspace.adjacent_pane(window, cx)
19405                } else {
19406                    workspace.active_pane().clone()
19407                };
19408
19409                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19410                    let editor = buffer
19411                        .read(cx)
19412                        .file()
19413                        .is_none()
19414                        .then(|| {
19415                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19416                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19417                            // Instead, we try to activate the existing editor in the pane first.
19418                            let (editor, pane_item_index) =
19419                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19420                                    let editor = item.downcast::<Editor>()?;
19421                                    let singleton_buffer =
19422                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19423                                    if singleton_buffer == buffer {
19424                                        Some((editor, i))
19425                                    } else {
19426                                        None
19427                                    }
19428                                })?;
19429                            pane.update(cx, |pane, cx| {
19430                                pane.activate_item(pane_item_index, true, true, window, cx)
19431                            });
19432                            Some(editor)
19433                        })
19434                        .flatten()
19435                        .unwrap_or_else(|| {
19436                            workspace.open_project_item::<Self>(
19437                                pane.clone(),
19438                                buffer,
19439                                true,
19440                                true,
19441                                window,
19442                                cx,
19443                            )
19444                        });
19445
19446                    editor.update(cx, |editor, cx| {
19447                        let autoscroll = match scroll_offset {
19448                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19449                            None => Autoscroll::newest(),
19450                        };
19451                        let nav_history = editor.nav_history.take();
19452                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19453                            s.select_ranges(ranges);
19454                        });
19455                        editor.nav_history = nav_history;
19456                    });
19457                }
19458            })
19459        });
19460    }
19461
19462    // For now, don't allow opening excerpts in buffers that aren't backed by
19463    // regular project files.
19464    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19465        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19466    }
19467
19468    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19469        let snapshot = self.buffer.read(cx).read(cx);
19470        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19471        Some(
19472            ranges
19473                .iter()
19474                .map(move |range| {
19475                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19476                })
19477                .collect(),
19478        )
19479    }
19480
19481    fn selection_replacement_ranges(
19482        &self,
19483        range: Range<OffsetUtf16>,
19484        cx: &mut App,
19485    ) -> Vec<Range<OffsetUtf16>> {
19486        let selections = self.selections.all::<OffsetUtf16>(cx);
19487        let newest_selection = selections
19488            .iter()
19489            .max_by_key(|selection| selection.id)
19490            .unwrap();
19491        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19492        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19493        let snapshot = self.buffer.read(cx).read(cx);
19494        selections
19495            .into_iter()
19496            .map(|mut selection| {
19497                selection.start.0 =
19498                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19499                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19500                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19501                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19502            })
19503            .collect()
19504    }
19505
19506    fn report_editor_event(
19507        &self,
19508        event_type: &'static str,
19509        file_extension: Option<String>,
19510        cx: &App,
19511    ) {
19512        if cfg!(any(test, feature = "test-support")) {
19513            return;
19514        }
19515
19516        let Some(project) = &self.project else { return };
19517
19518        // If None, we are in a file without an extension
19519        let file = self
19520            .buffer
19521            .read(cx)
19522            .as_singleton()
19523            .and_then(|b| b.read(cx).file());
19524        let file_extension = file_extension.or(file
19525            .as_ref()
19526            .and_then(|file| Path::new(file.file_name(cx)).extension())
19527            .and_then(|e| e.to_str())
19528            .map(|a| a.to_string()));
19529
19530        let vim_mode = vim_enabled(cx);
19531
19532        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19533        let copilot_enabled = edit_predictions_provider
19534            == language::language_settings::EditPredictionProvider::Copilot;
19535        let copilot_enabled_for_language = self
19536            .buffer
19537            .read(cx)
19538            .language_settings(cx)
19539            .show_edit_predictions;
19540
19541        let project = project.read(cx);
19542        telemetry::event!(
19543            event_type,
19544            file_extension,
19545            vim_mode,
19546            copilot_enabled,
19547            copilot_enabled_for_language,
19548            edit_predictions_provider,
19549            is_via_ssh = project.is_via_ssh(),
19550        );
19551    }
19552
19553    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19554    /// with each line being an array of {text, highlight} objects.
19555    fn copy_highlight_json(
19556        &mut self,
19557        _: &CopyHighlightJson,
19558        window: &mut Window,
19559        cx: &mut Context<Self>,
19560    ) {
19561        #[derive(Serialize)]
19562        struct Chunk<'a> {
19563            text: String,
19564            highlight: Option<&'a str>,
19565        }
19566
19567        let snapshot = self.buffer.read(cx).snapshot(cx);
19568        let range = self
19569            .selected_text_range(false, window, cx)
19570            .and_then(|selection| {
19571                if selection.range.is_empty() {
19572                    None
19573                } else {
19574                    Some(selection.range)
19575                }
19576            })
19577            .unwrap_or_else(|| 0..snapshot.len());
19578
19579        let chunks = snapshot.chunks(range, true);
19580        let mut lines = Vec::new();
19581        let mut line: VecDeque<Chunk> = VecDeque::new();
19582
19583        let Some(style) = self.style.as_ref() else {
19584            return;
19585        };
19586
19587        for chunk in chunks {
19588            let highlight = chunk
19589                .syntax_highlight_id
19590                .and_then(|id| id.name(&style.syntax));
19591            let mut chunk_lines = chunk.text.split('\n').peekable();
19592            while let Some(text) = chunk_lines.next() {
19593                let mut merged_with_last_token = false;
19594                if let Some(last_token) = line.back_mut() {
19595                    if last_token.highlight == highlight {
19596                        last_token.text.push_str(text);
19597                        merged_with_last_token = true;
19598                    }
19599                }
19600
19601                if !merged_with_last_token {
19602                    line.push_back(Chunk {
19603                        text: text.into(),
19604                        highlight,
19605                    });
19606                }
19607
19608                if chunk_lines.peek().is_some() {
19609                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19610                        line.pop_front();
19611                    }
19612                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19613                        line.pop_back();
19614                    }
19615
19616                    lines.push(mem::take(&mut line));
19617                }
19618            }
19619        }
19620
19621        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19622            return;
19623        };
19624        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19625    }
19626
19627    pub fn open_context_menu(
19628        &mut self,
19629        _: &OpenContextMenu,
19630        window: &mut Window,
19631        cx: &mut Context<Self>,
19632    ) {
19633        self.request_autoscroll(Autoscroll::newest(), cx);
19634        let position = self.selections.newest_display(cx).start;
19635        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19636    }
19637
19638    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19639        &self.inlay_hint_cache
19640    }
19641
19642    pub fn replay_insert_event(
19643        &mut self,
19644        text: &str,
19645        relative_utf16_range: Option<Range<isize>>,
19646        window: &mut Window,
19647        cx: &mut Context<Self>,
19648    ) {
19649        if !self.input_enabled {
19650            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19651            return;
19652        }
19653        if let Some(relative_utf16_range) = relative_utf16_range {
19654            let selections = self.selections.all::<OffsetUtf16>(cx);
19655            self.change_selections(None, window, cx, |s| {
19656                let new_ranges = selections.into_iter().map(|range| {
19657                    let start = OffsetUtf16(
19658                        range
19659                            .head()
19660                            .0
19661                            .saturating_add_signed(relative_utf16_range.start),
19662                    );
19663                    let end = OffsetUtf16(
19664                        range
19665                            .head()
19666                            .0
19667                            .saturating_add_signed(relative_utf16_range.end),
19668                    );
19669                    start..end
19670                });
19671                s.select_ranges(new_ranges);
19672            });
19673        }
19674
19675        self.handle_input(text, window, cx);
19676    }
19677
19678    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19679        let Some(provider) = self.semantics_provider.as_ref() else {
19680            return false;
19681        };
19682
19683        let mut supports = false;
19684        self.buffer().update(cx, |this, cx| {
19685            this.for_each_buffer(|buffer| {
19686                supports |= provider.supports_inlay_hints(buffer, cx);
19687            });
19688        });
19689
19690        supports
19691    }
19692
19693    pub fn is_focused(&self, window: &Window) -> bool {
19694        self.focus_handle.is_focused(window)
19695    }
19696
19697    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19698        cx.emit(EditorEvent::Focused);
19699
19700        if let Some(descendant) = self
19701            .last_focused_descendant
19702            .take()
19703            .and_then(|descendant| descendant.upgrade())
19704        {
19705            window.focus(&descendant);
19706        } else {
19707            if let Some(blame) = self.blame.as_ref() {
19708                blame.update(cx, GitBlame::focus)
19709            }
19710
19711            self.blink_manager.update(cx, BlinkManager::enable);
19712            self.show_cursor_names(window, cx);
19713            self.buffer.update(cx, |buffer, cx| {
19714                buffer.finalize_last_transaction(cx);
19715                if self.leader_id.is_none() {
19716                    buffer.set_active_selections(
19717                        &self.selections.disjoint_anchors(),
19718                        self.selections.line_mode,
19719                        self.cursor_shape,
19720                        cx,
19721                    );
19722                }
19723            });
19724        }
19725    }
19726
19727    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19728        cx.emit(EditorEvent::FocusedIn)
19729    }
19730
19731    fn handle_focus_out(
19732        &mut self,
19733        event: FocusOutEvent,
19734        _window: &mut Window,
19735        cx: &mut Context<Self>,
19736    ) {
19737        if event.blurred != self.focus_handle {
19738            self.last_focused_descendant = Some(event.blurred);
19739        }
19740        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19741    }
19742
19743    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19744        self.blink_manager.update(cx, BlinkManager::disable);
19745        self.buffer
19746            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19747
19748        if let Some(blame) = self.blame.as_ref() {
19749            blame.update(cx, GitBlame::blur)
19750        }
19751        if !self.hover_state.focused(window, cx) {
19752            hide_hover(self, cx);
19753        }
19754        if !self
19755            .context_menu
19756            .borrow()
19757            .as_ref()
19758            .is_some_and(|context_menu| context_menu.focused(window, cx))
19759        {
19760            self.hide_context_menu(window, cx);
19761        }
19762        self.discard_inline_completion(false, cx);
19763        cx.emit(EditorEvent::Blurred);
19764        cx.notify();
19765    }
19766
19767    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19768        let mut pending: String = window
19769            .pending_input_keystrokes()
19770            .into_iter()
19771            .flatten()
19772            .filter_map(|keystroke| {
19773                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19774                    keystroke.key_char.clone()
19775                } else {
19776                    None
19777                }
19778            })
19779            .collect();
19780
19781        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19782            pending = "".to_string();
19783        }
19784
19785        let existing_pending = self
19786            .text_highlights::<PendingInput>(cx)
19787            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
19788        if existing_pending.is_none() && pending.is_empty() {
19789            return;
19790        }
19791        let transaction =
19792            self.transact(window, cx, |this, window, cx| {
19793                let selections = this.selections.all::<usize>(cx);
19794                let edits = selections
19795                    .iter()
19796                    .map(|selection| (selection.end..selection.end, pending.clone()));
19797                this.edit(edits, cx);
19798                this.change_selections(None, window, cx, |s| {
19799                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19800                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19801                    }));
19802                });
19803                if let Some(existing_ranges) = existing_pending {
19804                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19805                    this.edit(edits, cx);
19806                }
19807            });
19808
19809        let snapshot = self.snapshot(window, cx);
19810        let ranges = self
19811            .selections
19812            .all::<usize>(cx)
19813            .into_iter()
19814            .map(|selection| {
19815                snapshot.buffer_snapshot.anchor_after(selection.end)
19816                    ..snapshot
19817                        .buffer_snapshot
19818                        .anchor_before(selection.end + pending.len())
19819            })
19820            .collect();
19821
19822        if pending.is_empty() {
19823            self.clear_highlights::<PendingInput>(cx);
19824        } else {
19825            self.highlight_text::<PendingInput>(
19826                ranges,
19827                HighlightStyle {
19828                    underline: Some(UnderlineStyle {
19829                        thickness: px(1.),
19830                        color: None,
19831                        wavy: false,
19832                    }),
19833                    ..Default::default()
19834                },
19835                cx,
19836            );
19837        }
19838
19839        self.ime_transaction = self.ime_transaction.or(transaction);
19840        if let Some(transaction) = self.ime_transaction {
19841            self.buffer.update(cx, |buffer, cx| {
19842                buffer.group_until_transaction(transaction, cx);
19843            });
19844        }
19845
19846        if self.text_highlights::<PendingInput>(cx).is_none() {
19847            self.ime_transaction.take();
19848        }
19849    }
19850
19851    pub fn register_action_renderer(
19852        &mut self,
19853        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
19854    ) -> Subscription {
19855        let id = self.next_editor_action_id.post_inc();
19856        self.editor_actions
19857            .borrow_mut()
19858            .insert(id, Box::new(listener));
19859
19860        let editor_actions = self.editor_actions.clone();
19861        Subscription::new(move || {
19862            editor_actions.borrow_mut().remove(&id);
19863        })
19864    }
19865
19866    pub fn register_action<A: Action>(
19867        &mut self,
19868        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19869    ) -> Subscription {
19870        let id = self.next_editor_action_id.post_inc();
19871        let listener = Arc::new(listener);
19872        self.editor_actions.borrow_mut().insert(
19873            id,
19874            Box::new(move |_, window, _| {
19875                let listener = listener.clone();
19876                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19877                    let action = action.downcast_ref().unwrap();
19878                    if phase == DispatchPhase::Bubble {
19879                        listener(action, window, cx)
19880                    }
19881                })
19882            }),
19883        );
19884
19885        let editor_actions = self.editor_actions.clone();
19886        Subscription::new(move || {
19887            editor_actions.borrow_mut().remove(&id);
19888        })
19889    }
19890
19891    pub fn file_header_size(&self) -> u32 {
19892        FILE_HEADER_HEIGHT
19893    }
19894
19895    pub fn restore(
19896        &mut self,
19897        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19898        window: &mut Window,
19899        cx: &mut Context<Self>,
19900    ) {
19901        let workspace = self.workspace();
19902        let project = self.project.as_ref();
19903        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19904            let mut tasks = Vec::new();
19905            for (buffer_id, changes) in revert_changes {
19906                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19907                    buffer.update(cx, |buffer, cx| {
19908                        buffer.edit(
19909                            changes
19910                                .into_iter()
19911                                .map(|(range, text)| (range, text.to_string())),
19912                            None,
19913                            cx,
19914                        );
19915                    });
19916
19917                    if let Some(project) =
19918                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19919                    {
19920                        project.update(cx, |project, cx| {
19921                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19922                        })
19923                    }
19924                }
19925            }
19926            tasks
19927        });
19928        cx.spawn_in(window, async move |_, cx| {
19929            for (buffer, task) in save_tasks {
19930                let result = task.await;
19931                if result.is_err() {
19932                    let Some(path) = buffer
19933                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19934                        .ok()
19935                    else {
19936                        continue;
19937                    };
19938                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19939                        let Some(task) = cx
19940                            .update_window_entity(&workspace, |workspace, window, cx| {
19941                                workspace
19942                                    .open_path_preview(path, None, false, false, false, window, cx)
19943                            })
19944                            .ok()
19945                        else {
19946                            continue;
19947                        };
19948                        task.await.log_err();
19949                    }
19950                }
19951            }
19952        })
19953        .detach();
19954        self.change_selections(None, window, cx, |selections| selections.refresh());
19955    }
19956
19957    pub fn to_pixel_point(
19958        &self,
19959        source: multi_buffer::Anchor,
19960        editor_snapshot: &EditorSnapshot,
19961        window: &mut Window,
19962    ) -> Option<gpui::Point<Pixels>> {
19963        let source_point = source.to_display_point(editor_snapshot);
19964        self.display_to_pixel_point(source_point, editor_snapshot, window)
19965    }
19966
19967    pub fn display_to_pixel_point(
19968        &self,
19969        source: DisplayPoint,
19970        editor_snapshot: &EditorSnapshot,
19971        window: &mut Window,
19972    ) -> Option<gpui::Point<Pixels>> {
19973        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19974        let text_layout_details = self.text_layout_details(window);
19975        let scroll_top = text_layout_details
19976            .scroll_anchor
19977            .scroll_position(editor_snapshot)
19978            .y;
19979
19980        if source.row().as_f32() < scroll_top.floor() {
19981            return None;
19982        }
19983        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19984        let source_y = line_height * (source.row().as_f32() - scroll_top);
19985        Some(gpui::Point::new(source_x, source_y))
19986    }
19987
19988    pub fn has_visible_completions_menu(&self) -> bool {
19989        !self.edit_prediction_preview_is_active()
19990            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19991                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19992            })
19993    }
19994
19995    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19996        if self.mode.is_minimap() {
19997            return;
19998        }
19999        self.addons
20000            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20001    }
20002
20003    pub fn unregister_addon<T: Addon>(&mut self) {
20004        self.addons.remove(&std::any::TypeId::of::<T>());
20005    }
20006
20007    pub fn addon<T: Addon>(&self) -> Option<&T> {
20008        let type_id = std::any::TypeId::of::<T>();
20009        self.addons
20010            .get(&type_id)
20011            .and_then(|item| item.to_any().downcast_ref::<T>())
20012    }
20013
20014    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20015        let type_id = std::any::TypeId::of::<T>();
20016        self.addons
20017            .get_mut(&type_id)
20018            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20019    }
20020
20021    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20022        let text_layout_details = self.text_layout_details(window);
20023        let style = &text_layout_details.editor_style;
20024        let font_id = window.text_system().resolve_font(&style.text.font());
20025        let font_size = style.text.font_size.to_pixels(window.rem_size());
20026        let line_height = style.text.line_height_in_pixels(window.rem_size());
20027        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20028
20029        gpui::Size::new(em_width, line_height)
20030    }
20031
20032    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20033        self.load_diff_task.clone()
20034    }
20035
20036    fn read_metadata_from_db(
20037        &mut self,
20038        item_id: u64,
20039        workspace_id: WorkspaceId,
20040        window: &mut Window,
20041        cx: &mut Context<Editor>,
20042    ) {
20043        if self.is_singleton(cx)
20044            && !self.mode.is_minimap()
20045            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20046        {
20047            let buffer_snapshot = OnceCell::new();
20048
20049            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20050                if !folds.is_empty() {
20051                    let snapshot =
20052                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20053                    self.fold_ranges(
20054                        folds
20055                            .into_iter()
20056                            .map(|(start, end)| {
20057                                snapshot.clip_offset(start, Bias::Left)
20058                                    ..snapshot.clip_offset(end, Bias::Right)
20059                            })
20060                            .collect(),
20061                        false,
20062                        window,
20063                        cx,
20064                    );
20065                }
20066            }
20067
20068            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20069                if !selections.is_empty() {
20070                    let snapshot =
20071                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20072                    // skip adding the initial selection to selection history
20073                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20074                    self.change_selections(None, window, cx, |s| {
20075                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20076                            snapshot.clip_offset(start, Bias::Left)
20077                                ..snapshot.clip_offset(end, Bias::Right)
20078                        }));
20079                    });
20080                    self.selection_history.mode = SelectionHistoryMode::Normal;
20081                }
20082            };
20083        }
20084
20085        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20086    }
20087}
20088
20089fn vim_enabled(cx: &App) -> bool {
20090    cx.global::<SettingsStore>()
20091        .raw_user_settings()
20092        .get("vim_mode")
20093        == Some(&serde_json::Value::Bool(true))
20094}
20095
20096fn process_completion_for_edit(
20097    completion: &Completion,
20098    intent: CompletionIntent,
20099    buffer: &Entity<Buffer>,
20100    cursor_position: &text::Anchor,
20101    cx: &mut Context<Editor>,
20102) -> CompletionEdit {
20103    let buffer = buffer.read(cx);
20104    let buffer_snapshot = buffer.snapshot();
20105    let (snippet, new_text) = if completion.is_snippet() {
20106        // Workaround for typescript language server issues so that methods don't expand within
20107        // strings and functions with type expressions. The previous point is used because the query
20108        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20109        let mut snippet_source = completion.new_text.clone();
20110        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20111        previous_point.column = previous_point.column.saturating_sub(1);
20112        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20113            if scope.prefers_label_for_snippet_in_completion() {
20114                if let Some(label) = completion.label() {
20115                    if matches!(
20116                        completion.kind(),
20117                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20118                    ) {
20119                        snippet_source = label;
20120                    }
20121                }
20122            }
20123        }
20124        match Snippet::parse(&snippet_source).log_err() {
20125            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20126            None => (None, completion.new_text.clone()),
20127        }
20128    } else {
20129        (None, completion.new_text.clone())
20130    };
20131
20132    let mut range_to_replace = {
20133        let replace_range = &completion.replace_range;
20134        if let CompletionSource::Lsp {
20135            insert_range: Some(insert_range),
20136            ..
20137        } = &completion.source
20138        {
20139            debug_assert_eq!(
20140                insert_range.start, replace_range.start,
20141                "insert_range and replace_range should start at the same position"
20142            );
20143            debug_assert!(
20144                insert_range
20145                    .start
20146                    .cmp(&cursor_position, &buffer_snapshot)
20147                    .is_le(),
20148                "insert_range should start before or at cursor position"
20149            );
20150            debug_assert!(
20151                replace_range
20152                    .start
20153                    .cmp(&cursor_position, &buffer_snapshot)
20154                    .is_le(),
20155                "replace_range should start before or at cursor position"
20156            );
20157            debug_assert!(
20158                insert_range
20159                    .end
20160                    .cmp(&cursor_position, &buffer_snapshot)
20161                    .is_le(),
20162                "insert_range should end before or at cursor position"
20163            );
20164
20165            let should_replace = match intent {
20166                CompletionIntent::CompleteWithInsert => false,
20167                CompletionIntent::CompleteWithReplace => true,
20168                CompletionIntent::Complete | CompletionIntent::Compose => {
20169                    let insert_mode =
20170                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20171                            .completions
20172                            .lsp_insert_mode;
20173                    match insert_mode {
20174                        LspInsertMode::Insert => false,
20175                        LspInsertMode::Replace => true,
20176                        LspInsertMode::ReplaceSubsequence => {
20177                            let mut text_to_replace = buffer.chars_for_range(
20178                                buffer.anchor_before(replace_range.start)
20179                                    ..buffer.anchor_after(replace_range.end),
20180                            );
20181                            let mut current_needle = text_to_replace.next();
20182                            for haystack_ch in completion.label.text.chars() {
20183                                if let Some(needle_ch) = current_needle {
20184                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20185                                        current_needle = text_to_replace.next();
20186                                    }
20187                                }
20188                            }
20189                            current_needle.is_none()
20190                        }
20191                        LspInsertMode::ReplaceSuffix => {
20192                            if replace_range
20193                                .end
20194                                .cmp(&cursor_position, &buffer_snapshot)
20195                                .is_gt()
20196                            {
20197                                let range_after_cursor = *cursor_position..replace_range.end;
20198                                let text_after_cursor = buffer
20199                                    .text_for_range(
20200                                        buffer.anchor_before(range_after_cursor.start)
20201                                            ..buffer.anchor_after(range_after_cursor.end),
20202                                    )
20203                                    .collect::<String>()
20204                                    .to_ascii_lowercase();
20205                                completion
20206                                    .label
20207                                    .text
20208                                    .to_ascii_lowercase()
20209                                    .ends_with(&text_after_cursor)
20210                            } else {
20211                                true
20212                            }
20213                        }
20214                    }
20215                }
20216            };
20217
20218            if should_replace {
20219                replace_range.clone()
20220            } else {
20221                insert_range.clone()
20222            }
20223        } else {
20224            replace_range.clone()
20225        }
20226    };
20227
20228    if range_to_replace
20229        .end
20230        .cmp(&cursor_position, &buffer_snapshot)
20231        .is_lt()
20232    {
20233        range_to_replace.end = *cursor_position;
20234    }
20235
20236    CompletionEdit {
20237        new_text,
20238        replace_range: range_to_replace.to_offset(&buffer),
20239        snippet,
20240    }
20241}
20242
20243struct CompletionEdit {
20244    new_text: String,
20245    replace_range: Range<usize>,
20246    snippet: Option<Snippet>,
20247}
20248
20249fn insert_extra_newline_brackets(
20250    buffer: &MultiBufferSnapshot,
20251    range: Range<usize>,
20252    language: &language::LanguageScope,
20253) -> bool {
20254    let leading_whitespace_len = buffer
20255        .reversed_chars_at(range.start)
20256        .take_while(|c| c.is_whitespace() && *c != '\n')
20257        .map(|c| c.len_utf8())
20258        .sum::<usize>();
20259    let trailing_whitespace_len = buffer
20260        .chars_at(range.end)
20261        .take_while(|c| c.is_whitespace() && *c != '\n')
20262        .map(|c| c.len_utf8())
20263        .sum::<usize>();
20264    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20265
20266    language.brackets().any(|(pair, enabled)| {
20267        let pair_start = pair.start.trim_end();
20268        let pair_end = pair.end.trim_start();
20269
20270        enabled
20271            && pair.newline
20272            && buffer.contains_str_at(range.end, pair_end)
20273            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20274    })
20275}
20276
20277fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20278    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20279        [(buffer, range, _)] => (*buffer, range.clone()),
20280        _ => return false,
20281    };
20282    let pair = {
20283        let mut result: Option<BracketMatch> = None;
20284
20285        for pair in buffer
20286            .all_bracket_ranges(range.clone())
20287            .filter(move |pair| {
20288                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20289            })
20290        {
20291            let len = pair.close_range.end - pair.open_range.start;
20292
20293            if let Some(existing) = &result {
20294                let existing_len = existing.close_range.end - existing.open_range.start;
20295                if len > existing_len {
20296                    continue;
20297                }
20298            }
20299
20300            result = Some(pair);
20301        }
20302
20303        result
20304    };
20305    let Some(pair) = pair else {
20306        return false;
20307    };
20308    pair.newline_only
20309        && buffer
20310            .chars_for_range(pair.open_range.end..range.start)
20311            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20312            .all(|c| c.is_whitespace() && c != '\n')
20313}
20314
20315fn update_uncommitted_diff_for_buffer(
20316    editor: Entity<Editor>,
20317    project: &Entity<Project>,
20318    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20319    buffer: Entity<MultiBuffer>,
20320    cx: &mut App,
20321) -> Task<()> {
20322    let mut tasks = Vec::new();
20323    project.update(cx, |project, cx| {
20324        for buffer in buffers {
20325            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20326                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20327            }
20328        }
20329    });
20330    cx.spawn(async move |cx| {
20331        let diffs = future::join_all(tasks).await;
20332        if editor
20333            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20334            .unwrap_or(false)
20335        {
20336            return;
20337        }
20338
20339        buffer
20340            .update(cx, |buffer, cx| {
20341                for diff in diffs.into_iter().flatten() {
20342                    buffer.add_diff(diff, cx);
20343                }
20344            })
20345            .ok();
20346    })
20347}
20348
20349fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20350    let tab_size = tab_size.get() as usize;
20351    let mut width = offset;
20352
20353    for ch in text.chars() {
20354        width += if ch == '\t' {
20355            tab_size - (width % tab_size)
20356        } else {
20357            1
20358        };
20359    }
20360
20361    width - offset
20362}
20363
20364#[cfg(test)]
20365mod tests {
20366    use super::*;
20367
20368    #[test]
20369    fn test_string_size_with_expanded_tabs() {
20370        let nz = |val| NonZeroU32::new(val).unwrap();
20371        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20372        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20373        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20374        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20375        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20376        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20377        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20378        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20379    }
20380}
20381
20382/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20383struct WordBreakingTokenizer<'a> {
20384    input: &'a str,
20385}
20386
20387impl<'a> WordBreakingTokenizer<'a> {
20388    fn new(input: &'a str) -> Self {
20389        Self { input }
20390    }
20391}
20392
20393fn is_char_ideographic(ch: char) -> bool {
20394    use unicode_script::Script::*;
20395    use unicode_script::UnicodeScript;
20396    matches!(ch.script(), Han | Tangut | Yi)
20397}
20398
20399fn is_grapheme_ideographic(text: &str) -> bool {
20400    text.chars().any(is_char_ideographic)
20401}
20402
20403fn is_grapheme_whitespace(text: &str) -> bool {
20404    text.chars().any(|x| x.is_whitespace())
20405}
20406
20407fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20408    text.chars().next().map_or(false, |ch| {
20409        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20410    })
20411}
20412
20413#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20414enum WordBreakToken<'a> {
20415    Word { token: &'a str, grapheme_len: usize },
20416    InlineWhitespace { token: &'a str, grapheme_len: usize },
20417    Newline,
20418}
20419
20420impl<'a> Iterator for WordBreakingTokenizer<'a> {
20421    /// Yields a span, the count of graphemes in the token, and whether it was
20422    /// whitespace. Note that it also breaks at word boundaries.
20423    type Item = WordBreakToken<'a>;
20424
20425    fn next(&mut self) -> Option<Self::Item> {
20426        use unicode_segmentation::UnicodeSegmentation;
20427        if self.input.is_empty() {
20428            return None;
20429        }
20430
20431        let mut iter = self.input.graphemes(true).peekable();
20432        let mut offset = 0;
20433        let mut grapheme_len = 0;
20434        if let Some(first_grapheme) = iter.next() {
20435            let is_newline = first_grapheme == "\n";
20436            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20437            offset += first_grapheme.len();
20438            grapheme_len += 1;
20439            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20440                if let Some(grapheme) = iter.peek().copied() {
20441                    if should_stay_with_preceding_ideograph(grapheme) {
20442                        offset += grapheme.len();
20443                        grapheme_len += 1;
20444                    }
20445                }
20446            } else {
20447                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20448                let mut next_word_bound = words.peek().copied();
20449                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20450                    next_word_bound = words.next();
20451                }
20452                while let Some(grapheme) = iter.peek().copied() {
20453                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20454                        break;
20455                    };
20456                    if is_grapheme_whitespace(grapheme) != is_whitespace
20457                        || (grapheme == "\n") != is_newline
20458                    {
20459                        break;
20460                    };
20461                    offset += grapheme.len();
20462                    grapheme_len += 1;
20463                    iter.next();
20464                }
20465            }
20466            let token = &self.input[..offset];
20467            self.input = &self.input[offset..];
20468            if token == "\n" {
20469                Some(WordBreakToken::Newline)
20470            } else if is_whitespace {
20471                Some(WordBreakToken::InlineWhitespace {
20472                    token,
20473                    grapheme_len,
20474                })
20475            } else {
20476                Some(WordBreakToken::Word {
20477                    token,
20478                    grapheme_len,
20479                })
20480            }
20481        } else {
20482            None
20483        }
20484    }
20485}
20486
20487#[test]
20488fn test_word_breaking_tokenizer() {
20489    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20490        ("", &[]),
20491        ("  ", &[whitespace("  ", 2)]),
20492        ("Ʒ", &[word("Ʒ", 1)]),
20493        ("Ǽ", &[word("Ǽ", 1)]),
20494        ("", &[word("", 1)]),
20495        ("⋑⋑", &[word("⋑⋑", 2)]),
20496        (
20497            "原理,进而",
20498            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20499        ),
20500        (
20501            "hello world",
20502            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20503        ),
20504        (
20505            "hello, world",
20506            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20507        ),
20508        (
20509            "  hello world",
20510            &[
20511                whitespace("  ", 2),
20512                word("hello", 5),
20513                whitespace(" ", 1),
20514                word("world", 5),
20515            ],
20516        ),
20517        (
20518            "这是什么 \n 钢笔",
20519            &[
20520                word("", 1),
20521                word("", 1),
20522                word("", 1),
20523                word("", 1),
20524                whitespace(" ", 1),
20525                newline(),
20526                whitespace(" ", 1),
20527                word("", 1),
20528                word("", 1),
20529            ],
20530        ),
20531        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20532    ];
20533
20534    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20535        WordBreakToken::Word {
20536            token,
20537            grapheme_len,
20538        }
20539    }
20540
20541    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20542        WordBreakToken::InlineWhitespace {
20543            token,
20544            grapheme_len,
20545        }
20546    }
20547
20548    fn newline() -> WordBreakToken<'static> {
20549        WordBreakToken::Newline
20550    }
20551
20552    for (input, result) in tests {
20553        assert_eq!(
20554            WordBreakingTokenizer::new(input)
20555                .collect::<Vec<_>>()
20556                .as_slice(),
20557            *result,
20558        );
20559    }
20560}
20561
20562fn wrap_with_prefix(
20563    line_prefix: String,
20564    unwrapped_text: String,
20565    wrap_column: usize,
20566    tab_size: NonZeroU32,
20567    preserve_existing_whitespace: bool,
20568) -> String {
20569    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20570    let mut wrapped_text = String::new();
20571    let mut current_line = line_prefix.clone();
20572
20573    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20574    let mut current_line_len = line_prefix_len;
20575    let mut in_whitespace = false;
20576    for token in tokenizer {
20577        let have_preceding_whitespace = in_whitespace;
20578        match token {
20579            WordBreakToken::Word {
20580                token,
20581                grapheme_len,
20582            } => {
20583                in_whitespace = false;
20584                if current_line_len + grapheme_len > wrap_column
20585                    && current_line_len != line_prefix_len
20586                {
20587                    wrapped_text.push_str(current_line.trim_end());
20588                    wrapped_text.push('\n');
20589                    current_line.truncate(line_prefix.len());
20590                    current_line_len = line_prefix_len;
20591                }
20592                current_line.push_str(token);
20593                current_line_len += grapheme_len;
20594            }
20595            WordBreakToken::InlineWhitespace {
20596                mut token,
20597                mut grapheme_len,
20598            } => {
20599                in_whitespace = true;
20600                if have_preceding_whitespace && !preserve_existing_whitespace {
20601                    continue;
20602                }
20603                if !preserve_existing_whitespace {
20604                    token = " ";
20605                    grapheme_len = 1;
20606                }
20607                if current_line_len + grapheme_len > wrap_column {
20608                    wrapped_text.push_str(current_line.trim_end());
20609                    wrapped_text.push('\n');
20610                    current_line.truncate(line_prefix.len());
20611                    current_line_len = line_prefix_len;
20612                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20613                    current_line.push_str(token);
20614                    current_line_len += grapheme_len;
20615                }
20616            }
20617            WordBreakToken::Newline => {
20618                in_whitespace = true;
20619                if preserve_existing_whitespace {
20620                    wrapped_text.push_str(current_line.trim_end());
20621                    wrapped_text.push('\n');
20622                    current_line.truncate(line_prefix.len());
20623                    current_line_len = line_prefix_len;
20624                } else if have_preceding_whitespace {
20625                    continue;
20626                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20627                {
20628                    wrapped_text.push_str(current_line.trim_end());
20629                    wrapped_text.push('\n');
20630                    current_line.truncate(line_prefix.len());
20631                    current_line_len = line_prefix_len;
20632                } else if current_line_len != line_prefix_len {
20633                    current_line.push(' ');
20634                    current_line_len += 1;
20635                }
20636            }
20637        }
20638    }
20639
20640    if !current_line.is_empty() {
20641        wrapped_text.push_str(&current_line);
20642    }
20643    wrapped_text
20644}
20645
20646#[test]
20647fn test_wrap_with_prefix() {
20648    assert_eq!(
20649        wrap_with_prefix(
20650            "# ".to_string(),
20651            "abcdefg".to_string(),
20652            4,
20653            NonZeroU32::new(4).unwrap(),
20654            false,
20655        ),
20656        "# abcdefg"
20657    );
20658    assert_eq!(
20659        wrap_with_prefix(
20660            "".to_string(),
20661            "\thello world".to_string(),
20662            8,
20663            NonZeroU32::new(4).unwrap(),
20664            false,
20665        ),
20666        "hello\nworld"
20667    );
20668    assert_eq!(
20669        wrap_with_prefix(
20670            "// ".to_string(),
20671            "xx \nyy zz aa bb cc".to_string(),
20672            12,
20673            NonZeroU32::new(4).unwrap(),
20674            false,
20675        ),
20676        "// xx yy zz\n// aa bb cc"
20677    );
20678    assert_eq!(
20679        wrap_with_prefix(
20680            String::new(),
20681            "这是什么 \n 钢笔".to_string(),
20682            3,
20683            NonZeroU32::new(4).unwrap(),
20684            false,
20685        ),
20686        "这是什\n么 钢\n"
20687    );
20688}
20689
20690pub trait CollaborationHub {
20691    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20692    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20693    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20694}
20695
20696impl CollaborationHub for Entity<Project> {
20697    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20698        self.read(cx).collaborators()
20699    }
20700
20701    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20702        self.read(cx).user_store().read(cx).participant_indices()
20703    }
20704
20705    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20706        let this = self.read(cx);
20707        let user_ids = this.collaborators().values().map(|c| c.user_id);
20708        this.user_store().read(cx).participant_names(user_ids, cx)
20709    }
20710}
20711
20712pub trait SemanticsProvider {
20713    fn hover(
20714        &self,
20715        buffer: &Entity<Buffer>,
20716        position: text::Anchor,
20717        cx: &mut App,
20718    ) -> Option<Task<Vec<project::Hover>>>;
20719
20720    fn inline_values(
20721        &self,
20722        buffer_handle: Entity<Buffer>,
20723        range: Range<text::Anchor>,
20724        cx: &mut App,
20725    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20726
20727    fn inlay_hints(
20728        &self,
20729        buffer_handle: Entity<Buffer>,
20730        range: Range<text::Anchor>,
20731        cx: &mut App,
20732    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20733
20734    fn resolve_inlay_hint(
20735        &self,
20736        hint: InlayHint,
20737        buffer_handle: Entity<Buffer>,
20738        server_id: LanguageServerId,
20739        cx: &mut App,
20740    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20741
20742    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20743
20744    fn document_highlights(
20745        &self,
20746        buffer: &Entity<Buffer>,
20747        position: text::Anchor,
20748        cx: &mut App,
20749    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20750
20751    fn definitions(
20752        &self,
20753        buffer: &Entity<Buffer>,
20754        position: text::Anchor,
20755        kind: GotoDefinitionKind,
20756        cx: &mut App,
20757    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20758
20759    fn range_for_rename(
20760        &self,
20761        buffer: &Entity<Buffer>,
20762        position: text::Anchor,
20763        cx: &mut App,
20764    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20765
20766    fn perform_rename(
20767        &self,
20768        buffer: &Entity<Buffer>,
20769        position: text::Anchor,
20770        new_name: String,
20771        cx: &mut App,
20772    ) -> Option<Task<Result<ProjectTransaction>>>;
20773
20774    fn pull_diagnostics_for_buffer(
20775        &self,
20776        buffer: Entity<Buffer>,
20777        cx: &mut App,
20778    ) -> Task<anyhow::Result<()>>;
20779}
20780
20781pub trait CompletionProvider {
20782    fn completions(
20783        &self,
20784        excerpt_id: ExcerptId,
20785        buffer: &Entity<Buffer>,
20786        buffer_position: text::Anchor,
20787        trigger: CompletionContext,
20788        window: &mut Window,
20789        cx: &mut Context<Editor>,
20790    ) -> Task<Result<Vec<CompletionResponse>>>;
20791
20792    fn resolve_completions(
20793        &self,
20794        _buffer: Entity<Buffer>,
20795        _completion_indices: Vec<usize>,
20796        _completions: Rc<RefCell<Box<[Completion]>>>,
20797        _cx: &mut Context<Editor>,
20798    ) -> Task<Result<bool>> {
20799        Task::ready(Ok(false))
20800    }
20801
20802    fn apply_additional_edits_for_completion(
20803        &self,
20804        _buffer: Entity<Buffer>,
20805        _completions: Rc<RefCell<Box<[Completion]>>>,
20806        _completion_index: usize,
20807        _push_to_history: bool,
20808        _cx: &mut Context<Editor>,
20809    ) -> Task<Result<Option<language::Transaction>>> {
20810        Task::ready(Ok(None))
20811    }
20812
20813    fn is_completion_trigger(
20814        &self,
20815        buffer: &Entity<Buffer>,
20816        position: language::Anchor,
20817        text: &str,
20818        trigger_in_words: bool,
20819        menu_is_open: bool,
20820        cx: &mut Context<Editor>,
20821    ) -> bool;
20822
20823    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20824
20825    fn sort_completions(&self) -> bool {
20826        true
20827    }
20828
20829    fn filter_completions(&self) -> bool {
20830        true
20831    }
20832}
20833
20834pub trait CodeActionProvider {
20835    fn id(&self) -> Arc<str>;
20836
20837    fn code_actions(
20838        &self,
20839        buffer: &Entity<Buffer>,
20840        range: Range<text::Anchor>,
20841        window: &mut Window,
20842        cx: &mut App,
20843    ) -> Task<Result<Vec<CodeAction>>>;
20844
20845    fn apply_code_action(
20846        &self,
20847        buffer_handle: Entity<Buffer>,
20848        action: CodeAction,
20849        excerpt_id: ExcerptId,
20850        push_to_history: bool,
20851        window: &mut Window,
20852        cx: &mut App,
20853    ) -> Task<Result<ProjectTransaction>>;
20854}
20855
20856impl CodeActionProvider for Entity<Project> {
20857    fn id(&self) -> Arc<str> {
20858        "project".into()
20859    }
20860
20861    fn code_actions(
20862        &self,
20863        buffer: &Entity<Buffer>,
20864        range: Range<text::Anchor>,
20865        _window: &mut Window,
20866        cx: &mut App,
20867    ) -> Task<Result<Vec<CodeAction>>> {
20868        self.update(cx, |project, cx| {
20869            let code_lens = project.code_lens(buffer, range.clone(), cx);
20870            let code_actions = project.code_actions(buffer, range, None, cx);
20871            cx.background_spawn(async move {
20872                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20873                Ok(code_lens
20874                    .context("code lens fetch")?
20875                    .into_iter()
20876                    .chain(code_actions.context("code action fetch")?)
20877                    .collect())
20878            })
20879        })
20880    }
20881
20882    fn apply_code_action(
20883        &self,
20884        buffer_handle: Entity<Buffer>,
20885        action: CodeAction,
20886        _excerpt_id: ExcerptId,
20887        push_to_history: bool,
20888        _window: &mut Window,
20889        cx: &mut App,
20890    ) -> Task<Result<ProjectTransaction>> {
20891        self.update(cx, |project, cx| {
20892            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20893        })
20894    }
20895}
20896
20897fn snippet_completions(
20898    project: &Project,
20899    buffer: &Entity<Buffer>,
20900    buffer_position: text::Anchor,
20901    cx: &mut App,
20902) -> Task<Result<CompletionResponse>> {
20903    let languages = buffer.read(cx).languages_at(buffer_position);
20904    let snippet_store = project.snippets().read(cx);
20905
20906    let scopes: Vec<_> = languages
20907        .iter()
20908        .filter_map(|language| {
20909            let language_name = language.lsp_id();
20910            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20911
20912            if snippets.is_empty() {
20913                None
20914            } else {
20915                Some((language.default_scope(), snippets))
20916            }
20917        })
20918        .collect();
20919
20920    if scopes.is_empty() {
20921        return Task::ready(Ok(CompletionResponse {
20922            completions: vec![],
20923            is_incomplete: false,
20924        }));
20925    }
20926
20927    let snapshot = buffer.read(cx).text_snapshot();
20928    let chars: String = snapshot
20929        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20930        .collect();
20931    let executor = cx.background_executor().clone();
20932
20933    cx.background_spawn(async move {
20934        let mut is_incomplete = false;
20935        let mut completions: Vec<Completion> = Vec::new();
20936        for (scope, snippets) in scopes.into_iter() {
20937            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20938            let mut last_word = chars
20939                .chars()
20940                .take_while(|c| classifier.is_word(*c))
20941                .collect::<String>();
20942            last_word = last_word.chars().rev().collect();
20943
20944            if last_word.is_empty() {
20945                return Ok(CompletionResponse {
20946                    completions: vec![],
20947                    is_incomplete: true,
20948                });
20949            }
20950
20951            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20952            let to_lsp = |point: &text::Anchor| {
20953                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20954                point_to_lsp(end)
20955            };
20956            let lsp_end = to_lsp(&buffer_position);
20957
20958            let candidates = snippets
20959                .iter()
20960                .enumerate()
20961                .flat_map(|(ix, snippet)| {
20962                    snippet
20963                        .prefix
20964                        .iter()
20965                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20966                })
20967                .collect::<Vec<StringMatchCandidate>>();
20968
20969            const MAX_RESULTS: usize = 100;
20970            let mut matches = fuzzy::match_strings(
20971                &candidates,
20972                &last_word,
20973                last_word.chars().any(|c| c.is_uppercase()),
20974                MAX_RESULTS,
20975                &Default::default(),
20976                executor.clone(),
20977            )
20978            .await;
20979
20980            if matches.len() >= MAX_RESULTS {
20981                is_incomplete = true;
20982            }
20983
20984            // Remove all candidates where the query's start does not match the start of any word in the candidate
20985            if let Some(query_start) = last_word.chars().next() {
20986                matches.retain(|string_match| {
20987                    split_words(&string_match.string).any(|word| {
20988                        // Check that the first codepoint of the word as lowercase matches the first
20989                        // codepoint of the query as lowercase
20990                        word.chars()
20991                            .flat_map(|codepoint| codepoint.to_lowercase())
20992                            .zip(query_start.to_lowercase())
20993                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20994                    })
20995                });
20996            }
20997
20998            let matched_strings = matches
20999                .into_iter()
21000                .map(|m| m.string)
21001                .collect::<HashSet<_>>();
21002
21003            completions.extend(snippets.iter().filter_map(|snippet| {
21004                let matching_prefix = snippet
21005                    .prefix
21006                    .iter()
21007                    .find(|prefix| matched_strings.contains(*prefix))?;
21008                let start = as_offset - last_word.len();
21009                let start = snapshot.anchor_before(start);
21010                let range = start..buffer_position;
21011                let lsp_start = to_lsp(&start);
21012                let lsp_range = lsp::Range {
21013                    start: lsp_start,
21014                    end: lsp_end,
21015                };
21016                Some(Completion {
21017                    replace_range: range,
21018                    new_text: snippet.body.clone(),
21019                    source: CompletionSource::Lsp {
21020                        insert_range: None,
21021                        server_id: LanguageServerId(usize::MAX),
21022                        resolved: true,
21023                        lsp_completion: Box::new(lsp::CompletionItem {
21024                            label: snippet.prefix.first().unwrap().clone(),
21025                            kind: Some(CompletionItemKind::SNIPPET),
21026                            label_details: snippet.description.as_ref().map(|description| {
21027                                lsp::CompletionItemLabelDetails {
21028                                    detail: Some(description.clone()),
21029                                    description: None,
21030                                }
21031                            }),
21032                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21033                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21034                                lsp::InsertReplaceEdit {
21035                                    new_text: snippet.body.clone(),
21036                                    insert: lsp_range,
21037                                    replace: lsp_range,
21038                                },
21039                            )),
21040                            filter_text: Some(snippet.body.clone()),
21041                            sort_text: Some(char::MAX.to_string()),
21042                            ..lsp::CompletionItem::default()
21043                        }),
21044                        lsp_defaults: None,
21045                    },
21046                    label: CodeLabel {
21047                        text: matching_prefix.clone(),
21048                        runs: Vec::new(),
21049                        filter_range: 0..matching_prefix.len(),
21050                    },
21051                    icon_path: None,
21052                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21053                        single_line: snippet.name.clone().into(),
21054                        plain_text: snippet
21055                            .description
21056                            .clone()
21057                            .map(|description| description.into()),
21058                    }),
21059                    insert_text_mode: None,
21060                    confirm: None,
21061                })
21062            }))
21063        }
21064
21065        Ok(CompletionResponse {
21066            completions,
21067            is_incomplete,
21068        })
21069    })
21070}
21071
21072impl CompletionProvider for Entity<Project> {
21073    fn completions(
21074        &self,
21075        _excerpt_id: ExcerptId,
21076        buffer: &Entity<Buffer>,
21077        buffer_position: text::Anchor,
21078        options: CompletionContext,
21079        _window: &mut Window,
21080        cx: &mut Context<Editor>,
21081    ) -> Task<Result<Vec<CompletionResponse>>> {
21082        self.update(cx, |project, cx| {
21083            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21084            let project_completions = project.completions(buffer, buffer_position, options, cx);
21085            cx.background_spawn(async move {
21086                let mut responses = project_completions.await?;
21087                let snippets = snippets.await?;
21088                if !snippets.completions.is_empty() {
21089                    responses.push(snippets);
21090                }
21091                Ok(responses)
21092            })
21093        })
21094    }
21095
21096    fn resolve_completions(
21097        &self,
21098        buffer: Entity<Buffer>,
21099        completion_indices: Vec<usize>,
21100        completions: Rc<RefCell<Box<[Completion]>>>,
21101        cx: &mut Context<Editor>,
21102    ) -> Task<Result<bool>> {
21103        self.update(cx, |project, cx| {
21104            project.lsp_store().update(cx, |lsp_store, cx| {
21105                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21106            })
21107        })
21108    }
21109
21110    fn apply_additional_edits_for_completion(
21111        &self,
21112        buffer: Entity<Buffer>,
21113        completions: Rc<RefCell<Box<[Completion]>>>,
21114        completion_index: usize,
21115        push_to_history: bool,
21116        cx: &mut Context<Editor>,
21117    ) -> Task<Result<Option<language::Transaction>>> {
21118        self.update(cx, |project, cx| {
21119            project.lsp_store().update(cx, |lsp_store, cx| {
21120                lsp_store.apply_additional_edits_for_completion(
21121                    buffer,
21122                    completions,
21123                    completion_index,
21124                    push_to_history,
21125                    cx,
21126                )
21127            })
21128        })
21129    }
21130
21131    fn is_completion_trigger(
21132        &self,
21133        buffer: &Entity<Buffer>,
21134        position: language::Anchor,
21135        text: &str,
21136        trigger_in_words: bool,
21137        menu_is_open: bool,
21138        cx: &mut Context<Editor>,
21139    ) -> bool {
21140        let mut chars = text.chars();
21141        let char = if let Some(char) = chars.next() {
21142            char
21143        } else {
21144            return false;
21145        };
21146        if chars.next().is_some() {
21147            return false;
21148        }
21149
21150        let buffer = buffer.read(cx);
21151        let snapshot = buffer.snapshot();
21152        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21153            return false;
21154        }
21155        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21156        if trigger_in_words && classifier.is_word(char) {
21157            return true;
21158        }
21159
21160        buffer.completion_triggers().contains(text)
21161    }
21162}
21163
21164impl SemanticsProvider for Entity<Project> {
21165    fn hover(
21166        &self,
21167        buffer: &Entity<Buffer>,
21168        position: text::Anchor,
21169        cx: &mut App,
21170    ) -> Option<Task<Vec<project::Hover>>> {
21171        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21172    }
21173
21174    fn document_highlights(
21175        &self,
21176        buffer: &Entity<Buffer>,
21177        position: text::Anchor,
21178        cx: &mut App,
21179    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21180        Some(self.update(cx, |project, cx| {
21181            project.document_highlights(buffer, position, cx)
21182        }))
21183    }
21184
21185    fn definitions(
21186        &self,
21187        buffer: &Entity<Buffer>,
21188        position: text::Anchor,
21189        kind: GotoDefinitionKind,
21190        cx: &mut App,
21191    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21192        Some(self.update(cx, |project, cx| match kind {
21193            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21194            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21195            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21196            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21197        }))
21198    }
21199
21200    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21201        // TODO: make this work for remote projects
21202        self.update(cx, |project, cx| {
21203            if project
21204                .active_debug_session(cx)
21205                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21206            {
21207                return true;
21208            }
21209
21210            buffer.update(cx, |buffer, cx| {
21211                project.any_language_server_supports_inlay_hints(buffer, cx)
21212            })
21213        })
21214    }
21215
21216    fn inline_values(
21217        &self,
21218        buffer_handle: Entity<Buffer>,
21219
21220        range: Range<text::Anchor>,
21221        cx: &mut App,
21222    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21223        self.update(cx, |project, cx| {
21224            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21225
21226            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21227        })
21228    }
21229
21230    fn inlay_hints(
21231        &self,
21232        buffer_handle: Entity<Buffer>,
21233        range: Range<text::Anchor>,
21234        cx: &mut App,
21235    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21236        Some(self.update(cx, |project, cx| {
21237            project.inlay_hints(buffer_handle, range, cx)
21238        }))
21239    }
21240
21241    fn resolve_inlay_hint(
21242        &self,
21243        hint: InlayHint,
21244        buffer_handle: Entity<Buffer>,
21245        server_id: LanguageServerId,
21246        cx: &mut App,
21247    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21248        Some(self.update(cx, |project, cx| {
21249            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21250        }))
21251    }
21252
21253    fn range_for_rename(
21254        &self,
21255        buffer: &Entity<Buffer>,
21256        position: text::Anchor,
21257        cx: &mut App,
21258    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21259        Some(self.update(cx, |project, cx| {
21260            let buffer = buffer.clone();
21261            let task = project.prepare_rename(buffer.clone(), position, cx);
21262            cx.spawn(async move |_, cx| {
21263                Ok(match task.await? {
21264                    PrepareRenameResponse::Success(range) => Some(range),
21265                    PrepareRenameResponse::InvalidPosition => None,
21266                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21267                        // Fallback on using TreeSitter info to determine identifier range
21268                        buffer.read_with(cx, |buffer, _| {
21269                            let snapshot = buffer.snapshot();
21270                            let (range, kind) = snapshot.surrounding_word(position);
21271                            if kind != Some(CharKind::Word) {
21272                                return None;
21273                            }
21274                            Some(
21275                                snapshot.anchor_before(range.start)
21276                                    ..snapshot.anchor_after(range.end),
21277                            )
21278                        })?
21279                    }
21280                })
21281            })
21282        }))
21283    }
21284
21285    fn perform_rename(
21286        &self,
21287        buffer: &Entity<Buffer>,
21288        position: text::Anchor,
21289        new_name: String,
21290        cx: &mut App,
21291    ) -> Option<Task<Result<ProjectTransaction>>> {
21292        Some(self.update(cx, |project, cx| {
21293            project.perform_rename(buffer.clone(), position, new_name, cx)
21294        }))
21295    }
21296
21297    fn pull_diagnostics_for_buffer(
21298        &self,
21299        buffer: Entity<Buffer>,
21300        cx: &mut App,
21301    ) -> Task<anyhow::Result<()>> {
21302        let diagnostics = self.update(cx, |project, cx| {
21303            project
21304                .lsp_store()
21305                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21306        });
21307        let project = self.clone();
21308        cx.spawn(async move |cx| {
21309            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21310            project.update(cx, |project, cx| {
21311                project.lsp_store().update(cx, |lsp_store, cx| {
21312                    for diagnostics_set in diagnostics {
21313                        let LspPullDiagnostics::Response {
21314                            server_id,
21315                            uri,
21316                            diagnostics,
21317                        } = diagnostics_set
21318                        else {
21319                            continue;
21320                        };
21321
21322                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21323                        let disk_based_sources = adapter
21324                            .as_ref()
21325                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21326                            .unwrap_or(&[]);
21327                        match diagnostics {
21328                            PulledDiagnostics::Unchanged { result_id } => {
21329                                lsp_store
21330                                    .merge_diagnostics(
21331                                        server_id,
21332                                        lsp::PublishDiagnosticsParams {
21333                                            uri: uri.clone(),
21334                                            diagnostics: Vec::new(),
21335                                            version: None,
21336                                        },
21337                                        Some(result_id),
21338                                        DiagnosticSourceKind::Pulled,
21339                                        disk_based_sources,
21340                                        |_, _| true,
21341                                        cx,
21342                                    )
21343                                    .log_err();
21344                            }
21345                            PulledDiagnostics::Changed {
21346                                diagnostics,
21347                                result_id,
21348                            } => {
21349                                lsp_store
21350                                    .merge_diagnostics(
21351                                        server_id,
21352                                        lsp::PublishDiagnosticsParams {
21353                                            uri: uri.clone(),
21354                                            diagnostics,
21355                                            version: None,
21356                                        },
21357                                        result_id,
21358                                        DiagnosticSourceKind::Pulled,
21359                                        disk_based_sources,
21360                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21361                                            DiagnosticSourceKind::Pulled => false,
21362                                            DiagnosticSourceKind::Other
21363                                            | DiagnosticSourceKind::Pushed => true,
21364                                        },
21365                                        cx,
21366                                    )
21367                                    .log_err();
21368                            }
21369                        }
21370                    }
21371                })
21372            })
21373        })
21374    }
21375}
21376
21377fn inlay_hint_settings(
21378    location: Anchor,
21379    snapshot: &MultiBufferSnapshot,
21380    cx: &mut Context<Editor>,
21381) -> InlayHintSettings {
21382    let file = snapshot.file_at(location);
21383    let language = snapshot.language_at(location).map(|l| l.name());
21384    language_settings(language, file, cx).inlay_hints
21385}
21386
21387fn consume_contiguous_rows(
21388    contiguous_row_selections: &mut Vec<Selection<Point>>,
21389    selection: &Selection<Point>,
21390    display_map: &DisplaySnapshot,
21391    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21392) -> (MultiBufferRow, MultiBufferRow) {
21393    contiguous_row_selections.push(selection.clone());
21394    let start_row = MultiBufferRow(selection.start.row);
21395    let mut end_row = ending_row(selection, display_map);
21396
21397    while let Some(next_selection) = selections.peek() {
21398        if next_selection.start.row <= end_row.0 {
21399            end_row = ending_row(next_selection, display_map);
21400            contiguous_row_selections.push(selections.next().unwrap().clone());
21401        } else {
21402            break;
21403        }
21404    }
21405    (start_row, end_row)
21406}
21407
21408fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21409    if next_selection.end.column > 0 || next_selection.is_empty() {
21410        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21411    } else {
21412        MultiBufferRow(next_selection.end.row)
21413    }
21414}
21415
21416impl EditorSnapshot {
21417    pub fn remote_selections_in_range<'a>(
21418        &'a self,
21419        range: &'a Range<Anchor>,
21420        collaboration_hub: &dyn CollaborationHub,
21421        cx: &'a App,
21422    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21423        let participant_names = collaboration_hub.user_names(cx);
21424        let participant_indices = collaboration_hub.user_participant_indices(cx);
21425        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21426        let collaborators_by_replica_id = collaborators_by_peer_id
21427            .values()
21428            .map(|collaborator| (collaborator.replica_id, collaborator))
21429            .collect::<HashMap<_, _>>();
21430        self.buffer_snapshot
21431            .selections_in_range(range, false)
21432            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21433                if replica_id == AGENT_REPLICA_ID {
21434                    Some(RemoteSelection {
21435                        replica_id,
21436                        selection,
21437                        cursor_shape,
21438                        line_mode,
21439                        collaborator_id: CollaboratorId::Agent,
21440                        user_name: Some("Agent".into()),
21441                        color: cx.theme().players().agent(),
21442                    })
21443                } else {
21444                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21445                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21446                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21447                    Some(RemoteSelection {
21448                        replica_id,
21449                        selection,
21450                        cursor_shape,
21451                        line_mode,
21452                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21453                        user_name,
21454                        color: if let Some(index) = participant_index {
21455                            cx.theme().players().color_for_participant(index.0)
21456                        } else {
21457                            cx.theme().players().absent()
21458                        },
21459                    })
21460                }
21461            })
21462    }
21463
21464    pub fn hunks_for_ranges(
21465        &self,
21466        ranges: impl IntoIterator<Item = Range<Point>>,
21467    ) -> Vec<MultiBufferDiffHunk> {
21468        let mut hunks = Vec::new();
21469        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21470            HashMap::default();
21471        for query_range in ranges {
21472            let query_rows =
21473                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21474            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21475                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21476            ) {
21477                // Include deleted hunks that are adjacent to the query range, because
21478                // otherwise they would be missed.
21479                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21480                if hunk.status().is_deleted() {
21481                    intersects_range |= hunk.row_range.start == query_rows.end;
21482                    intersects_range |= hunk.row_range.end == query_rows.start;
21483                }
21484                if intersects_range {
21485                    if !processed_buffer_rows
21486                        .entry(hunk.buffer_id)
21487                        .or_default()
21488                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21489                    {
21490                        continue;
21491                    }
21492                    hunks.push(hunk);
21493                }
21494            }
21495        }
21496
21497        hunks
21498    }
21499
21500    fn display_diff_hunks_for_rows<'a>(
21501        &'a self,
21502        display_rows: Range<DisplayRow>,
21503        folded_buffers: &'a HashSet<BufferId>,
21504    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21505        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21506        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21507
21508        self.buffer_snapshot
21509            .diff_hunks_in_range(buffer_start..buffer_end)
21510            .filter_map(|hunk| {
21511                if folded_buffers.contains(&hunk.buffer_id) {
21512                    return None;
21513                }
21514
21515                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21516                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21517
21518                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21519                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21520
21521                let display_hunk = if hunk_display_start.column() != 0 {
21522                    DisplayDiffHunk::Folded {
21523                        display_row: hunk_display_start.row(),
21524                    }
21525                } else {
21526                    let mut end_row = hunk_display_end.row();
21527                    if hunk_display_end.column() > 0 {
21528                        end_row.0 += 1;
21529                    }
21530                    let is_created_file = hunk.is_created_file();
21531                    DisplayDiffHunk::Unfolded {
21532                        status: hunk.status(),
21533                        diff_base_byte_range: hunk.diff_base_byte_range,
21534                        display_row_range: hunk_display_start.row()..end_row,
21535                        multi_buffer_range: Anchor::range_in_buffer(
21536                            hunk.excerpt_id,
21537                            hunk.buffer_id,
21538                            hunk.buffer_range,
21539                        ),
21540                        is_created_file,
21541                    }
21542                };
21543
21544                Some(display_hunk)
21545            })
21546    }
21547
21548    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21549        self.display_snapshot.buffer_snapshot.language_at(position)
21550    }
21551
21552    pub fn is_focused(&self) -> bool {
21553        self.is_focused
21554    }
21555
21556    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21557        self.placeholder_text.as_ref()
21558    }
21559
21560    pub fn scroll_position(&self) -> gpui::Point<f32> {
21561        self.scroll_anchor.scroll_position(&self.display_snapshot)
21562    }
21563
21564    fn gutter_dimensions(
21565        &self,
21566        font_id: FontId,
21567        font_size: Pixels,
21568        max_line_number_width: Pixels,
21569        cx: &App,
21570    ) -> Option<GutterDimensions> {
21571        if !self.show_gutter {
21572            return None;
21573        }
21574
21575        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
21576        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
21577
21578        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21579            matches!(
21580                ProjectSettings::get_global(cx).git.git_gutter,
21581                Some(GitGutterSetting::TrackedFiles)
21582            )
21583        });
21584        let gutter_settings = EditorSettings::get_global(cx).gutter;
21585        let show_line_numbers = self
21586            .show_line_numbers
21587            .unwrap_or(gutter_settings.line_numbers);
21588        let line_gutter_width = if show_line_numbers {
21589            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
21590            let min_width_for_number_on_gutter =
21591                em_advance * gutter_settings.min_line_number_digits as f32;
21592            max_line_number_width.max(min_width_for_number_on_gutter)
21593        } else {
21594            0.0.into()
21595        };
21596
21597        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21598        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21599
21600        let git_blame_entries_width =
21601            self.git_blame_gutter_max_author_length
21602                .map(|max_author_length| {
21603                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21604                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21605
21606                    /// The number of characters to dedicate to gaps and margins.
21607                    const SPACING_WIDTH: usize = 4;
21608
21609                    let max_char_count = max_author_length.min(renderer.max_author_length())
21610                        + ::git::SHORT_SHA_LENGTH
21611                        + MAX_RELATIVE_TIMESTAMP.len()
21612                        + SPACING_WIDTH;
21613
21614                    em_advance * max_char_count
21615                });
21616
21617        let is_singleton = self.buffer_snapshot.is_singleton();
21618
21619        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21620        left_padding += if !is_singleton {
21621            em_width * 4.0
21622        } else if show_runnables || show_breakpoints {
21623            em_width * 3.0
21624        } else if show_git_gutter && show_line_numbers {
21625            em_width * 2.0
21626        } else if show_git_gutter || show_line_numbers {
21627            em_width
21628        } else {
21629            px(0.)
21630        };
21631
21632        let shows_folds = is_singleton && gutter_settings.folds;
21633
21634        let right_padding = if shows_folds && show_line_numbers {
21635            em_width * 4.0
21636        } else if shows_folds || (!is_singleton && show_line_numbers) {
21637            em_width * 3.0
21638        } else if show_line_numbers {
21639            em_width
21640        } else {
21641            px(0.)
21642        };
21643
21644        Some(GutterDimensions {
21645            left_padding,
21646            right_padding,
21647            width: line_gutter_width + left_padding + right_padding,
21648            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21649            git_blame_entries_width,
21650        })
21651    }
21652
21653    pub fn render_crease_toggle(
21654        &self,
21655        buffer_row: MultiBufferRow,
21656        row_contains_cursor: bool,
21657        editor: Entity<Editor>,
21658        window: &mut Window,
21659        cx: &mut App,
21660    ) -> Option<AnyElement> {
21661        let folded = self.is_line_folded(buffer_row);
21662        let mut is_foldable = false;
21663
21664        if let Some(crease) = self
21665            .crease_snapshot
21666            .query_row(buffer_row, &self.buffer_snapshot)
21667        {
21668            is_foldable = true;
21669            match crease {
21670                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21671                    if let Some(render_toggle) = render_toggle {
21672                        let toggle_callback =
21673                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21674                                if folded {
21675                                    editor.update(cx, |editor, cx| {
21676                                        editor.fold_at(buffer_row, window, cx)
21677                                    });
21678                                } else {
21679                                    editor.update(cx, |editor, cx| {
21680                                        editor.unfold_at(buffer_row, window, cx)
21681                                    });
21682                                }
21683                            });
21684                        return Some((render_toggle)(
21685                            buffer_row,
21686                            folded,
21687                            toggle_callback,
21688                            window,
21689                            cx,
21690                        ));
21691                    }
21692                }
21693            }
21694        }
21695
21696        is_foldable |= self.starts_indent(buffer_row);
21697
21698        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21699            Some(
21700                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21701                    .toggle_state(folded)
21702                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21703                        if folded {
21704                            this.unfold_at(buffer_row, window, cx);
21705                        } else {
21706                            this.fold_at(buffer_row, window, cx);
21707                        }
21708                    }))
21709                    .into_any_element(),
21710            )
21711        } else {
21712            None
21713        }
21714    }
21715
21716    pub fn render_crease_trailer(
21717        &self,
21718        buffer_row: MultiBufferRow,
21719        window: &mut Window,
21720        cx: &mut App,
21721    ) -> Option<AnyElement> {
21722        let folded = self.is_line_folded(buffer_row);
21723        if let Crease::Inline { render_trailer, .. } = self
21724            .crease_snapshot
21725            .query_row(buffer_row, &self.buffer_snapshot)?
21726        {
21727            let render_trailer = render_trailer.as_ref()?;
21728            Some(render_trailer(buffer_row, folded, window, cx))
21729        } else {
21730            None
21731        }
21732    }
21733}
21734
21735impl Deref for EditorSnapshot {
21736    type Target = DisplaySnapshot;
21737
21738    fn deref(&self) -> &Self::Target {
21739        &self.display_snapshot
21740    }
21741}
21742
21743#[derive(Clone, Debug, PartialEq, Eq)]
21744pub enum EditorEvent {
21745    InputIgnored {
21746        text: Arc<str>,
21747    },
21748    InputHandled {
21749        utf16_range_to_replace: Option<Range<isize>>,
21750        text: Arc<str>,
21751    },
21752    ExcerptsAdded {
21753        buffer: Entity<Buffer>,
21754        predecessor: ExcerptId,
21755        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21756    },
21757    ExcerptsRemoved {
21758        ids: Vec<ExcerptId>,
21759        removed_buffer_ids: Vec<BufferId>,
21760    },
21761    BufferFoldToggled {
21762        ids: Vec<ExcerptId>,
21763        folded: bool,
21764    },
21765    ExcerptsEdited {
21766        ids: Vec<ExcerptId>,
21767    },
21768    ExcerptsExpanded {
21769        ids: Vec<ExcerptId>,
21770    },
21771    BufferEdited,
21772    Edited {
21773        transaction_id: clock::Lamport,
21774    },
21775    Reparsed(BufferId),
21776    Focused,
21777    FocusedIn,
21778    Blurred,
21779    DirtyChanged,
21780    Saved,
21781    TitleChanged,
21782    DiffBaseChanged,
21783    SelectionsChanged {
21784        local: bool,
21785    },
21786    ScrollPositionChanged {
21787        local: bool,
21788        autoscroll: bool,
21789    },
21790    Closed,
21791    TransactionUndone {
21792        transaction_id: clock::Lamport,
21793    },
21794    TransactionBegun {
21795        transaction_id: clock::Lamport,
21796    },
21797    Reloaded,
21798    CursorShapeChanged,
21799    PushedToNavHistory {
21800        anchor: Anchor,
21801        is_deactivate: bool,
21802    },
21803}
21804
21805impl EventEmitter<EditorEvent> for Editor {}
21806
21807impl Focusable for Editor {
21808    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21809        self.focus_handle.clone()
21810    }
21811}
21812
21813impl Render for Editor {
21814    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21815        let settings = ThemeSettings::get_global(cx);
21816
21817        let mut text_style = match self.mode {
21818            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21819                color: cx.theme().colors().editor_foreground,
21820                font_family: settings.ui_font.family.clone(),
21821                font_features: settings.ui_font.features.clone(),
21822                font_fallbacks: settings.ui_font.fallbacks.clone(),
21823                font_size: rems(0.875).into(),
21824                font_weight: settings.ui_font.weight,
21825                line_height: relative(settings.buffer_line_height.value()),
21826                ..Default::default()
21827            },
21828            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21829                color: cx.theme().colors().editor_foreground,
21830                font_family: settings.buffer_font.family.clone(),
21831                font_features: settings.buffer_font.features.clone(),
21832                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21833                font_size: settings.buffer_font_size(cx).into(),
21834                font_weight: settings.buffer_font.weight,
21835                line_height: relative(settings.buffer_line_height.value()),
21836                ..Default::default()
21837            },
21838        };
21839        if let Some(text_style_refinement) = &self.text_style_refinement {
21840            text_style.refine(text_style_refinement)
21841        }
21842
21843        let background = match self.mode {
21844            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21845            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21846            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21847            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21848        };
21849
21850        EditorElement::new(
21851            &cx.entity(),
21852            EditorStyle {
21853                background,
21854                local_player: cx.theme().players().local(),
21855                text: text_style,
21856                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21857                syntax: cx.theme().syntax().clone(),
21858                status: cx.theme().status().clone(),
21859                inlay_hints_style: make_inlay_hints_style(cx),
21860                inline_completion_styles: make_suggestion_styles(cx),
21861                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21862                show_underlines: !self.mode.is_minimap(),
21863            },
21864        )
21865    }
21866}
21867
21868impl EntityInputHandler for Editor {
21869    fn text_for_range(
21870        &mut self,
21871        range_utf16: Range<usize>,
21872        adjusted_range: &mut Option<Range<usize>>,
21873        _: &mut Window,
21874        cx: &mut Context<Self>,
21875    ) -> Option<String> {
21876        let snapshot = self.buffer.read(cx).read(cx);
21877        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21878        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21879        if (start.0..end.0) != range_utf16 {
21880            adjusted_range.replace(start.0..end.0);
21881        }
21882        Some(snapshot.text_for_range(start..end).collect())
21883    }
21884
21885    fn selected_text_range(
21886        &mut self,
21887        ignore_disabled_input: bool,
21888        _: &mut Window,
21889        cx: &mut Context<Self>,
21890    ) -> Option<UTF16Selection> {
21891        // Prevent the IME menu from appearing when holding down an alphabetic key
21892        // while input is disabled.
21893        if !ignore_disabled_input && !self.input_enabled {
21894            return None;
21895        }
21896
21897        let selection = self.selections.newest::<OffsetUtf16>(cx);
21898        let range = selection.range();
21899
21900        Some(UTF16Selection {
21901            range: range.start.0..range.end.0,
21902            reversed: selection.reversed,
21903        })
21904    }
21905
21906    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21907        let snapshot = self.buffer.read(cx).read(cx);
21908        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21909        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21910    }
21911
21912    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21913        self.clear_highlights::<InputComposition>(cx);
21914        self.ime_transaction.take();
21915    }
21916
21917    fn replace_text_in_range(
21918        &mut self,
21919        range_utf16: Option<Range<usize>>,
21920        text: &str,
21921        window: &mut Window,
21922        cx: &mut Context<Self>,
21923    ) {
21924        if !self.input_enabled {
21925            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21926            return;
21927        }
21928
21929        self.transact(window, cx, |this, window, cx| {
21930            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21931                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21932                Some(this.selection_replacement_ranges(range_utf16, cx))
21933            } else {
21934                this.marked_text_ranges(cx)
21935            };
21936
21937            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21938                let newest_selection_id = this.selections.newest_anchor().id;
21939                this.selections
21940                    .all::<OffsetUtf16>(cx)
21941                    .iter()
21942                    .zip(ranges_to_replace.iter())
21943                    .find_map(|(selection, range)| {
21944                        if selection.id == newest_selection_id {
21945                            Some(
21946                                (range.start.0 as isize - selection.head().0 as isize)
21947                                    ..(range.end.0 as isize - selection.head().0 as isize),
21948                            )
21949                        } else {
21950                            None
21951                        }
21952                    })
21953            });
21954
21955            cx.emit(EditorEvent::InputHandled {
21956                utf16_range_to_replace: range_to_replace,
21957                text: text.into(),
21958            });
21959
21960            if let Some(new_selected_ranges) = new_selected_ranges {
21961                this.change_selections(None, window, cx, |selections| {
21962                    selections.select_ranges(new_selected_ranges)
21963                });
21964                this.backspace(&Default::default(), window, cx);
21965            }
21966
21967            this.handle_input(text, window, cx);
21968        });
21969
21970        if let Some(transaction) = self.ime_transaction {
21971            self.buffer.update(cx, |buffer, cx| {
21972                buffer.group_until_transaction(transaction, cx);
21973            });
21974        }
21975
21976        self.unmark_text(window, cx);
21977    }
21978
21979    fn replace_and_mark_text_in_range(
21980        &mut self,
21981        range_utf16: Option<Range<usize>>,
21982        text: &str,
21983        new_selected_range_utf16: Option<Range<usize>>,
21984        window: &mut Window,
21985        cx: &mut Context<Self>,
21986    ) {
21987        if !self.input_enabled {
21988            return;
21989        }
21990
21991        let transaction = self.transact(window, cx, |this, window, cx| {
21992            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21993                let snapshot = this.buffer.read(cx).read(cx);
21994                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21995                    for marked_range in &mut marked_ranges {
21996                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21997                        marked_range.start.0 += relative_range_utf16.start;
21998                        marked_range.start =
21999                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22000                        marked_range.end =
22001                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22002                    }
22003                }
22004                Some(marked_ranges)
22005            } else if let Some(range_utf16) = range_utf16 {
22006                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22007                Some(this.selection_replacement_ranges(range_utf16, cx))
22008            } else {
22009                None
22010            };
22011
22012            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22013                let newest_selection_id = this.selections.newest_anchor().id;
22014                this.selections
22015                    .all::<OffsetUtf16>(cx)
22016                    .iter()
22017                    .zip(ranges_to_replace.iter())
22018                    .find_map(|(selection, range)| {
22019                        if selection.id == newest_selection_id {
22020                            Some(
22021                                (range.start.0 as isize - selection.head().0 as isize)
22022                                    ..(range.end.0 as isize - selection.head().0 as isize),
22023                            )
22024                        } else {
22025                            None
22026                        }
22027                    })
22028            });
22029
22030            cx.emit(EditorEvent::InputHandled {
22031                utf16_range_to_replace: range_to_replace,
22032                text: text.into(),
22033            });
22034
22035            if let Some(ranges) = ranges_to_replace {
22036                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22037            }
22038
22039            let marked_ranges = {
22040                let snapshot = this.buffer.read(cx).read(cx);
22041                this.selections
22042                    .disjoint_anchors()
22043                    .iter()
22044                    .map(|selection| {
22045                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22046                    })
22047                    .collect::<Vec<_>>()
22048            };
22049
22050            if text.is_empty() {
22051                this.unmark_text(window, cx);
22052            } else {
22053                this.highlight_text::<InputComposition>(
22054                    marked_ranges.clone(),
22055                    HighlightStyle {
22056                        underline: Some(UnderlineStyle {
22057                            thickness: px(1.),
22058                            color: None,
22059                            wavy: false,
22060                        }),
22061                        ..Default::default()
22062                    },
22063                    cx,
22064                );
22065            }
22066
22067            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22068            let use_autoclose = this.use_autoclose;
22069            let use_auto_surround = this.use_auto_surround;
22070            this.set_use_autoclose(false);
22071            this.set_use_auto_surround(false);
22072            this.handle_input(text, window, cx);
22073            this.set_use_autoclose(use_autoclose);
22074            this.set_use_auto_surround(use_auto_surround);
22075
22076            if let Some(new_selected_range) = new_selected_range_utf16 {
22077                let snapshot = this.buffer.read(cx).read(cx);
22078                let new_selected_ranges = marked_ranges
22079                    .into_iter()
22080                    .map(|marked_range| {
22081                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22082                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22083                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22084                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22085                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22086                    })
22087                    .collect::<Vec<_>>();
22088
22089                drop(snapshot);
22090                this.change_selections(None, window, cx, |selections| {
22091                    selections.select_ranges(new_selected_ranges)
22092                });
22093            }
22094        });
22095
22096        self.ime_transaction = self.ime_transaction.or(transaction);
22097        if let Some(transaction) = self.ime_transaction {
22098            self.buffer.update(cx, |buffer, cx| {
22099                buffer.group_until_transaction(transaction, cx);
22100            });
22101        }
22102
22103        if self.text_highlights::<InputComposition>(cx).is_none() {
22104            self.ime_transaction.take();
22105        }
22106    }
22107
22108    fn bounds_for_range(
22109        &mut self,
22110        range_utf16: Range<usize>,
22111        element_bounds: gpui::Bounds<Pixels>,
22112        window: &mut Window,
22113        cx: &mut Context<Self>,
22114    ) -> Option<gpui::Bounds<Pixels>> {
22115        let text_layout_details = self.text_layout_details(window);
22116        let gpui::Size {
22117            width: em_width,
22118            height: line_height,
22119        } = self.character_size(window);
22120
22121        let snapshot = self.snapshot(window, cx);
22122        let scroll_position = snapshot.scroll_position();
22123        let scroll_left = scroll_position.x * em_width;
22124
22125        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22126        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22127            + self.gutter_dimensions.width
22128            + self.gutter_dimensions.margin;
22129        let y = line_height * (start.row().as_f32() - scroll_position.y);
22130
22131        Some(Bounds {
22132            origin: element_bounds.origin + point(x, y),
22133            size: size(em_width, line_height),
22134        })
22135    }
22136
22137    fn character_index_for_point(
22138        &mut self,
22139        point: gpui::Point<Pixels>,
22140        _window: &mut Window,
22141        _cx: &mut Context<Self>,
22142    ) -> Option<usize> {
22143        let position_map = self.last_position_map.as_ref()?;
22144        if !position_map.text_hitbox.contains(&point) {
22145            return None;
22146        }
22147        let display_point = position_map.point_for_position(point).previous_valid;
22148        let anchor = position_map
22149            .snapshot
22150            .display_point_to_anchor(display_point, Bias::Left);
22151        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22152        Some(utf16_offset.0)
22153    }
22154}
22155
22156trait SelectionExt {
22157    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22158    fn spanned_rows(
22159        &self,
22160        include_end_if_at_line_start: bool,
22161        map: &DisplaySnapshot,
22162    ) -> Range<MultiBufferRow>;
22163}
22164
22165impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22166    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22167        let start = self
22168            .start
22169            .to_point(&map.buffer_snapshot)
22170            .to_display_point(map);
22171        let end = self
22172            .end
22173            .to_point(&map.buffer_snapshot)
22174            .to_display_point(map);
22175        if self.reversed {
22176            end..start
22177        } else {
22178            start..end
22179        }
22180    }
22181
22182    fn spanned_rows(
22183        &self,
22184        include_end_if_at_line_start: bool,
22185        map: &DisplaySnapshot,
22186    ) -> Range<MultiBufferRow> {
22187        let start = self.start.to_point(&map.buffer_snapshot);
22188        let mut end = self.end.to_point(&map.buffer_snapshot);
22189        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22190            end.row -= 1;
22191        }
22192
22193        let buffer_start = map.prev_line_boundary(start).0;
22194        let buffer_end = map.next_line_boundary(end).0;
22195        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22196    }
22197}
22198
22199impl<T: InvalidationRegion> InvalidationStack<T> {
22200    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22201    where
22202        S: Clone + ToOffset,
22203    {
22204        while let Some(region) = self.last() {
22205            let all_selections_inside_invalidation_ranges =
22206                if selections.len() == region.ranges().len() {
22207                    selections
22208                        .iter()
22209                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22210                        .all(|(selection, invalidation_range)| {
22211                            let head = selection.head().to_offset(buffer);
22212                            invalidation_range.start <= head && invalidation_range.end >= head
22213                        })
22214                } else {
22215                    false
22216                };
22217
22218            if all_selections_inside_invalidation_ranges {
22219                break;
22220            } else {
22221                self.pop();
22222            }
22223        }
22224    }
22225}
22226
22227impl<T> Default for InvalidationStack<T> {
22228    fn default() -> Self {
22229        Self(Default::default())
22230    }
22231}
22232
22233impl<T> Deref for InvalidationStack<T> {
22234    type Target = Vec<T>;
22235
22236    fn deref(&self) -> &Self::Target {
22237        &self.0
22238    }
22239}
22240
22241impl<T> DerefMut for InvalidationStack<T> {
22242    fn deref_mut(&mut self) -> &mut Self::Target {
22243        &mut self.0
22244    }
22245}
22246
22247impl InvalidationRegion for SnippetState {
22248    fn ranges(&self) -> &[Range<Anchor>] {
22249        &self.ranges[self.active_index]
22250    }
22251}
22252
22253fn inline_completion_edit_text(
22254    current_snapshot: &BufferSnapshot,
22255    edits: &[(Range<Anchor>, String)],
22256    edit_preview: &EditPreview,
22257    include_deletions: bool,
22258    cx: &App,
22259) -> HighlightedText {
22260    let edits = edits
22261        .iter()
22262        .map(|(anchor, text)| {
22263            (
22264                anchor.start.text_anchor..anchor.end.text_anchor,
22265                text.clone(),
22266            )
22267        })
22268        .collect::<Vec<_>>();
22269
22270    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22271}
22272
22273pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22274    match severity {
22275        lsp::DiagnosticSeverity::ERROR => colors.error,
22276        lsp::DiagnosticSeverity::WARNING => colors.warning,
22277        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22278        lsp::DiagnosticSeverity::HINT => colors.info,
22279        _ => colors.ignored,
22280    }
22281}
22282
22283pub fn styled_runs_for_code_label<'a>(
22284    label: &'a CodeLabel,
22285    syntax_theme: &'a theme::SyntaxTheme,
22286) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22287    let fade_out = HighlightStyle {
22288        fade_out: Some(0.35),
22289        ..Default::default()
22290    };
22291
22292    let mut prev_end = label.filter_range.end;
22293    label
22294        .runs
22295        .iter()
22296        .enumerate()
22297        .flat_map(move |(ix, (range, highlight_id))| {
22298            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22299                style
22300            } else {
22301                return Default::default();
22302            };
22303            let mut muted_style = style;
22304            muted_style.highlight(fade_out);
22305
22306            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22307            if range.start >= label.filter_range.end {
22308                if range.start > prev_end {
22309                    runs.push((prev_end..range.start, fade_out));
22310                }
22311                runs.push((range.clone(), muted_style));
22312            } else if range.end <= label.filter_range.end {
22313                runs.push((range.clone(), style));
22314            } else {
22315                runs.push((range.start..label.filter_range.end, style));
22316                runs.push((label.filter_range.end..range.end, muted_style));
22317            }
22318            prev_end = cmp::max(prev_end, range.end);
22319
22320            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22321                runs.push((prev_end..label.text.len(), fade_out));
22322            }
22323
22324            runs
22325        })
22326}
22327
22328pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22329    let mut prev_index = 0;
22330    let mut prev_codepoint: Option<char> = None;
22331    text.char_indices()
22332        .chain([(text.len(), '\0')])
22333        .filter_map(move |(index, codepoint)| {
22334            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22335            let is_boundary = index == text.len()
22336                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22337                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22338            if is_boundary {
22339                let chunk = &text[prev_index..index];
22340                prev_index = index;
22341                Some(chunk)
22342            } else {
22343                None
22344            }
22345        })
22346}
22347
22348pub trait RangeToAnchorExt: Sized {
22349    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22350
22351    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22352        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22353        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22354    }
22355}
22356
22357impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22358    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22359        let start_offset = self.start.to_offset(snapshot);
22360        let end_offset = self.end.to_offset(snapshot);
22361        if start_offset == end_offset {
22362            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22363        } else {
22364            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22365        }
22366    }
22367}
22368
22369pub trait RowExt {
22370    fn as_f32(&self) -> f32;
22371
22372    fn next_row(&self) -> Self;
22373
22374    fn previous_row(&self) -> Self;
22375
22376    fn minus(&self, other: Self) -> u32;
22377}
22378
22379impl RowExt for DisplayRow {
22380    fn as_f32(&self) -> f32 {
22381        self.0 as f32
22382    }
22383
22384    fn next_row(&self) -> Self {
22385        Self(self.0 + 1)
22386    }
22387
22388    fn previous_row(&self) -> Self {
22389        Self(self.0.saturating_sub(1))
22390    }
22391
22392    fn minus(&self, other: Self) -> u32 {
22393        self.0 - other.0
22394    }
22395}
22396
22397impl RowExt for MultiBufferRow {
22398    fn as_f32(&self) -> f32 {
22399        self.0 as f32
22400    }
22401
22402    fn next_row(&self) -> Self {
22403        Self(self.0 + 1)
22404    }
22405
22406    fn previous_row(&self) -> Self {
22407        Self(self.0.saturating_sub(1))
22408    }
22409
22410    fn minus(&self, other: Self) -> u32 {
22411        self.0 - other.0
22412    }
22413}
22414
22415trait RowRangeExt {
22416    type Row;
22417
22418    fn len(&self) -> usize;
22419
22420    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22421}
22422
22423impl RowRangeExt for Range<MultiBufferRow> {
22424    type Row = MultiBufferRow;
22425
22426    fn len(&self) -> usize {
22427        (self.end.0 - self.start.0) as usize
22428    }
22429
22430    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22431        (self.start.0..self.end.0).map(MultiBufferRow)
22432    }
22433}
22434
22435impl RowRangeExt for Range<DisplayRow> {
22436    type Row = DisplayRow;
22437
22438    fn len(&self) -> usize {
22439        (self.end.0 - self.start.0) as usize
22440    }
22441
22442    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22443        (self.start.0..self.end.0).map(DisplayRow)
22444    }
22445}
22446
22447/// If select range has more than one line, we
22448/// just point the cursor to range.start.
22449fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22450    if range.start.row == range.end.row {
22451        range
22452    } else {
22453        range.start..range.start
22454    }
22455}
22456pub struct KillRing(ClipboardItem);
22457impl Global for KillRing {}
22458
22459const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22460
22461enum BreakpointPromptEditAction {
22462    Log,
22463    Condition,
22464    HitCondition,
22465}
22466
22467struct BreakpointPromptEditor {
22468    pub(crate) prompt: Entity<Editor>,
22469    editor: WeakEntity<Editor>,
22470    breakpoint_anchor: Anchor,
22471    breakpoint: Breakpoint,
22472    edit_action: BreakpointPromptEditAction,
22473    block_ids: HashSet<CustomBlockId>,
22474    editor_margins: Arc<Mutex<EditorMargins>>,
22475    _subscriptions: Vec<Subscription>,
22476}
22477
22478impl BreakpointPromptEditor {
22479    const MAX_LINES: u8 = 4;
22480
22481    fn new(
22482        editor: WeakEntity<Editor>,
22483        breakpoint_anchor: Anchor,
22484        breakpoint: Breakpoint,
22485        edit_action: BreakpointPromptEditAction,
22486        window: &mut Window,
22487        cx: &mut Context<Self>,
22488    ) -> Self {
22489        let base_text = match edit_action {
22490            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22491            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22492            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22493        }
22494        .map(|msg| msg.to_string())
22495        .unwrap_or_default();
22496
22497        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22498        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22499
22500        let prompt = cx.new(|cx| {
22501            let mut prompt = Editor::new(
22502                EditorMode::AutoHeight {
22503                    max_lines: Self::MAX_LINES as usize,
22504                },
22505                buffer,
22506                None,
22507                window,
22508                cx,
22509            );
22510            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22511            prompt.set_show_cursor_when_unfocused(false, cx);
22512            prompt.set_placeholder_text(
22513                match edit_action {
22514                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22515                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22516                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22517                },
22518                cx,
22519            );
22520
22521            prompt
22522        });
22523
22524        Self {
22525            prompt,
22526            editor,
22527            breakpoint_anchor,
22528            breakpoint,
22529            edit_action,
22530            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22531            block_ids: Default::default(),
22532            _subscriptions: vec![],
22533        }
22534    }
22535
22536    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22537        self.block_ids.extend(block_ids)
22538    }
22539
22540    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22541        if let Some(editor) = self.editor.upgrade() {
22542            let message = self
22543                .prompt
22544                .read(cx)
22545                .buffer
22546                .read(cx)
22547                .as_singleton()
22548                .expect("A multi buffer in breakpoint prompt isn't possible")
22549                .read(cx)
22550                .as_rope()
22551                .to_string();
22552
22553            editor.update(cx, |editor, cx| {
22554                editor.edit_breakpoint_at_anchor(
22555                    self.breakpoint_anchor,
22556                    self.breakpoint.clone(),
22557                    match self.edit_action {
22558                        BreakpointPromptEditAction::Log => {
22559                            BreakpointEditAction::EditLogMessage(message.into())
22560                        }
22561                        BreakpointPromptEditAction::Condition => {
22562                            BreakpointEditAction::EditCondition(message.into())
22563                        }
22564                        BreakpointPromptEditAction::HitCondition => {
22565                            BreakpointEditAction::EditHitCondition(message.into())
22566                        }
22567                    },
22568                    cx,
22569                );
22570
22571                editor.remove_blocks(self.block_ids.clone(), None, cx);
22572                cx.focus_self(window);
22573            });
22574        }
22575    }
22576
22577    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22578        self.editor
22579            .update(cx, |editor, cx| {
22580                editor.remove_blocks(self.block_ids.clone(), None, cx);
22581                window.focus(&editor.focus_handle);
22582            })
22583            .log_err();
22584    }
22585
22586    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22587        let settings = ThemeSettings::get_global(cx);
22588        let text_style = TextStyle {
22589            color: if self.prompt.read(cx).read_only(cx) {
22590                cx.theme().colors().text_disabled
22591            } else {
22592                cx.theme().colors().text
22593            },
22594            font_family: settings.buffer_font.family.clone(),
22595            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22596            font_size: settings.buffer_font_size(cx).into(),
22597            font_weight: settings.buffer_font.weight,
22598            line_height: relative(settings.buffer_line_height.value()),
22599            ..Default::default()
22600        };
22601        EditorElement::new(
22602            &self.prompt,
22603            EditorStyle {
22604                background: cx.theme().colors().editor_background,
22605                local_player: cx.theme().players().local(),
22606                text: text_style,
22607                ..Default::default()
22608            },
22609        )
22610    }
22611}
22612
22613impl Render for BreakpointPromptEditor {
22614    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22615        let editor_margins = *self.editor_margins.lock();
22616        let gutter_dimensions = editor_margins.gutter;
22617        h_flex()
22618            .key_context("Editor")
22619            .bg(cx.theme().colors().editor_background)
22620            .border_y_1()
22621            .border_color(cx.theme().status().info_border)
22622            .size_full()
22623            .py(window.line_height() / 2.5)
22624            .on_action(cx.listener(Self::confirm))
22625            .on_action(cx.listener(Self::cancel))
22626            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22627            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22628    }
22629}
22630
22631impl Focusable for BreakpointPromptEditor {
22632    fn focus_handle(&self, cx: &App) -> FocusHandle {
22633        self.prompt.focus_handle(cx)
22634    }
22635}
22636
22637fn all_edits_insertions_or_deletions(
22638    edits: &Vec<(Range<Anchor>, String)>,
22639    snapshot: &MultiBufferSnapshot,
22640) -> bool {
22641    let mut all_insertions = true;
22642    let mut all_deletions = true;
22643
22644    for (range, new_text) in edits.iter() {
22645        let range_is_empty = range.to_offset(&snapshot).is_empty();
22646        let text_is_empty = new_text.is_empty();
22647
22648        if range_is_empty != text_is_empty {
22649            if range_is_empty {
22650                all_deletions = false;
22651            } else {
22652                all_insertions = false;
22653            }
22654        } else {
22655            return false;
22656        }
22657
22658        if !all_insertions && !all_deletions {
22659            return false;
22660        }
22661    }
22662    all_insertions || all_deletions
22663}
22664
22665struct MissingEditPredictionKeybindingTooltip;
22666
22667impl Render for MissingEditPredictionKeybindingTooltip {
22668    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22669        ui::tooltip_container(window, cx, |container, _, cx| {
22670            container
22671                .flex_shrink_0()
22672                .max_w_80()
22673                .min_h(rems_from_px(124.))
22674                .justify_between()
22675                .child(
22676                    v_flex()
22677                        .flex_1()
22678                        .text_ui_sm(cx)
22679                        .child(Label::new("Conflict with Accept Keybinding"))
22680                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22681                )
22682                .child(
22683                    h_flex()
22684                        .pb_1()
22685                        .gap_1()
22686                        .items_end()
22687                        .w_full()
22688                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22689                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22690                        }))
22691                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22692                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22693                        })),
22694                )
22695        })
22696    }
22697}
22698
22699#[derive(Debug, Clone, Copy, PartialEq)]
22700pub struct LineHighlight {
22701    pub background: Background,
22702    pub border: Option<gpui::Hsla>,
22703    pub include_gutter: bool,
22704    pub type_id: Option<TypeId>,
22705}
22706
22707fn render_diff_hunk_controls(
22708    row: u32,
22709    status: &DiffHunkStatus,
22710    hunk_range: Range<Anchor>,
22711    is_created_file: bool,
22712    line_height: Pixels,
22713    editor: &Entity<Editor>,
22714    _window: &mut Window,
22715    cx: &mut App,
22716) -> AnyElement {
22717    h_flex()
22718        .h(line_height)
22719        .mr_1()
22720        .gap_1()
22721        .px_0p5()
22722        .pb_1()
22723        .border_x_1()
22724        .border_b_1()
22725        .border_color(cx.theme().colors().border_variant)
22726        .rounded_b_lg()
22727        .bg(cx.theme().colors().editor_background)
22728        .gap_1()
22729        .block_mouse_except_scroll()
22730        .shadow_md()
22731        .child(if status.has_secondary_hunk() {
22732            Button::new(("stage", row as u64), "Stage")
22733                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22734                .tooltip({
22735                    let focus_handle = editor.focus_handle(cx);
22736                    move |window, cx| {
22737                        Tooltip::for_action_in(
22738                            "Stage Hunk",
22739                            &::git::ToggleStaged,
22740                            &focus_handle,
22741                            window,
22742                            cx,
22743                        )
22744                    }
22745                })
22746                .on_click({
22747                    let editor = editor.clone();
22748                    move |_event, _window, cx| {
22749                        editor.update(cx, |editor, cx| {
22750                            editor.stage_or_unstage_diff_hunks(
22751                                true,
22752                                vec![hunk_range.start..hunk_range.start],
22753                                cx,
22754                            );
22755                        });
22756                    }
22757                })
22758        } else {
22759            Button::new(("unstage", row as u64), "Unstage")
22760                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22761                .tooltip({
22762                    let focus_handle = editor.focus_handle(cx);
22763                    move |window, cx| {
22764                        Tooltip::for_action_in(
22765                            "Unstage Hunk",
22766                            &::git::ToggleStaged,
22767                            &focus_handle,
22768                            window,
22769                            cx,
22770                        )
22771                    }
22772                })
22773                .on_click({
22774                    let editor = editor.clone();
22775                    move |_event, _window, cx| {
22776                        editor.update(cx, |editor, cx| {
22777                            editor.stage_or_unstage_diff_hunks(
22778                                false,
22779                                vec![hunk_range.start..hunk_range.start],
22780                                cx,
22781                            );
22782                        });
22783                    }
22784                })
22785        })
22786        .child(
22787            Button::new(("restore", row as u64), "Restore")
22788                .tooltip({
22789                    let focus_handle = editor.focus_handle(cx);
22790                    move |window, cx| {
22791                        Tooltip::for_action_in(
22792                            "Restore Hunk",
22793                            &::git::Restore,
22794                            &focus_handle,
22795                            window,
22796                            cx,
22797                        )
22798                    }
22799                })
22800                .on_click({
22801                    let editor = editor.clone();
22802                    move |_event, window, cx| {
22803                        editor.update(cx, |editor, cx| {
22804                            let snapshot = editor.snapshot(window, cx);
22805                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22806                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22807                        });
22808                    }
22809                })
22810                .disabled(is_created_file),
22811        )
22812        .when(
22813            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22814            |el| {
22815                el.child(
22816                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22817                        .shape(IconButtonShape::Square)
22818                        .icon_size(IconSize::Small)
22819                        // .disabled(!has_multiple_hunks)
22820                        .tooltip({
22821                            let focus_handle = editor.focus_handle(cx);
22822                            move |window, cx| {
22823                                Tooltip::for_action_in(
22824                                    "Next Hunk",
22825                                    &GoToHunk,
22826                                    &focus_handle,
22827                                    window,
22828                                    cx,
22829                                )
22830                            }
22831                        })
22832                        .on_click({
22833                            let editor = editor.clone();
22834                            move |_event, window, cx| {
22835                                editor.update(cx, |editor, cx| {
22836                                    let snapshot = editor.snapshot(window, cx);
22837                                    let position =
22838                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22839                                    editor.go_to_hunk_before_or_after_position(
22840                                        &snapshot,
22841                                        position,
22842                                        Direction::Next,
22843                                        window,
22844                                        cx,
22845                                    );
22846                                    editor.expand_selected_diff_hunks(cx);
22847                                });
22848                            }
22849                        }),
22850                )
22851                .child(
22852                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22853                        .shape(IconButtonShape::Square)
22854                        .icon_size(IconSize::Small)
22855                        // .disabled(!has_multiple_hunks)
22856                        .tooltip({
22857                            let focus_handle = editor.focus_handle(cx);
22858                            move |window, cx| {
22859                                Tooltip::for_action_in(
22860                                    "Previous Hunk",
22861                                    &GoToPreviousHunk,
22862                                    &focus_handle,
22863                                    window,
22864                                    cx,
22865                                )
22866                            }
22867                        })
22868                        .on_click({
22869                            let editor = editor.clone();
22870                            move |_event, window, cx| {
22871                                editor.update(cx, |editor, cx| {
22872                                    let snapshot = editor.snapshot(window, cx);
22873                                    let point =
22874                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22875                                    editor.go_to_hunk_before_or_after_position(
22876                                        &snapshot,
22877                                        point,
22878                                        Direction::Prev,
22879                                        window,
22880                                        cx,
22881                                    );
22882                                    editor.expand_selected_diff_hunks(cx);
22883                                });
22884                            }
22885                        }),
22886                )
22887            },
22888        )
22889        .into_any_element()
22890}