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        mouse_down_time: Instant,
  916    },
  917    /// State when the mouse is dragging the selection in the editor.
  918    Dragging {
  919        selection: Selection<Anchor>,
  920        drop_cursor: Selection<Anchor>,
  921        hide_drop_cursor: bool,
  922    },
  923}
  924
  925/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  926/// a breakpoint on them.
  927#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  928struct PhantomBreakpointIndicator {
  929    display_row: DisplayRow,
  930    /// There's a small debounce between hovering over the line and showing the indicator.
  931    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  932    is_active: bool,
  933    collides_with_existing_breakpoint: bool,
  934}
  935
  936/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  937///
  938/// See the [module level documentation](self) for more information.
  939pub struct Editor {
  940    focus_handle: FocusHandle,
  941    last_focused_descendant: Option<WeakFocusHandle>,
  942    /// The text buffer being edited
  943    buffer: Entity<MultiBuffer>,
  944    /// Map of how text in the buffer should be displayed.
  945    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  946    pub display_map: Entity<DisplayMap>,
  947    pub selections: SelectionsCollection,
  948    pub scroll_manager: ScrollManager,
  949    /// When inline assist editors are linked, they all render cursors because
  950    /// typing enters text into each of them, even the ones that aren't focused.
  951    pub(crate) show_cursor_when_unfocused: bool,
  952    columnar_selection_tail: Option<Anchor>,
  953    columnar_display_point: Option<DisplayPoint>,
  954    add_selections_state: Option<AddSelectionsState>,
  955    select_next_state: Option<SelectNextState>,
  956    select_prev_state: Option<SelectNextState>,
  957    selection_history: SelectionHistory,
  958    defer_selection_effects: bool,
  959    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  960    autoclose_regions: Vec<AutocloseRegion>,
  961    snippet_stack: InvalidationStack<SnippetState>,
  962    select_syntax_node_history: SelectSyntaxNodeHistory,
  963    ime_transaction: Option<TransactionId>,
  964    pub diagnostics_max_severity: DiagnosticSeverity,
  965    active_diagnostics: ActiveDiagnostic,
  966    show_inline_diagnostics: bool,
  967    inline_diagnostics_update: Task<()>,
  968    inline_diagnostics_enabled: bool,
  969    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  970    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  971    hard_wrap: Option<usize>,
  972
  973    // TODO: make this a access method
  974    pub project: Option<Entity<Project>>,
  975    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  976    completion_provider: Option<Rc<dyn CompletionProvider>>,
  977    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  978    blink_manager: Entity<BlinkManager>,
  979    show_cursor_names: bool,
  980    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  981    pub show_local_selections: bool,
  982    mode: EditorMode,
  983    show_breadcrumbs: bool,
  984    show_gutter: bool,
  985    show_scrollbars: ScrollbarAxes,
  986    minimap_visibility: MinimapVisibility,
  987    offset_content: bool,
  988    disable_expand_excerpt_buttons: bool,
  989    show_line_numbers: Option<bool>,
  990    use_relative_line_numbers: Option<bool>,
  991    show_git_diff_gutter: Option<bool>,
  992    show_code_actions: Option<bool>,
  993    show_runnables: Option<bool>,
  994    show_breakpoints: Option<bool>,
  995    show_wrap_guides: Option<bool>,
  996    show_indent_guides: Option<bool>,
  997    placeholder_text: Option<Arc<str>>,
  998    highlight_order: usize,
  999    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1000    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
 1001    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1002    scrollbar_marker_state: ScrollbarMarkerState,
 1003    active_indent_guides_state: ActiveIndentGuidesState,
 1004    nav_history: Option<ItemNavHistory>,
 1005    context_menu: RefCell<Option<CodeContextMenu>>,
 1006    context_menu_options: Option<ContextMenuOptions>,
 1007    mouse_context_menu: Option<MouseContextMenu>,
 1008    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1009    inline_blame_popover: Option<InlineBlamePopover>,
 1010    signature_help_state: SignatureHelpState,
 1011    auto_signature_help: Option<bool>,
 1012    find_all_references_task_sources: Vec<Anchor>,
 1013    next_completion_id: CompletionId,
 1014    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1015    code_actions_task: Option<Task<Result<()>>>,
 1016    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1017    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1018    document_highlights_task: Option<Task<()>>,
 1019    linked_editing_range_task: Option<Task<Option<()>>>,
 1020    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1021    pending_rename: Option<RenameState>,
 1022    searchable: bool,
 1023    cursor_shape: CursorShape,
 1024    current_line_highlight: Option<CurrentLineHighlight>,
 1025    collapse_matches: bool,
 1026    autoindent_mode: Option<AutoindentMode>,
 1027    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1028    input_enabled: bool,
 1029    use_modal_editing: bool,
 1030    read_only: bool,
 1031    leader_id: Option<CollaboratorId>,
 1032    remote_id: Option<ViewId>,
 1033    pub hover_state: HoverState,
 1034    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1035    gutter_hovered: bool,
 1036    hovered_link_state: Option<HoveredLinkState>,
 1037    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1038    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1039    active_inline_completion: Option<InlineCompletionState>,
 1040    /// Used to prevent flickering as the user types while the menu is open
 1041    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1042    edit_prediction_settings: EditPredictionSettings,
 1043    inline_completions_hidden_for_vim_mode: bool,
 1044    show_inline_completions_override: Option<bool>,
 1045    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1046    edit_prediction_preview: EditPredictionPreview,
 1047    edit_prediction_indent_conflict: bool,
 1048    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1049    inlay_hint_cache: InlayHintCache,
 1050    next_inlay_id: usize,
 1051    _subscriptions: Vec<Subscription>,
 1052    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1053    gutter_dimensions: GutterDimensions,
 1054    style: Option<EditorStyle>,
 1055    text_style_refinement: Option<TextStyleRefinement>,
 1056    next_editor_action_id: EditorActionId,
 1057    editor_actions: Rc<
 1058        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1059    >,
 1060    use_autoclose: bool,
 1061    use_auto_surround: bool,
 1062    auto_replace_emoji_shortcode: bool,
 1063    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1064    show_git_blame_gutter: bool,
 1065    show_git_blame_inline: bool,
 1066    show_git_blame_inline_delay_task: Option<Task<()>>,
 1067    git_blame_inline_enabled: bool,
 1068    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1069    serialize_dirty_buffers: bool,
 1070    show_selection_menu: Option<bool>,
 1071    blame: Option<Entity<GitBlame>>,
 1072    blame_subscription: Option<Subscription>,
 1073    custom_context_menu: Option<
 1074        Box<
 1075            dyn 'static
 1076                + Fn(
 1077                    &mut Self,
 1078                    DisplayPoint,
 1079                    &mut Window,
 1080                    &mut Context<Self>,
 1081                ) -> Option<Entity<ui::ContextMenu>>,
 1082        >,
 1083    >,
 1084    last_bounds: Option<Bounds<Pixels>>,
 1085    last_position_map: Option<Rc<PositionMap>>,
 1086    expect_bounds_change: Option<Bounds<Pixels>>,
 1087    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1088    tasks_update_task: Option<Task<()>>,
 1089    breakpoint_store: Option<Entity<BreakpointStore>>,
 1090    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1091    pull_diagnostics_task: Task<()>,
 1092    in_project_search: bool,
 1093    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1094    breadcrumb_header: Option<String>,
 1095    focused_block: Option<FocusedBlock>,
 1096    next_scroll_position: NextScrollCursorCenterTopBottom,
 1097    addons: HashMap<TypeId, Box<dyn Addon>>,
 1098    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1099    load_diff_task: Option<Shared<Task<()>>>,
 1100    /// Whether we are temporarily displaying a diff other than git's
 1101    temporary_diff_override: bool,
 1102    selection_mark_mode: bool,
 1103    toggle_fold_multiple_buffers: Task<()>,
 1104    _scroll_cursor_center_top_bottom_task: Task<()>,
 1105    serialize_selections: Task<()>,
 1106    serialize_folds: Task<()>,
 1107    mouse_cursor_hidden: bool,
 1108    minimap: Option<Entity<Self>>,
 1109    hide_mouse_mode: HideMouseMode,
 1110    pub change_list: ChangeList,
 1111    inline_value_cache: InlineValueCache,
 1112    selection_drag_state: SelectionDragState,
 1113    drag_and_drop_selection_enabled: bool,
 1114}
 1115
 1116#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1117enum NextScrollCursorCenterTopBottom {
 1118    #[default]
 1119    Center,
 1120    Top,
 1121    Bottom,
 1122}
 1123
 1124impl NextScrollCursorCenterTopBottom {
 1125    fn next(&self) -> Self {
 1126        match self {
 1127            Self::Center => Self::Top,
 1128            Self::Top => Self::Bottom,
 1129            Self::Bottom => Self::Center,
 1130        }
 1131    }
 1132}
 1133
 1134#[derive(Clone)]
 1135pub struct EditorSnapshot {
 1136    pub mode: EditorMode,
 1137    show_gutter: bool,
 1138    show_line_numbers: Option<bool>,
 1139    show_git_diff_gutter: Option<bool>,
 1140    show_code_actions: Option<bool>,
 1141    show_runnables: Option<bool>,
 1142    show_breakpoints: Option<bool>,
 1143    git_blame_gutter_max_author_length: Option<usize>,
 1144    pub display_snapshot: DisplaySnapshot,
 1145    pub placeholder_text: Option<Arc<str>>,
 1146    is_focused: bool,
 1147    scroll_anchor: ScrollAnchor,
 1148    ongoing_scroll: OngoingScroll,
 1149    current_line_highlight: CurrentLineHighlight,
 1150    gutter_hovered: bool,
 1151}
 1152
 1153#[derive(Default, Debug, Clone, Copy)]
 1154pub struct GutterDimensions {
 1155    pub left_padding: Pixels,
 1156    pub right_padding: Pixels,
 1157    pub width: Pixels,
 1158    pub margin: Pixels,
 1159    pub git_blame_entries_width: Option<Pixels>,
 1160}
 1161
 1162impl GutterDimensions {
 1163    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1164        Self {
 1165            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1166            ..Default::default()
 1167        }
 1168    }
 1169
 1170    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1171        -cx.text_system().descent(font_id, font_size)
 1172    }
 1173    /// The full width of the space taken up by the gutter.
 1174    pub fn full_width(&self) -> Pixels {
 1175        self.margin + self.width
 1176    }
 1177
 1178    /// The width of the space reserved for the fold indicators,
 1179    /// use alongside 'justify_end' and `gutter_width` to
 1180    /// right align content with the line numbers
 1181    pub fn fold_area_width(&self) -> Pixels {
 1182        self.margin + self.right_padding
 1183    }
 1184}
 1185
 1186#[derive(Debug)]
 1187pub struct RemoteSelection {
 1188    pub replica_id: ReplicaId,
 1189    pub selection: Selection<Anchor>,
 1190    pub cursor_shape: CursorShape,
 1191    pub collaborator_id: CollaboratorId,
 1192    pub line_mode: bool,
 1193    pub user_name: Option<SharedString>,
 1194    pub color: PlayerColor,
 1195}
 1196
 1197#[derive(Clone, Debug)]
 1198struct SelectionHistoryEntry {
 1199    selections: Arc<[Selection<Anchor>]>,
 1200    select_next_state: Option<SelectNextState>,
 1201    select_prev_state: Option<SelectNextState>,
 1202    add_selections_state: Option<AddSelectionsState>,
 1203}
 1204
 1205#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1206enum SelectionHistoryMode {
 1207    Normal,
 1208    Undoing,
 1209    Redoing,
 1210    Skipping,
 1211}
 1212
 1213#[derive(Clone, PartialEq, Eq, Hash)]
 1214struct HoveredCursor {
 1215    replica_id: u16,
 1216    selection_id: usize,
 1217}
 1218
 1219impl Default for SelectionHistoryMode {
 1220    fn default() -> Self {
 1221        Self::Normal
 1222    }
 1223}
 1224
 1225struct DeferredSelectionEffectsState {
 1226    changed: bool,
 1227    should_update_completions: bool,
 1228    autoscroll: Option<Autoscroll>,
 1229    old_cursor_position: Anchor,
 1230    history_entry: SelectionHistoryEntry,
 1231}
 1232
 1233#[derive(Default)]
 1234struct SelectionHistory {
 1235    #[allow(clippy::type_complexity)]
 1236    selections_by_transaction:
 1237        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1238    mode: SelectionHistoryMode,
 1239    undo_stack: VecDeque<SelectionHistoryEntry>,
 1240    redo_stack: VecDeque<SelectionHistoryEntry>,
 1241}
 1242
 1243impl SelectionHistory {
 1244    #[track_caller]
 1245    fn insert_transaction(
 1246        &mut self,
 1247        transaction_id: TransactionId,
 1248        selections: Arc<[Selection<Anchor>]>,
 1249    ) {
 1250        if selections.is_empty() {
 1251            log::error!(
 1252                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1253                std::panic::Location::caller()
 1254            );
 1255            return;
 1256        }
 1257        self.selections_by_transaction
 1258            .insert(transaction_id, (selections, None));
 1259    }
 1260
 1261    #[allow(clippy::type_complexity)]
 1262    fn transaction(
 1263        &self,
 1264        transaction_id: TransactionId,
 1265    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1266        self.selections_by_transaction.get(&transaction_id)
 1267    }
 1268
 1269    #[allow(clippy::type_complexity)]
 1270    fn transaction_mut(
 1271        &mut self,
 1272        transaction_id: TransactionId,
 1273    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1274        self.selections_by_transaction.get_mut(&transaction_id)
 1275    }
 1276
 1277    fn push(&mut self, entry: SelectionHistoryEntry) {
 1278        if !entry.selections.is_empty() {
 1279            match self.mode {
 1280                SelectionHistoryMode::Normal => {
 1281                    self.push_undo(entry);
 1282                    self.redo_stack.clear();
 1283                }
 1284                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1285                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1286                SelectionHistoryMode::Skipping => {}
 1287            }
 1288        }
 1289    }
 1290
 1291    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1292        if self
 1293            .undo_stack
 1294            .back()
 1295            .map_or(true, |e| e.selections != entry.selections)
 1296        {
 1297            self.undo_stack.push_back(entry);
 1298            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1299                self.undo_stack.pop_front();
 1300            }
 1301        }
 1302    }
 1303
 1304    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1305        if self
 1306            .redo_stack
 1307            .back()
 1308            .map_or(true, |e| e.selections != entry.selections)
 1309        {
 1310            self.redo_stack.push_back(entry);
 1311            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1312                self.redo_stack.pop_front();
 1313            }
 1314        }
 1315    }
 1316}
 1317
 1318#[derive(Clone, Copy)]
 1319pub struct RowHighlightOptions {
 1320    pub autoscroll: bool,
 1321    pub include_gutter: bool,
 1322}
 1323
 1324impl Default for RowHighlightOptions {
 1325    fn default() -> Self {
 1326        Self {
 1327            autoscroll: Default::default(),
 1328            include_gutter: true,
 1329        }
 1330    }
 1331}
 1332
 1333struct RowHighlight {
 1334    index: usize,
 1335    range: Range<Anchor>,
 1336    color: Hsla,
 1337    options: RowHighlightOptions,
 1338    type_id: TypeId,
 1339}
 1340
 1341#[derive(Clone, Debug)]
 1342struct AddSelectionsState {
 1343    groups: Vec<AddSelectionsGroup>,
 1344}
 1345
 1346#[derive(Clone, Debug)]
 1347struct AddSelectionsGroup {
 1348    above: bool,
 1349    stack: Vec<usize>,
 1350}
 1351
 1352#[derive(Clone)]
 1353struct SelectNextState {
 1354    query: AhoCorasick,
 1355    wordwise: bool,
 1356    done: bool,
 1357}
 1358
 1359impl std::fmt::Debug for SelectNextState {
 1360    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1361        f.debug_struct(std::any::type_name::<Self>())
 1362            .field("wordwise", &self.wordwise)
 1363            .field("done", &self.done)
 1364            .finish()
 1365    }
 1366}
 1367
 1368#[derive(Debug)]
 1369struct AutocloseRegion {
 1370    selection_id: usize,
 1371    range: Range<Anchor>,
 1372    pair: BracketPair,
 1373}
 1374
 1375#[derive(Debug)]
 1376struct SnippetState {
 1377    ranges: Vec<Vec<Range<Anchor>>>,
 1378    active_index: usize,
 1379    choices: Vec<Option<Vec<String>>>,
 1380}
 1381
 1382#[doc(hidden)]
 1383pub struct RenameState {
 1384    pub range: Range<Anchor>,
 1385    pub old_name: Arc<str>,
 1386    pub editor: Entity<Editor>,
 1387    block_id: CustomBlockId,
 1388}
 1389
 1390struct InvalidationStack<T>(Vec<T>);
 1391
 1392struct RegisteredInlineCompletionProvider {
 1393    provider: Arc<dyn InlineCompletionProviderHandle>,
 1394    _subscription: Subscription,
 1395}
 1396
 1397#[derive(Debug, PartialEq, Eq)]
 1398pub struct ActiveDiagnosticGroup {
 1399    pub active_range: Range<Anchor>,
 1400    pub active_message: String,
 1401    pub group_id: usize,
 1402    pub blocks: HashSet<CustomBlockId>,
 1403}
 1404
 1405#[derive(Debug, PartialEq, Eq)]
 1406
 1407pub(crate) enum ActiveDiagnostic {
 1408    None,
 1409    All,
 1410    Group(ActiveDiagnosticGroup),
 1411}
 1412
 1413#[derive(Serialize, Deserialize, Clone, Debug)]
 1414pub struct ClipboardSelection {
 1415    /// The number of bytes in this selection.
 1416    pub len: usize,
 1417    /// Whether this was a full-line selection.
 1418    pub is_entire_line: bool,
 1419    /// The indentation of the first line when this content was originally copied.
 1420    pub first_line_indent: u32,
 1421}
 1422
 1423// selections, scroll behavior, was newest selection reversed
 1424type SelectSyntaxNodeHistoryState = (
 1425    Box<[Selection<usize>]>,
 1426    SelectSyntaxNodeScrollBehavior,
 1427    bool,
 1428);
 1429
 1430#[derive(Default)]
 1431struct SelectSyntaxNodeHistory {
 1432    stack: Vec<SelectSyntaxNodeHistoryState>,
 1433    // disable temporarily to allow changing selections without losing the stack
 1434    pub disable_clearing: bool,
 1435}
 1436
 1437impl SelectSyntaxNodeHistory {
 1438    pub fn try_clear(&mut self) {
 1439        if !self.disable_clearing {
 1440            self.stack.clear();
 1441        }
 1442    }
 1443
 1444    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1445        self.stack.push(selection);
 1446    }
 1447
 1448    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1449        self.stack.pop()
 1450    }
 1451}
 1452
 1453enum SelectSyntaxNodeScrollBehavior {
 1454    CursorTop,
 1455    FitSelection,
 1456    CursorBottom,
 1457}
 1458
 1459#[derive(Debug)]
 1460pub(crate) struct NavigationData {
 1461    cursor_anchor: Anchor,
 1462    cursor_position: Point,
 1463    scroll_anchor: ScrollAnchor,
 1464    scroll_top_row: u32,
 1465}
 1466
 1467#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1468pub enum GotoDefinitionKind {
 1469    Symbol,
 1470    Declaration,
 1471    Type,
 1472    Implementation,
 1473}
 1474
 1475#[derive(Debug, Clone)]
 1476enum InlayHintRefreshReason {
 1477    ModifiersChanged(bool),
 1478    Toggle(bool),
 1479    SettingsChange(InlayHintSettings),
 1480    NewLinesShown,
 1481    BufferEdited(HashSet<Arc<Language>>),
 1482    RefreshRequested,
 1483    ExcerptsRemoved(Vec<ExcerptId>),
 1484}
 1485
 1486impl InlayHintRefreshReason {
 1487    fn description(&self) -> &'static str {
 1488        match self {
 1489            Self::ModifiersChanged(_) => "modifiers changed",
 1490            Self::Toggle(_) => "toggle",
 1491            Self::SettingsChange(_) => "settings change",
 1492            Self::NewLinesShown => "new lines shown",
 1493            Self::BufferEdited(_) => "buffer edited",
 1494            Self::RefreshRequested => "refresh requested",
 1495            Self::ExcerptsRemoved(_) => "excerpts removed",
 1496        }
 1497    }
 1498}
 1499
 1500pub enum FormatTarget {
 1501    Buffers,
 1502    Ranges(Vec<Range<MultiBufferPoint>>),
 1503}
 1504
 1505pub(crate) struct FocusedBlock {
 1506    id: BlockId,
 1507    focus_handle: WeakFocusHandle,
 1508}
 1509
 1510#[derive(Clone)]
 1511enum JumpData {
 1512    MultiBufferRow {
 1513        row: MultiBufferRow,
 1514        line_offset_from_top: u32,
 1515    },
 1516    MultiBufferPoint {
 1517        excerpt_id: ExcerptId,
 1518        position: Point,
 1519        anchor: text::Anchor,
 1520        line_offset_from_top: u32,
 1521    },
 1522}
 1523
 1524pub enum MultibufferSelectionMode {
 1525    First,
 1526    All,
 1527}
 1528
 1529#[derive(Clone, Copy, Debug, Default)]
 1530pub struct RewrapOptions {
 1531    pub override_language_settings: bool,
 1532    pub preserve_existing_whitespace: bool,
 1533}
 1534
 1535impl Editor {
 1536    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1537        let buffer = cx.new(|cx| Buffer::local("", cx));
 1538        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1539        Self::new(
 1540            EditorMode::SingleLine { auto_width: false },
 1541            buffer,
 1542            None,
 1543            window,
 1544            cx,
 1545        )
 1546    }
 1547
 1548    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1549        let buffer = cx.new(|cx| Buffer::local("", cx));
 1550        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1551        Self::new(EditorMode::full(), buffer, None, window, cx)
 1552    }
 1553
 1554    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1555        let buffer = cx.new(|cx| Buffer::local("", cx));
 1556        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1557        Self::new(
 1558            EditorMode::SingleLine { auto_width: true },
 1559            buffer,
 1560            None,
 1561            window,
 1562            cx,
 1563        )
 1564    }
 1565
 1566    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1567        let buffer = cx.new(|cx| Buffer::local("", cx));
 1568        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1569        Self::new(
 1570            EditorMode::AutoHeight { max_lines },
 1571            buffer,
 1572            None,
 1573            window,
 1574            cx,
 1575        )
 1576    }
 1577
 1578    pub fn for_buffer(
 1579        buffer: Entity<Buffer>,
 1580        project: Option<Entity<Project>>,
 1581        window: &mut Window,
 1582        cx: &mut Context<Self>,
 1583    ) -> Self {
 1584        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1585        Self::new(EditorMode::full(), buffer, project, window, cx)
 1586    }
 1587
 1588    pub fn for_multibuffer(
 1589        buffer: Entity<MultiBuffer>,
 1590        project: Option<Entity<Project>>,
 1591        window: &mut Window,
 1592        cx: &mut Context<Self>,
 1593    ) -> Self {
 1594        Self::new(EditorMode::full(), buffer, project, window, cx)
 1595    }
 1596
 1597    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1598        let mut clone = Self::new(
 1599            self.mode.clone(),
 1600            self.buffer.clone(),
 1601            self.project.clone(),
 1602            window,
 1603            cx,
 1604        );
 1605        self.display_map.update(cx, |display_map, cx| {
 1606            let snapshot = display_map.snapshot(cx);
 1607            clone.display_map.update(cx, |display_map, cx| {
 1608                display_map.set_state(&snapshot, cx);
 1609            });
 1610        });
 1611        clone.folds_did_change(cx);
 1612        clone.selections.clone_state(&self.selections);
 1613        clone.scroll_manager.clone_state(&self.scroll_manager);
 1614        clone.searchable = self.searchable;
 1615        clone.read_only = self.read_only;
 1616        clone
 1617    }
 1618
 1619    pub fn new(
 1620        mode: EditorMode,
 1621        buffer: Entity<MultiBuffer>,
 1622        project: Option<Entity<Project>>,
 1623        window: &mut Window,
 1624        cx: &mut Context<Self>,
 1625    ) -> Self {
 1626        Editor::new_internal(mode, buffer, project, None, window, cx)
 1627    }
 1628
 1629    fn new_internal(
 1630        mode: EditorMode,
 1631        buffer: Entity<MultiBuffer>,
 1632        project: Option<Entity<Project>>,
 1633        display_map: Option<Entity<DisplayMap>>,
 1634        window: &mut Window,
 1635        cx: &mut Context<Self>,
 1636    ) -> Self {
 1637        debug_assert!(
 1638            display_map.is_none() || mode.is_minimap(),
 1639            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1640        );
 1641
 1642        let full_mode = mode.is_full();
 1643        let diagnostics_max_severity = if full_mode {
 1644            EditorSettings::get_global(cx)
 1645                .diagnostics_max_severity
 1646                .unwrap_or(DiagnosticSeverity::Hint)
 1647        } else {
 1648            DiagnosticSeverity::Off
 1649        };
 1650        let style = window.text_style();
 1651        let font_size = style.font_size.to_pixels(window.rem_size());
 1652        let editor = cx.entity().downgrade();
 1653        let fold_placeholder = FoldPlaceholder {
 1654            constrain_width: true,
 1655            render: Arc::new(move |fold_id, fold_range, cx| {
 1656                let editor = editor.clone();
 1657                div()
 1658                    .id(fold_id)
 1659                    .bg(cx.theme().colors().ghost_element_background)
 1660                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1661                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1662                    .rounded_xs()
 1663                    .size_full()
 1664                    .cursor_pointer()
 1665                    .child("")
 1666                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1667                    .on_click(move |_, _window, cx| {
 1668                        editor
 1669                            .update(cx, |editor, cx| {
 1670                                editor.unfold_ranges(
 1671                                    &[fold_range.start..fold_range.end],
 1672                                    true,
 1673                                    false,
 1674                                    cx,
 1675                                );
 1676                                cx.stop_propagation();
 1677                            })
 1678                            .ok();
 1679                    })
 1680                    .into_any()
 1681            }),
 1682            merge_adjacent: true,
 1683            ..FoldPlaceholder::default()
 1684        };
 1685        let display_map = display_map.unwrap_or_else(|| {
 1686            cx.new(|cx| {
 1687                DisplayMap::new(
 1688                    buffer.clone(),
 1689                    style.font(),
 1690                    font_size,
 1691                    None,
 1692                    FILE_HEADER_HEIGHT,
 1693                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1694                    fold_placeholder,
 1695                    diagnostics_max_severity,
 1696                    cx,
 1697                )
 1698            })
 1699        });
 1700
 1701        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1702
 1703        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1704
 1705        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1706            .then(|| language_settings::SoftWrap::None);
 1707
 1708        let mut project_subscriptions = Vec::new();
 1709        if mode.is_full() {
 1710            if let Some(project) = project.as_ref() {
 1711                project_subscriptions.push(cx.subscribe_in(
 1712                    project,
 1713                    window,
 1714                    |editor, _, event, window, cx| match event {
 1715                        project::Event::RefreshCodeLens => {
 1716                            // we always query lens with actions, without storing them, always refreshing them
 1717                        }
 1718                        project::Event::RefreshInlayHints => {
 1719                            editor
 1720                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1721                        }
 1722                        project::Event::LanguageServerAdded(..)
 1723                        | project::Event::LanguageServerRemoved(..) => {
 1724                            if editor.tasks_update_task.is_none() {
 1725                                editor.tasks_update_task =
 1726                                    Some(editor.refresh_runnables(window, cx));
 1727                            }
 1728                            editor.pull_diagnostics(None, window, cx);
 1729                        }
 1730                        project::Event::SnippetEdit(id, snippet_edits) => {
 1731                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1732                                let focus_handle = editor.focus_handle(cx);
 1733                                if focus_handle.is_focused(window) {
 1734                                    let snapshot = buffer.read(cx).snapshot();
 1735                                    for (range, snippet) in snippet_edits {
 1736                                        let editor_range =
 1737                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1738                                        editor
 1739                                            .insert_snippet(
 1740                                                &[editor_range],
 1741                                                snippet.clone(),
 1742                                                window,
 1743                                                cx,
 1744                                            )
 1745                                            .ok();
 1746                                    }
 1747                                }
 1748                            }
 1749                        }
 1750                        _ => {}
 1751                    },
 1752                ));
 1753                if let Some(task_inventory) = project
 1754                    .read(cx)
 1755                    .task_store()
 1756                    .read(cx)
 1757                    .task_inventory()
 1758                    .cloned()
 1759                {
 1760                    project_subscriptions.push(cx.observe_in(
 1761                        &task_inventory,
 1762                        window,
 1763                        |editor, _, window, cx| {
 1764                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1765                        },
 1766                    ));
 1767                };
 1768
 1769                project_subscriptions.push(cx.subscribe_in(
 1770                    &project.read(cx).breakpoint_store(),
 1771                    window,
 1772                    |editor, _, event, window, cx| match event {
 1773                        BreakpointStoreEvent::ClearDebugLines => {
 1774                            editor.clear_row_highlights::<ActiveDebugLine>();
 1775                            editor.refresh_inline_values(cx);
 1776                        }
 1777                        BreakpointStoreEvent::SetDebugLine => {
 1778                            if editor.go_to_active_debug_line(window, cx) {
 1779                                cx.stop_propagation();
 1780                            }
 1781
 1782                            editor.refresh_inline_values(cx);
 1783                        }
 1784                        _ => {}
 1785                    },
 1786                ));
 1787            }
 1788        }
 1789
 1790        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1791
 1792        let inlay_hint_settings =
 1793            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1794        let focus_handle = cx.focus_handle();
 1795        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1796            .detach();
 1797        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1798            .detach();
 1799        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1800            .detach();
 1801        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1802            .detach();
 1803        cx.observe_pending_input(window, Self::observe_pending_input)
 1804            .detach();
 1805
 1806        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1807            Some(false)
 1808        } else {
 1809            None
 1810        };
 1811
 1812        let breakpoint_store = match (&mode, project.as_ref()) {
 1813            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1814            _ => None,
 1815        };
 1816
 1817        let mut code_action_providers = Vec::new();
 1818        let mut load_uncommitted_diff = None;
 1819        if let Some(project) = project.clone() {
 1820            load_uncommitted_diff = Some(
 1821                update_uncommitted_diff_for_buffer(
 1822                    cx.entity(),
 1823                    &project,
 1824                    buffer.read(cx).all_buffers(),
 1825                    buffer.clone(),
 1826                    cx,
 1827                )
 1828                .shared(),
 1829            );
 1830            code_action_providers.push(Rc::new(project) as Rc<_>);
 1831        }
 1832
 1833        let mut editor = Self {
 1834            focus_handle,
 1835            show_cursor_when_unfocused: false,
 1836            last_focused_descendant: None,
 1837            buffer: buffer.clone(),
 1838            display_map: display_map.clone(),
 1839            selections,
 1840            scroll_manager: ScrollManager::new(cx),
 1841            columnar_selection_tail: None,
 1842            columnar_display_point: None,
 1843            add_selections_state: None,
 1844            select_next_state: None,
 1845            select_prev_state: None,
 1846            selection_history: SelectionHistory::default(),
 1847            defer_selection_effects: false,
 1848            deferred_selection_effects_state: None,
 1849            autoclose_regions: Vec::new(),
 1850            snippet_stack: InvalidationStack::default(),
 1851            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1852            ime_transaction: None,
 1853            active_diagnostics: ActiveDiagnostic::None,
 1854            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1855            inline_diagnostics_update: Task::ready(()),
 1856            inline_diagnostics: Vec::new(),
 1857            soft_wrap_mode_override,
 1858            diagnostics_max_severity,
 1859            hard_wrap: None,
 1860            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1861            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1862            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1863            project,
 1864            blink_manager: blink_manager.clone(),
 1865            show_local_selections: true,
 1866            show_scrollbars: ScrollbarAxes {
 1867                horizontal: full_mode,
 1868                vertical: full_mode,
 1869            },
 1870            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1871            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1872            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1873            show_gutter: mode.is_full(),
 1874            show_line_numbers: None,
 1875            use_relative_line_numbers: None,
 1876            disable_expand_excerpt_buttons: false,
 1877            show_git_diff_gutter: None,
 1878            show_code_actions: None,
 1879            show_runnables: None,
 1880            show_breakpoints: None,
 1881            show_wrap_guides: None,
 1882            show_indent_guides,
 1883            placeholder_text: None,
 1884            highlight_order: 0,
 1885            highlighted_rows: HashMap::default(),
 1886            background_highlights: TreeMap::default(),
 1887            gutter_highlights: TreeMap::default(),
 1888            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1889            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1890            nav_history: None,
 1891            context_menu: RefCell::new(None),
 1892            context_menu_options: None,
 1893            mouse_context_menu: None,
 1894            completion_tasks: Vec::new(),
 1895            inline_blame_popover: None,
 1896            signature_help_state: SignatureHelpState::default(),
 1897            auto_signature_help: None,
 1898            find_all_references_task_sources: Vec::new(),
 1899            next_completion_id: 0,
 1900            next_inlay_id: 0,
 1901            code_action_providers,
 1902            available_code_actions: None,
 1903            code_actions_task: None,
 1904            quick_selection_highlight_task: None,
 1905            debounced_selection_highlight_task: None,
 1906            document_highlights_task: None,
 1907            linked_editing_range_task: None,
 1908            pending_rename: None,
 1909            searchable: true,
 1910            cursor_shape: EditorSettings::get_global(cx)
 1911                .cursor_shape
 1912                .unwrap_or_default(),
 1913            current_line_highlight: None,
 1914            autoindent_mode: Some(AutoindentMode::EachLine),
 1915            collapse_matches: false,
 1916            workspace: None,
 1917            input_enabled: true,
 1918            use_modal_editing: mode.is_full(),
 1919            read_only: mode.is_minimap(),
 1920            use_autoclose: true,
 1921            use_auto_surround: true,
 1922            auto_replace_emoji_shortcode: false,
 1923            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1924            leader_id: None,
 1925            remote_id: None,
 1926            hover_state: HoverState::default(),
 1927            pending_mouse_down: None,
 1928            hovered_link_state: None,
 1929            edit_prediction_provider: None,
 1930            active_inline_completion: None,
 1931            stale_inline_completion_in_menu: None,
 1932            edit_prediction_preview: EditPredictionPreview::Inactive {
 1933                released_too_fast: false,
 1934            },
 1935            inline_diagnostics_enabled: mode.is_full(),
 1936            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1937            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1938
 1939            gutter_hovered: false,
 1940            pixel_position_of_newest_cursor: None,
 1941            last_bounds: None,
 1942            last_position_map: None,
 1943            expect_bounds_change: None,
 1944            gutter_dimensions: GutterDimensions::default(),
 1945            style: None,
 1946            show_cursor_names: false,
 1947            hovered_cursors: HashMap::default(),
 1948            next_editor_action_id: EditorActionId::default(),
 1949            editor_actions: Rc::default(),
 1950            inline_completions_hidden_for_vim_mode: false,
 1951            show_inline_completions_override: None,
 1952            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1953            edit_prediction_settings: EditPredictionSettings::Disabled,
 1954            edit_prediction_indent_conflict: false,
 1955            edit_prediction_requires_modifier_in_indent_conflict: true,
 1956            custom_context_menu: None,
 1957            show_git_blame_gutter: false,
 1958            show_git_blame_inline: false,
 1959            show_selection_menu: None,
 1960            show_git_blame_inline_delay_task: None,
 1961            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1962            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1963            serialize_dirty_buffers: !mode.is_minimap()
 1964                && ProjectSettings::get_global(cx)
 1965                    .session
 1966                    .restore_unsaved_buffers,
 1967            blame: None,
 1968            blame_subscription: None,
 1969            tasks: BTreeMap::default(),
 1970
 1971            breakpoint_store,
 1972            gutter_breakpoint_indicator: (None, None),
 1973            _subscriptions: vec![
 1974                cx.observe(&buffer, Self::on_buffer_changed),
 1975                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1976                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1977                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1978                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1979                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1980                cx.observe_window_activation(window, |editor, window, cx| {
 1981                    let active = window.is_window_active();
 1982                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1983                        if active {
 1984                            blink_manager.enable(cx);
 1985                        } else {
 1986                            blink_manager.disable(cx);
 1987                        }
 1988                    });
 1989                    if active {
 1990                        editor.show_mouse_cursor();
 1991                    }
 1992                }),
 1993            ],
 1994            tasks_update_task: None,
 1995            pull_diagnostics_task: Task::ready(()),
 1996            linked_edit_ranges: Default::default(),
 1997            in_project_search: false,
 1998            previous_search_ranges: None,
 1999            breadcrumb_header: None,
 2000            focused_block: None,
 2001            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2002            addons: HashMap::default(),
 2003            registered_buffers: HashMap::default(),
 2004            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2005            selection_mark_mode: false,
 2006            toggle_fold_multiple_buffers: Task::ready(()),
 2007            serialize_selections: Task::ready(()),
 2008            serialize_folds: Task::ready(()),
 2009            text_style_refinement: None,
 2010            load_diff_task: load_uncommitted_diff,
 2011            temporary_diff_override: false,
 2012            mouse_cursor_hidden: false,
 2013            minimap: None,
 2014            hide_mouse_mode: EditorSettings::get_global(cx)
 2015                .hide_mouse
 2016                .unwrap_or_default(),
 2017            change_list: ChangeList::new(),
 2018            mode,
 2019            selection_drag_state: SelectionDragState::None,
 2020            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2021        };
 2022        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2023            editor
 2024                ._subscriptions
 2025                .push(cx.observe(breakpoints, |_, _, cx| {
 2026                    cx.notify();
 2027                }));
 2028        }
 2029        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2030        editor._subscriptions.extend(project_subscriptions);
 2031
 2032        editor._subscriptions.push(cx.subscribe_in(
 2033            &cx.entity(),
 2034            window,
 2035            |editor, _, e: &EditorEvent, window, cx| match e {
 2036                EditorEvent::ScrollPositionChanged { local, .. } => {
 2037                    if *local {
 2038                        let new_anchor = editor.scroll_manager.anchor();
 2039                        let snapshot = editor.snapshot(window, cx);
 2040                        editor.update_restoration_data(cx, move |data| {
 2041                            data.scroll_position = (
 2042                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2043                                new_anchor.offset,
 2044                            );
 2045                        });
 2046                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2047                        editor.inline_blame_popover.take();
 2048                    }
 2049                }
 2050                EditorEvent::Edited { .. } => {
 2051                    if !vim_enabled(cx) {
 2052                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2053                        let pop_state = editor
 2054                            .change_list
 2055                            .last()
 2056                            .map(|previous| {
 2057                                previous.len() == selections.len()
 2058                                    && previous.iter().enumerate().all(|(ix, p)| {
 2059                                        p.to_display_point(&map).row()
 2060                                            == selections[ix].head().row()
 2061                                    })
 2062                            })
 2063                            .unwrap_or(false);
 2064                        let new_positions = selections
 2065                            .into_iter()
 2066                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2067                            .collect();
 2068                        editor
 2069                            .change_list
 2070                            .push_to_change_list(pop_state, new_positions);
 2071                    }
 2072                }
 2073                _ => (),
 2074            },
 2075        ));
 2076
 2077        if let Some(dap_store) = editor
 2078            .project
 2079            .as_ref()
 2080            .map(|project| project.read(cx).dap_store())
 2081        {
 2082            let weak_editor = cx.weak_entity();
 2083
 2084            editor
 2085                ._subscriptions
 2086                .push(
 2087                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2088                        let session_entity = cx.entity();
 2089                        weak_editor
 2090                            .update(cx, |editor, cx| {
 2091                                editor._subscriptions.push(
 2092                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2093                                );
 2094                            })
 2095                            .ok();
 2096                    }),
 2097                );
 2098
 2099            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2100                editor
 2101                    ._subscriptions
 2102                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2103            }
 2104        }
 2105
 2106        // skip adding the initial selection to selection history
 2107        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2108        editor.end_selection(window, cx);
 2109        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2110
 2111        editor.scroll_manager.show_scrollbars(window, cx);
 2112        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2113
 2114        if full_mode {
 2115            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2116            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2117
 2118            if editor.git_blame_inline_enabled {
 2119                editor.start_git_blame_inline(false, window, cx);
 2120            }
 2121
 2122            editor.go_to_active_debug_line(window, cx);
 2123
 2124            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2125                if let Some(project) = editor.project.as_ref() {
 2126                    let handle = project.update(cx, |project, cx| {
 2127                        project.register_buffer_with_language_servers(&buffer, cx)
 2128                    });
 2129                    editor
 2130                        .registered_buffers
 2131                        .insert(buffer.read(cx).remote_id(), handle);
 2132                }
 2133            }
 2134
 2135            editor.minimap =
 2136                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2137            editor.pull_diagnostics(None, window, cx);
 2138        }
 2139
 2140        editor.report_editor_event("Editor Opened", None, cx);
 2141        editor
 2142    }
 2143
 2144    pub fn deploy_mouse_context_menu(
 2145        &mut self,
 2146        position: gpui::Point<Pixels>,
 2147        context_menu: Entity<ContextMenu>,
 2148        window: &mut Window,
 2149        cx: &mut Context<Self>,
 2150    ) {
 2151        self.mouse_context_menu = Some(MouseContextMenu::new(
 2152            self,
 2153            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2154            context_menu,
 2155            window,
 2156            cx,
 2157        ));
 2158    }
 2159
 2160    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2161        self.mouse_context_menu
 2162            .as_ref()
 2163            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2164    }
 2165
 2166    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2167        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2168    }
 2169
 2170    fn key_context_internal(
 2171        &self,
 2172        has_active_edit_prediction: bool,
 2173        window: &Window,
 2174        cx: &App,
 2175    ) -> KeyContext {
 2176        let mut key_context = KeyContext::new_with_defaults();
 2177        key_context.add("Editor");
 2178        let mode = match self.mode {
 2179            EditorMode::SingleLine { .. } => "single_line",
 2180            EditorMode::AutoHeight { .. } => "auto_height",
 2181            EditorMode::Minimap { .. } => "minimap",
 2182            EditorMode::Full { .. } => "full",
 2183        };
 2184
 2185        if EditorSettings::jupyter_enabled(cx) {
 2186            key_context.add("jupyter");
 2187        }
 2188
 2189        key_context.set("mode", mode);
 2190        if self.pending_rename.is_some() {
 2191            key_context.add("renaming");
 2192        }
 2193
 2194        match self.context_menu.borrow().as_ref() {
 2195            Some(CodeContextMenu::Completions(_)) => {
 2196                key_context.add("menu");
 2197                key_context.add("showing_completions");
 2198            }
 2199            Some(CodeContextMenu::CodeActions(_)) => {
 2200                key_context.add("menu");
 2201                key_context.add("showing_code_actions")
 2202            }
 2203            None => {}
 2204        }
 2205
 2206        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2207        if !self.focus_handle(cx).contains_focused(window, cx)
 2208            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2209        {
 2210            for addon in self.addons.values() {
 2211                addon.extend_key_context(&mut key_context, cx)
 2212            }
 2213        }
 2214
 2215        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2216            if let Some(extension) = singleton_buffer
 2217                .read(cx)
 2218                .file()
 2219                .and_then(|file| file.path().extension()?.to_str())
 2220            {
 2221                key_context.set("extension", extension.to_string());
 2222            }
 2223        } else {
 2224            key_context.add("multibuffer");
 2225        }
 2226
 2227        if has_active_edit_prediction {
 2228            if self.edit_prediction_in_conflict() {
 2229                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2230            } else {
 2231                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2232                key_context.add("copilot_suggestion");
 2233            }
 2234        }
 2235
 2236        if self.selection_mark_mode {
 2237            key_context.add("selection_mode");
 2238        }
 2239
 2240        key_context
 2241    }
 2242
 2243    fn show_mouse_cursor(&mut self) {
 2244        self.mouse_cursor_hidden = false;
 2245    }
 2246
 2247    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2248        self.mouse_cursor_hidden = match origin {
 2249            HideMouseCursorOrigin::TypingAction => {
 2250                matches!(
 2251                    self.hide_mouse_mode,
 2252                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2253                )
 2254            }
 2255            HideMouseCursorOrigin::MovementAction => {
 2256                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2257            }
 2258        };
 2259    }
 2260
 2261    pub fn edit_prediction_in_conflict(&self) -> bool {
 2262        if !self.show_edit_predictions_in_menu() {
 2263            return false;
 2264        }
 2265
 2266        let showing_completions = self
 2267            .context_menu
 2268            .borrow()
 2269            .as_ref()
 2270            .map_or(false, |context| {
 2271                matches!(context, CodeContextMenu::Completions(_))
 2272            });
 2273
 2274        showing_completions
 2275            || self.edit_prediction_requires_modifier()
 2276            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2277            // bindings to insert tab characters.
 2278            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2279    }
 2280
 2281    pub fn accept_edit_prediction_keybind(
 2282        &self,
 2283        accept_partial: bool,
 2284        window: &Window,
 2285        cx: &App,
 2286    ) -> AcceptEditPredictionBinding {
 2287        let key_context = self.key_context_internal(true, window, cx);
 2288        let in_conflict = self.edit_prediction_in_conflict();
 2289
 2290        let bindings = if accept_partial {
 2291            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2292        } else {
 2293            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2294        };
 2295
 2296        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2297        // just the first one.
 2298        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2299            !in_conflict
 2300                || binding
 2301                    .keystrokes()
 2302                    .first()
 2303                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2304        }))
 2305    }
 2306
 2307    pub fn new_file(
 2308        workspace: &mut Workspace,
 2309        _: &workspace::NewFile,
 2310        window: &mut Window,
 2311        cx: &mut Context<Workspace>,
 2312    ) {
 2313        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2314            "Failed to create buffer",
 2315            window,
 2316            cx,
 2317            |e, _, _| match e.error_code() {
 2318                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2319                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2320                e.error_tag("required").unwrap_or("the latest version")
 2321            )),
 2322                _ => None,
 2323            },
 2324        );
 2325    }
 2326
 2327    pub fn new_in_workspace(
 2328        workspace: &mut Workspace,
 2329        window: &mut Window,
 2330        cx: &mut Context<Workspace>,
 2331    ) -> Task<Result<Entity<Editor>>> {
 2332        let project = workspace.project().clone();
 2333        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2334
 2335        cx.spawn_in(window, async move |workspace, cx| {
 2336            let buffer = create.await?;
 2337            workspace.update_in(cx, |workspace, window, cx| {
 2338                let editor =
 2339                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2340                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2341                editor
 2342            })
 2343        })
 2344    }
 2345
 2346    fn new_file_vertical(
 2347        workspace: &mut Workspace,
 2348        _: &workspace::NewFileSplitVertical,
 2349        window: &mut Window,
 2350        cx: &mut Context<Workspace>,
 2351    ) {
 2352        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2353    }
 2354
 2355    fn new_file_horizontal(
 2356        workspace: &mut Workspace,
 2357        _: &workspace::NewFileSplitHorizontal,
 2358        window: &mut Window,
 2359        cx: &mut Context<Workspace>,
 2360    ) {
 2361        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2362    }
 2363
 2364    fn new_file_in_direction(
 2365        workspace: &mut Workspace,
 2366        direction: SplitDirection,
 2367        window: &mut Window,
 2368        cx: &mut Context<Workspace>,
 2369    ) {
 2370        let project = workspace.project().clone();
 2371        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2372
 2373        cx.spawn_in(window, async move |workspace, cx| {
 2374            let buffer = create.await?;
 2375            workspace.update_in(cx, move |workspace, window, cx| {
 2376                workspace.split_item(
 2377                    direction,
 2378                    Box::new(
 2379                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2380                    ),
 2381                    window,
 2382                    cx,
 2383                )
 2384            })?;
 2385            anyhow::Ok(())
 2386        })
 2387        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2388            match e.error_code() {
 2389                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2390                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2391                e.error_tag("required").unwrap_or("the latest version")
 2392            )),
 2393                _ => None,
 2394            }
 2395        });
 2396    }
 2397
 2398    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2399        self.leader_id
 2400    }
 2401
 2402    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2403        &self.buffer
 2404    }
 2405
 2406    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2407        self.workspace.as_ref()?.0.upgrade()
 2408    }
 2409
 2410    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2411        self.buffer().read(cx).title(cx)
 2412    }
 2413
 2414    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2415        let git_blame_gutter_max_author_length = self
 2416            .render_git_blame_gutter(cx)
 2417            .then(|| {
 2418                if let Some(blame) = self.blame.as_ref() {
 2419                    let max_author_length =
 2420                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2421                    Some(max_author_length)
 2422                } else {
 2423                    None
 2424                }
 2425            })
 2426            .flatten();
 2427
 2428        EditorSnapshot {
 2429            mode: self.mode.clone(),
 2430            show_gutter: self.show_gutter,
 2431            show_line_numbers: self.show_line_numbers,
 2432            show_git_diff_gutter: self.show_git_diff_gutter,
 2433            show_code_actions: self.show_code_actions,
 2434            show_runnables: self.show_runnables,
 2435            show_breakpoints: self.show_breakpoints,
 2436            git_blame_gutter_max_author_length,
 2437            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2438            scroll_anchor: self.scroll_manager.anchor(),
 2439            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2440            placeholder_text: self.placeholder_text.clone(),
 2441            is_focused: self.focus_handle.is_focused(window),
 2442            current_line_highlight: self
 2443                .current_line_highlight
 2444                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2445            gutter_hovered: self.gutter_hovered,
 2446        }
 2447    }
 2448
 2449    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2450        self.buffer.read(cx).language_at(point, cx)
 2451    }
 2452
 2453    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2454        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2455    }
 2456
 2457    pub fn active_excerpt(
 2458        &self,
 2459        cx: &App,
 2460    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2461        self.buffer
 2462            .read(cx)
 2463            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2464    }
 2465
 2466    pub fn mode(&self) -> &EditorMode {
 2467        &self.mode
 2468    }
 2469
 2470    pub fn set_mode(&mut self, mode: EditorMode) {
 2471        self.mode = mode;
 2472    }
 2473
 2474    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2475        self.collaboration_hub.as_deref()
 2476    }
 2477
 2478    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2479        self.collaboration_hub = Some(hub);
 2480    }
 2481
 2482    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2483        self.in_project_search = in_project_search;
 2484    }
 2485
 2486    pub fn set_custom_context_menu(
 2487        &mut self,
 2488        f: impl 'static
 2489        + Fn(
 2490            &mut Self,
 2491            DisplayPoint,
 2492            &mut Window,
 2493            &mut Context<Self>,
 2494        ) -> Option<Entity<ui::ContextMenu>>,
 2495    ) {
 2496        self.custom_context_menu = Some(Box::new(f))
 2497    }
 2498
 2499    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2500        self.completion_provider = provider;
 2501    }
 2502
 2503    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2504        self.semantics_provider.clone()
 2505    }
 2506
 2507    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2508        self.semantics_provider = provider;
 2509    }
 2510
 2511    pub fn set_edit_prediction_provider<T>(
 2512        &mut self,
 2513        provider: Option<Entity<T>>,
 2514        window: &mut Window,
 2515        cx: &mut Context<Self>,
 2516    ) where
 2517        T: EditPredictionProvider,
 2518    {
 2519        self.edit_prediction_provider =
 2520            provider.map(|provider| RegisteredInlineCompletionProvider {
 2521                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2522                    if this.focus_handle.is_focused(window) {
 2523                        this.update_visible_inline_completion(window, cx);
 2524                    }
 2525                }),
 2526                provider: Arc::new(provider),
 2527            });
 2528        self.update_edit_prediction_settings(cx);
 2529        self.refresh_inline_completion(false, false, window, cx);
 2530    }
 2531
 2532    pub fn placeholder_text(&self) -> Option<&str> {
 2533        self.placeholder_text.as_deref()
 2534    }
 2535
 2536    pub fn set_placeholder_text(
 2537        &mut self,
 2538        placeholder_text: impl Into<Arc<str>>,
 2539        cx: &mut Context<Self>,
 2540    ) {
 2541        let placeholder_text = Some(placeholder_text.into());
 2542        if self.placeholder_text != placeholder_text {
 2543            self.placeholder_text = placeholder_text;
 2544            cx.notify();
 2545        }
 2546    }
 2547
 2548    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2549        self.cursor_shape = cursor_shape;
 2550
 2551        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2552        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2553
 2554        cx.notify();
 2555    }
 2556
 2557    pub fn set_current_line_highlight(
 2558        &mut self,
 2559        current_line_highlight: Option<CurrentLineHighlight>,
 2560    ) {
 2561        self.current_line_highlight = current_line_highlight;
 2562    }
 2563
 2564    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2565        self.collapse_matches = collapse_matches;
 2566    }
 2567
 2568    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2569        let buffers = self.buffer.read(cx).all_buffers();
 2570        let Some(project) = self.project.as_ref() else {
 2571            return;
 2572        };
 2573        project.update(cx, |project, cx| {
 2574            for buffer in buffers {
 2575                self.registered_buffers
 2576                    .entry(buffer.read(cx).remote_id())
 2577                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2578            }
 2579        })
 2580    }
 2581
 2582    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2583        if self.collapse_matches {
 2584            return range.start..range.start;
 2585        }
 2586        range.clone()
 2587    }
 2588
 2589    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2590        if self.display_map.read(cx).clip_at_line_ends != clip {
 2591            self.display_map
 2592                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2593        }
 2594    }
 2595
 2596    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2597        self.input_enabled = input_enabled;
 2598    }
 2599
 2600    pub fn set_inline_completions_hidden_for_vim_mode(
 2601        &mut self,
 2602        hidden: bool,
 2603        window: &mut Window,
 2604        cx: &mut Context<Self>,
 2605    ) {
 2606        if hidden != self.inline_completions_hidden_for_vim_mode {
 2607            self.inline_completions_hidden_for_vim_mode = hidden;
 2608            if hidden {
 2609                self.update_visible_inline_completion(window, cx);
 2610            } else {
 2611                self.refresh_inline_completion(true, false, window, cx);
 2612            }
 2613        }
 2614    }
 2615
 2616    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2617        self.menu_inline_completions_policy = value;
 2618    }
 2619
 2620    pub fn set_autoindent(&mut self, autoindent: bool) {
 2621        if autoindent {
 2622            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2623        } else {
 2624            self.autoindent_mode = None;
 2625        }
 2626    }
 2627
 2628    pub fn read_only(&self, cx: &App) -> bool {
 2629        self.read_only || self.buffer.read(cx).read_only()
 2630    }
 2631
 2632    pub fn set_read_only(&mut self, read_only: bool) {
 2633        self.read_only = read_only;
 2634    }
 2635
 2636    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2637        self.use_autoclose = autoclose;
 2638    }
 2639
 2640    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2641        self.use_auto_surround = auto_surround;
 2642    }
 2643
 2644    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2645        self.auto_replace_emoji_shortcode = auto_replace;
 2646    }
 2647
 2648    pub fn toggle_edit_predictions(
 2649        &mut self,
 2650        _: &ToggleEditPrediction,
 2651        window: &mut Window,
 2652        cx: &mut Context<Self>,
 2653    ) {
 2654        if self.show_inline_completions_override.is_some() {
 2655            self.set_show_edit_predictions(None, window, cx);
 2656        } else {
 2657            let show_edit_predictions = !self.edit_predictions_enabled();
 2658            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2659        }
 2660    }
 2661
 2662    pub fn set_show_edit_predictions(
 2663        &mut self,
 2664        show_edit_predictions: Option<bool>,
 2665        window: &mut Window,
 2666        cx: &mut Context<Self>,
 2667    ) {
 2668        self.show_inline_completions_override = show_edit_predictions;
 2669        self.update_edit_prediction_settings(cx);
 2670
 2671        if let Some(false) = show_edit_predictions {
 2672            self.discard_inline_completion(false, cx);
 2673        } else {
 2674            self.refresh_inline_completion(false, true, window, cx);
 2675        }
 2676    }
 2677
 2678    fn inline_completions_disabled_in_scope(
 2679        &self,
 2680        buffer: &Entity<Buffer>,
 2681        buffer_position: language::Anchor,
 2682        cx: &App,
 2683    ) -> bool {
 2684        let snapshot = buffer.read(cx).snapshot();
 2685        let settings = snapshot.settings_at(buffer_position, cx);
 2686
 2687        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2688            return false;
 2689        };
 2690
 2691        scope.override_name().map_or(false, |scope_name| {
 2692            settings
 2693                .edit_predictions_disabled_in
 2694                .iter()
 2695                .any(|s| s == scope_name)
 2696        })
 2697    }
 2698
 2699    pub fn set_use_modal_editing(&mut self, to: bool) {
 2700        self.use_modal_editing = to;
 2701    }
 2702
 2703    pub fn use_modal_editing(&self) -> bool {
 2704        self.use_modal_editing
 2705    }
 2706
 2707    fn selections_did_change(
 2708        &mut self,
 2709        local: bool,
 2710        old_cursor_position: &Anchor,
 2711        should_update_completions: bool,
 2712        window: &mut Window,
 2713        cx: &mut Context<Self>,
 2714    ) {
 2715        window.invalidate_character_coordinates();
 2716
 2717        // Copy selections to primary selection buffer
 2718        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2719        if local {
 2720            let selections = self.selections.all::<usize>(cx);
 2721            let buffer_handle = self.buffer.read(cx).read(cx);
 2722
 2723            let mut text = String::new();
 2724            for (index, selection) in selections.iter().enumerate() {
 2725                let text_for_selection = buffer_handle
 2726                    .text_for_range(selection.start..selection.end)
 2727                    .collect::<String>();
 2728
 2729                text.push_str(&text_for_selection);
 2730                if index != selections.len() - 1 {
 2731                    text.push('\n');
 2732                }
 2733            }
 2734
 2735            if !text.is_empty() {
 2736                cx.write_to_primary(ClipboardItem::new_string(text));
 2737            }
 2738        }
 2739
 2740        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2741            self.buffer.update(cx, |buffer, cx| {
 2742                buffer.set_active_selections(
 2743                    &self.selections.disjoint_anchors(),
 2744                    self.selections.line_mode,
 2745                    self.cursor_shape,
 2746                    cx,
 2747                )
 2748            });
 2749        }
 2750        let display_map = self
 2751            .display_map
 2752            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2753        let buffer = &display_map.buffer_snapshot;
 2754        if self.selections.count() == 1 {
 2755            self.add_selections_state = None;
 2756        }
 2757        self.select_next_state = None;
 2758        self.select_prev_state = None;
 2759        self.select_syntax_node_history.try_clear();
 2760        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2761        self.snippet_stack
 2762            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2763        self.take_rename(false, window, cx);
 2764
 2765        let newest_selection = self.selections.newest_anchor();
 2766        let new_cursor_position = newest_selection.head();
 2767        let selection_start = newest_selection.start;
 2768
 2769        self.push_to_nav_history(
 2770            *old_cursor_position,
 2771            Some(new_cursor_position.to_point(buffer)),
 2772            false,
 2773            cx,
 2774        );
 2775
 2776        if local {
 2777            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2778                if !self.registered_buffers.contains_key(&buffer_id) {
 2779                    if let Some(project) = self.project.as_ref() {
 2780                        project.update(cx, |project, cx| {
 2781                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2782                                return;
 2783                            };
 2784                            self.registered_buffers.insert(
 2785                                buffer_id,
 2786                                project.register_buffer_with_language_servers(&buffer, cx),
 2787                            );
 2788                        })
 2789                    }
 2790                }
 2791            }
 2792
 2793            let mut context_menu = self.context_menu.borrow_mut();
 2794            let completion_menu = match context_menu.as_ref() {
 2795                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2796                Some(CodeContextMenu::CodeActions(_)) => {
 2797                    *context_menu = None;
 2798                    None
 2799                }
 2800                None => None,
 2801            };
 2802            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2803            drop(context_menu);
 2804
 2805            if should_update_completions {
 2806                if let Some(completion_position) = completion_position {
 2807                    let start_offset = selection_start.to_offset(buffer);
 2808                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2809                    let continue_showing = if position_matches {
 2810                        if self.snippet_stack.is_empty() {
 2811                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2812                        } else {
 2813                            // Snippet choices can be shown even when the cursor is in whitespace.
 2814                            // Dismissing the menu when actions like backspace
 2815                            true
 2816                        }
 2817                    } else {
 2818                        false
 2819                    };
 2820
 2821                    if continue_showing {
 2822                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2823                    } else {
 2824                        self.hide_context_menu(window, cx);
 2825                    }
 2826                }
 2827            }
 2828
 2829            hide_hover(self, cx);
 2830
 2831            if old_cursor_position.to_display_point(&display_map).row()
 2832                != new_cursor_position.to_display_point(&display_map).row()
 2833            {
 2834                self.available_code_actions.take();
 2835            }
 2836            self.refresh_code_actions(window, cx);
 2837            self.refresh_document_highlights(cx);
 2838            self.refresh_selected_text_highlights(false, window, cx);
 2839            refresh_matching_bracket_highlights(self, window, cx);
 2840            self.update_visible_inline_completion(window, cx);
 2841            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2842            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2843            self.inline_blame_popover.take();
 2844            if self.git_blame_inline_enabled {
 2845                self.start_inline_blame_timer(window, cx);
 2846            }
 2847        }
 2848
 2849        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2850        cx.emit(EditorEvent::SelectionsChanged { local });
 2851
 2852        let selections = &self.selections.disjoint;
 2853        if selections.len() == 1 {
 2854            cx.emit(SearchEvent::ActiveMatchChanged)
 2855        }
 2856        if local {
 2857            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2858                let inmemory_selections = selections
 2859                    .iter()
 2860                    .map(|s| {
 2861                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2862                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2863                    })
 2864                    .collect();
 2865                self.update_restoration_data(cx, |data| {
 2866                    data.selections = inmemory_selections;
 2867                });
 2868
 2869                if WorkspaceSettings::get(None, cx).restore_on_startup
 2870                    != RestoreOnStartupBehavior::None
 2871                {
 2872                    if let Some(workspace_id) =
 2873                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2874                    {
 2875                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2876                        let selections = selections.clone();
 2877                        let background_executor = cx.background_executor().clone();
 2878                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2879                        self.serialize_selections = cx.background_spawn(async move {
 2880                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2881                    let db_selections = selections
 2882                        .iter()
 2883                        .map(|selection| {
 2884                            (
 2885                                selection.start.to_offset(&snapshot),
 2886                                selection.end.to_offset(&snapshot),
 2887                            )
 2888                        })
 2889                        .collect();
 2890
 2891                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2892                        .await
 2893                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2894                        .log_err();
 2895                });
 2896                    }
 2897                }
 2898            }
 2899        }
 2900
 2901        cx.notify();
 2902    }
 2903
 2904    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2905        use text::ToOffset as _;
 2906        use text::ToPoint as _;
 2907
 2908        if self.mode.is_minimap()
 2909            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2910        {
 2911            return;
 2912        }
 2913
 2914        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2915            return;
 2916        };
 2917
 2918        let snapshot = singleton.read(cx).snapshot();
 2919        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2920            let display_snapshot = display_map.snapshot(cx);
 2921
 2922            display_snapshot
 2923                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2924                .map(|fold| {
 2925                    fold.range.start.text_anchor.to_point(&snapshot)
 2926                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2927                })
 2928                .collect()
 2929        });
 2930        self.update_restoration_data(cx, |data| {
 2931            data.folds = inmemory_folds;
 2932        });
 2933
 2934        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2935            return;
 2936        };
 2937        let background_executor = cx.background_executor().clone();
 2938        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2939        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2940            display_map
 2941                .snapshot(cx)
 2942                .folds_in_range(0..snapshot.len())
 2943                .map(|fold| {
 2944                    (
 2945                        fold.range.start.text_anchor.to_offset(&snapshot),
 2946                        fold.range.end.text_anchor.to_offset(&snapshot),
 2947                    )
 2948                })
 2949                .collect()
 2950        });
 2951        self.serialize_folds = cx.background_spawn(async move {
 2952            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2953            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2954                .await
 2955                .with_context(|| {
 2956                    format!(
 2957                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2958                    )
 2959                })
 2960                .log_err();
 2961        });
 2962    }
 2963
 2964    pub fn sync_selections(
 2965        &mut self,
 2966        other: Entity<Editor>,
 2967        cx: &mut Context<Self>,
 2968    ) -> gpui::Subscription {
 2969        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2970        self.selections.change_with(cx, |selections| {
 2971            selections.select_anchors(other_selections);
 2972        });
 2973
 2974        let other_subscription =
 2975            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2976                EditorEvent::SelectionsChanged { local: true } => {
 2977                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2978                    if other_selections.is_empty() {
 2979                        return;
 2980                    }
 2981                    this.selections.change_with(cx, |selections| {
 2982                        selections.select_anchors(other_selections);
 2983                    });
 2984                }
 2985                _ => {}
 2986            });
 2987
 2988        let this_subscription =
 2989            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2990                EditorEvent::SelectionsChanged { local: true } => {
 2991                    let these_selections = this.selections.disjoint.to_vec();
 2992                    if these_selections.is_empty() {
 2993                        return;
 2994                    }
 2995                    other.update(cx, |other_editor, cx| {
 2996                        other_editor.selections.change_with(cx, |selections| {
 2997                            selections.select_anchors(these_selections);
 2998                        })
 2999                    });
 3000                }
 3001                _ => {}
 3002            });
 3003
 3004        Subscription::join(other_subscription, this_subscription)
 3005    }
 3006
 3007    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3008    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3009    /// effects of selection change occur at the end of the transaction.
 3010    pub fn change_selections<R>(
 3011        &mut self,
 3012        autoscroll: Option<Autoscroll>,
 3013        window: &mut Window,
 3014        cx: &mut Context<Self>,
 3015        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3016    ) -> R {
 3017        self.change_selections_inner(true, autoscroll, window, cx, change)
 3018    }
 3019
 3020    pub(crate) fn change_selections_without_updating_completions<R>(
 3021        &mut self,
 3022        autoscroll: Option<Autoscroll>,
 3023        window: &mut Window,
 3024        cx: &mut Context<Self>,
 3025        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3026    ) -> R {
 3027        self.change_selections_inner(false, autoscroll, window, cx, change)
 3028    }
 3029
 3030    fn change_selections_inner<R>(
 3031        &mut self,
 3032        should_update_completions: bool,
 3033        autoscroll: Option<Autoscroll>,
 3034        window: &mut Window,
 3035        cx: &mut Context<Self>,
 3036        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3037    ) -> R {
 3038        if let Some(state) = &mut self.deferred_selection_effects_state {
 3039            state.autoscroll = autoscroll.or(state.autoscroll);
 3040            state.should_update_completions = should_update_completions;
 3041            let (changed, result) = self.selections.change_with(cx, change);
 3042            state.changed |= changed;
 3043            return result;
 3044        }
 3045        let mut state = DeferredSelectionEffectsState {
 3046            changed: false,
 3047            should_update_completions,
 3048            autoscroll,
 3049            old_cursor_position: self.selections.newest_anchor().head(),
 3050            history_entry: SelectionHistoryEntry {
 3051                selections: self.selections.disjoint_anchors(),
 3052                select_next_state: self.select_next_state.clone(),
 3053                select_prev_state: self.select_prev_state.clone(),
 3054                add_selections_state: self.add_selections_state.clone(),
 3055            },
 3056        };
 3057        let (changed, result) = self.selections.change_with(cx, change);
 3058        state.changed = state.changed || changed;
 3059        if self.defer_selection_effects {
 3060            self.deferred_selection_effects_state = Some(state);
 3061        } else {
 3062            self.apply_selection_effects(state, window, cx);
 3063        }
 3064        result
 3065    }
 3066
 3067    /// Defers the effects of selection change, so that the effects of multiple calls to
 3068    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3069    /// to selection history and the state of popovers based on selection position aren't
 3070    /// erroneously updated.
 3071    pub fn with_selection_effects_deferred<R>(
 3072        &mut self,
 3073        window: &mut Window,
 3074        cx: &mut Context<Self>,
 3075        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3076    ) -> R {
 3077        let already_deferred = self.defer_selection_effects;
 3078        self.defer_selection_effects = true;
 3079        let result = update(self, window, cx);
 3080        if !already_deferred {
 3081            self.defer_selection_effects = false;
 3082            if let Some(state) = self.deferred_selection_effects_state.take() {
 3083                self.apply_selection_effects(state, window, cx);
 3084            }
 3085        }
 3086        result
 3087    }
 3088
 3089    fn apply_selection_effects(
 3090        &mut self,
 3091        state: DeferredSelectionEffectsState,
 3092        window: &mut Window,
 3093        cx: &mut Context<Self>,
 3094    ) {
 3095        if state.changed {
 3096            self.selection_history.push(state.history_entry);
 3097
 3098            if let Some(autoscroll) = state.autoscroll {
 3099                self.request_autoscroll(autoscroll, cx);
 3100            }
 3101
 3102            let old_cursor_position = &state.old_cursor_position;
 3103
 3104            self.selections_did_change(
 3105                true,
 3106                &old_cursor_position,
 3107                state.should_update_completions,
 3108                window,
 3109                cx,
 3110            );
 3111
 3112            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3113                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3114            }
 3115        }
 3116    }
 3117
 3118    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3119    where
 3120        I: IntoIterator<Item = (Range<S>, T)>,
 3121        S: ToOffset,
 3122        T: Into<Arc<str>>,
 3123    {
 3124        if self.read_only(cx) {
 3125            return;
 3126        }
 3127
 3128        self.buffer
 3129            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3130    }
 3131
 3132    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3133    where
 3134        I: IntoIterator<Item = (Range<S>, T)>,
 3135        S: ToOffset,
 3136        T: Into<Arc<str>>,
 3137    {
 3138        if self.read_only(cx) {
 3139            return;
 3140        }
 3141
 3142        self.buffer.update(cx, |buffer, cx| {
 3143            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3144        });
 3145    }
 3146
 3147    pub fn edit_with_block_indent<I, S, T>(
 3148        &mut self,
 3149        edits: I,
 3150        original_indent_columns: Vec<Option<u32>>,
 3151        cx: &mut Context<Self>,
 3152    ) where
 3153        I: IntoIterator<Item = (Range<S>, T)>,
 3154        S: ToOffset,
 3155        T: Into<Arc<str>>,
 3156    {
 3157        if self.read_only(cx) {
 3158            return;
 3159        }
 3160
 3161        self.buffer.update(cx, |buffer, cx| {
 3162            buffer.edit(
 3163                edits,
 3164                Some(AutoindentMode::Block {
 3165                    original_indent_columns,
 3166                }),
 3167                cx,
 3168            )
 3169        });
 3170    }
 3171
 3172    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3173        self.hide_context_menu(window, cx);
 3174
 3175        match phase {
 3176            SelectPhase::Begin {
 3177                position,
 3178                add,
 3179                click_count,
 3180            } => self.begin_selection(position, add, click_count, window, cx),
 3181            SelectPhase::BeginColumnar {
 3182                position,
 3183                goal_column,
 3184                reset,
 3185            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3186            SelectPhase::Extend {
 3187                position,
 3188                click_count,
 3189            } => self.extend_selection(position, click_count, window, cx),
 3190            SelectPhase::Update {
 3191                position,
 3192                goal_column,
 3193                scroll_delta,
 3194            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3195            SelectPhase::End => self.end_selection(window, cx),
 3196        }
 3197    }
 3198
 3199    fn extend_selection(
 3200        &mut self,
 3201        position: DisplayPoint,
 3202        click_count: usize,
 3203        window: &mut Window,
 3204        cx: &mut Context<Self>,
 3205    ) {
 3206        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3207        let tail = self.selections.newest::<usize>(cx).tail();
 3208        self.begin_selection(position, false, click_count, window, cx);
 3209
 3210        let position = position.to_offset(&display_map, Bias::Left);
 3211        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3212
 3213        let mut pending_selection = self
 3214            .selections
 3215            .pending_anchor()
 3216            .expect("extend_selection not called with pending selection");
 3217        if position >= tail {
 3218            pending_selection.start = tail_anchor;
 3219        } else {
 3220            pending_selection.end = tail_anchor;
 3221            pending_selection.reversed = true;
 3222        }
 3223
 3224        let mut pending_mode = self.selections.pending_mode().unwrap();
 3225        match &mut pending_mode {
 3226            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3227            _ => {}
 3228        }
 3229
 3230        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3231
 3232        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3233            s.set_pending(pending_selection, pending_mode)
 3234        });
 3235    }
 3236
 3237    fn begin_selection(
 3238        &mut self,
 3239        position: DisplayPoint,
 3240        add: bool,
 3241        click_count: usize,
 3242        window: &mut Window,
 3243        cx: &mut Context<Self>,
 3244    ) {
 3245        if !self.focus_handle.is_focused(window) {
 3246            self.last_focused_descendant = None;
 3247            window.focus(&self.focus_handle);
 3248        }
 3249
 3250        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3251        let buffer = &display_map.buffer_snapshot;
 3252        let position = display_map.clip_point(position, Bias::Left);
 3253
 3254        let start;
 3255        let end;
 3256        let mode;
 3257        let mut auto_scroll;
 3258        match click_count {
 3259            1 => {
 3260                start = buffer.anchor_before(position.to_point(&display_map));
 3261                end = start;
 3262                mode = SelectMode::Character;
 3263                auto_scroll = true;
 3264            }
 3265            2 => {
 3266                let range = movement::surrounding_word(&display_map, position);
 3267                start = buffer.anchor_before(range.start.to_point(&display_map));
 3268                end = buffer.anchor_before(range.end.to_point(&display_map));
 3269                mode = SelectMode::Word(start..end);
 3270                auto_scroll = true;
 3271            }
 3272            3 => {
 3273                let position = display_map
 3274                    .clip_point(position, Bias::Left)
 3275                    .to_point(&display_map);
 3276                let line_start = display_map.prev_line_boundary(position).0;
 3277                let next_line_start = buffer.clip_point(
 3278                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3279                    Bias::Left,
 3280                );
 3281                start = buffer.anchor_before(line_start);
 3282                end = buffer.anchor_before(next_line_start);
 3283                mode = SelectMode::Line(start..end);
 3284                auto_scroll = true;
 3285            }
 3286            _ => {
 3287                start = buffer.anchor_before(0);
 3288                end = buffer.anchor_before(buffer.len());
 3289                mode = SelectMode::All;
 3290                auto_scroll = false;
 3291            }
 3292        }
 3293        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3294
 3295        let point_to_delete: Option<usize> = {
 3296            let selected_points: Vec<Selection<Point>> =
 3297                self.selections.disjoint_in_range(start..end, cx);
 3298
 3299            if !add || click_count > 1 {
 3300                None
 3301            } else if !selected_points.is_empty() {
 3302                Some(selected_points[0].id)
 3303            } else {
 3304                let clicked_point_already_selected =
 3305                    self.selections.disjoint.iter().find(|selection| {
 3306                        selection.start.to_point(buffer) == start.to_point(buffer)
 3307                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3308                    });
 3309
 3310                clicked_point_already_selected.map(|selection| selection.id)
 3311            }
 3312        };
 3313
 3314        let selections_count = self.selections.count();
 3315
 3316        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3317            if let Some(point_to_delete) = point_to_delete {
 3318                s.delete(point_to_delete);
 3319
 3320                if selections_count == 1 {
 3321                    s.set_pending_anchor_range(start..end, mode);
 3322                }
 3323            } else {
 3324                if !add {
 3325                    s.clear_disjoint();
 3326                }
 3327
 3328                s.set_pending_anchor_range(start..end, mode);
 3329            }
 3330        });
 3331    }
 3332
 3333    fn begin_columnar_selection(
 3334        &mut self,
 3335        position: DisplayPoint,
 3336        goal_column: u32,
 3337        reset: bool,
 3338        window: &mut Window,
 3339        cx: &mut Context<Self>,
 3340    ) {
 3341        if !self.focus_handle.is_focused(window) {
 3342            self.last_focused_descendant = None;
 3343            window.focus(&self.focus_handle);
 3344        }
 3345
 3346        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3347
 3348        if reset {
 3349            let pointer_position = display_map
 3350                .buffer_snapshot
 3351                .anchor_before(position.to_point(&display_map));
 3352
 3353            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3354                s.clear_disjoint();
 3355                s.set_pending_anchor_range(
 3356                    pointer_position..pointer_position,
 3357                    SelectMode::Character,
 3358                );
 3359            });
 3360            if position.column() != goal_column {
 3361                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3362            } else {
 3363                self.columnar_display_point = None;
 3364            }
 3365        }
 3366
 3367        let tail = self.selections.newest::<Point>(cx).tail();
 3368        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3369
 3370        if !reset {
 3371            self.columnar_display_point = None;
 3372            self.select_columns(
 3373                tail.to_display_point(&display_map),
 3374                position,
 3375                goal_column,
 3376                &display_map,
 3377                window,
 3378                cx,
 3379            );
 3380        }
 3381    }
 3382
 3383    fn update_selection(
 3384        &mut self,
 3385        position: DisplayPoint,
 3386        goal_column: u32,
 3387        scroll_delta: gpui::Point<f32>,
 3388        window: &mut Window,
 3389        cx: &mut Context<Self>,
 3390    ) {
 3391        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3392
 3393        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3394            let tail = self
 3395                .columnar_display_point
 3396                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3397            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3398        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3399            let buffer = self.buffer.read(cx).snapshot(cx);
 3400            let head;
 3401            let tail;
 3402            let mode = self.selections.pending_mode().unwrap();
 3403            match &mode {
 3404                SelectMode::Character => {
 3405                    head = position.to_point(&display_map);
 3406                    tail = pending.tail().to_point(&buffer);
 3407                }
 3408                SelectMode::Word(original_range) => {
 3409                    let original_display_range = original_range.start.to_display_point(&display_map)
 3410                        ..original_range.end.to_display_point(&display_map);
 3411                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3412                        ..original_display_range.end.to_point(&display_map);
 3413                    if movement::is_inside_word(&display_map, position)
 3414                        || original_display_range.contains(&position)
 3415                    {
 3416                        let word_range = movement::surrounding_word(&display_map, position);
 3417                        if word_range.start < original_display_range.start {
 3418                            head = word_range.start.to_point(&display_map);
 3419                        } else {
 3420                            head = word_range.end.to_point(&display_map);
 3421                        }
 3422                    } else {
 3423                        head = position.to_point(&display_map);
 3424                    }
 3425
 3426                    if head <= original_buffer_range.start {
 3427                        tail = original_buffer_range.end;
 3428                    } else {
 3429                        tail = original_buffer_range.start;
 3430                    }
 3431                }
 3432                SelectMode::Line(original_range) => {
 3433                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3434
 3435                    let position = display_map
 3436                        .clip_point(position, Bias::Left)
 3437                        .to_point(&display_map);
 3438                    let line_start = display_map.prev_line_boundary(position).0;
 3439                    let next_line_start = buffer.clip_point(
 3440                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3441                        Bias::Left,
 3442                    );
 3443
 3444                    if line_start < original_range.start {
 3445                        head = line_start
 3446                    } else {
 3447                        head = next_line_start
 3448                    }
 3449
 3450                    if head <= original_range.start {
 3451                        tail = original_range.end;
 3452                    } else {
 3453                        tail = original_range.start;
 3454                    }
 3455                }
 3456                SelectMode::All => {
 3457                    return;
 3458                }
 3459            };
 3460
 3461            if head < tail {
 3462                pending.start = buffer.anchor_before(head);
 3463                pending.end = buffer.anchor_before(tail);
 3464                pending.reversed = true;
 3465            } else {
 3466                pending.start = buffer.anchor_before(tail);
 3467                pending.end = buffer.anchor_before(head);
 3468                pending.reversed = false;
 3469            }
 3470
 3471            self.change_selections(None, window, cx, |s| {
 3472                s.set_pending(pending, mode);
 3473            });
 3474        } else {
 3475            log::error!("update_selection dispatched with no pending selection");
 3476            return;
 3477        }
 3478
 3479        self.apply_scroll_delta(scroll_delta, window, cx);
 3480        cx.notify();
 3481    }
 3482
 3483    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3484        self.columnar_selection_tail.take();
 3485        if self.selections.pending_anchor().is_some() {
 3486            let selections = self.selections.all::<usize>(cx);
 3487            self.change_selections(None, window, cx, |s| {
 3488                s.select(selections);
 3489                s.clear_pending();
 3490            });
 3491        }
 3492    }
 3493
 3494    fn select_columns(
 3495        &mut self,
 3496        tail: DisplayPoint,
 3497        head: DisplayPoint,
 3498        goal_column: u32,
 3499        display_map: &DisplaySnapshot,
 3500        window: &mut Window,
 3501        cx: &mut Context<Self>,
 3502    ) {
 3503        let start_row = cmp::min(tail.row(), head.row());
 3504        let end_row = cmp::max(tail.row(), head.row());
 3505        let start_column = cmp::min(tail.column(), goal_column);
 3506        let end_column = cmp::max(tail.column(), goal_column);
 3507        let reversed = start_column < tail.column();
 3508
 3509        let selection_ranges = (start_row.0..=end_row.0)
 3510            .map(DisplayRow)
 3511            .filter_map(|row| {
 3512                if !display_map.is_block_line(row) {
 3513                    let start = display_map
 3514                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3515                        .to_point(display_map);
 3516                    let end = display_map
 3517                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3518                        .to_point(display_map);
 3519                    if reversed {
 3520                        Some(end..start)
 3521                    } else {
 3522                        Some(start..end)
 3523                    }
 3524                } else {
 3525                    None
 3526                }
 3527            })
 3528            .collect::<Vec<_>>();
 3529
 3530        let mut non_empty_ranges = selection_ranges
 3531            .iter()
 3532            .filter(|selection_range| selection_range.start != selection_range.end)
 3533            .peekable();
 3534
 3535        let ranges = if non_empty_ranges.peek().is_some() {
 3536            non_empty_ranges.cloned().collect()
 3537        } else {
 3538            selection_ranges
 3539        };
 3540
 3541        self.change_selections(None, window, cx, |s| {
 3542            s.select_ranges(ranges);
 3543        });
 3544        cx.notify();
 3545    }
 3546
 3547    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3548        self.selections
 3549            .all_adjusted(cx)
 3550            .iter()
 3551            .any(|selection| !selection.is_empty())
 3552    }
 3553
 3554    pub fn has_pending_nonempty_selection(&self) -> bool {
 3555        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3556            Some(Selection { start, end, .. }) => start != end,
 3557            None => false,
 3558        };
 3559
 3560        pending_nonempty_selection
 3561            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3562    }
 3563
 3564    pub fn has_pending_selection(&self) -> bool {
 3565        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3566    }
 3567
 3568    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3569        self.selection_mark_mode = false;
 3570        self.selection_drag_state = SelectionDragState::None;
 3571
 3572        if self.clear_expanded_diff_hunks(cx) {
 3573            cx.notify();
 3574            return;
 3575        }
 3576        if self.dismiss_menus_and_popups(true, window, cx) {
 3577            return;
 3578        }
 3579
 3580        if self.mode.is_full()
 3581            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3582        {
 3583            return;
 3584        }
 3585
 3586        cx.propagate();
 3587    }
 3588
 3589    pub fn dismiss_menus_and_popups(
 3590        &mut self,
 3591        is_user_requested: bool,
 3592        window: &mut Window,
 3593        cx: &mut Context<Self>,
 3594    ) -> bool {
 3595        if self.take_rename(false, window, cx).is_some() {
 3596            return true;
 3597        }
 3598
 3599        if hide_hover(self, cx) {
 3600            return true;
 3601        }
 3602
 3603        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3604            return true;
 3605        }
 3606
 3607        if self.hide_context_menu(window, cx).is_some() {
 3608            return true;
 3609        }
 3610
 3611        if self.mouse_context_menu.take().is_some() {
 3612            return true;
 3613        }
 3614
 3615        if is_user_requested && self.discard_inline_completion(true, cx) {
 3616            return true;
 3617        }
 3618
 3619        if self.snippet_stack.pop().is_some() {
 3620            return true;
 3621        }
 3622
 3623        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3624            self.dismiss_diagnostics(cx);
 3625            return true;
 3626        }
 3627
 3628        false
 3629    }
 3630
 3631    fn linked_editing_ranges_for(
 3632        &self,
 3633        selection: Range<text::Anchor>,
 3634        cx: &App,
 3635    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3636        if self.linked_edit_ranges.is_empty() {
 3637            return None;
 3638        }
 3639        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3640            selection.end.buffer_id.and_then(|end_buffer_id| {
 3641                if selection.start.buffer_id != Some(end_buffer_id) {
 3642                    return None;
 3643                }
 3644                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3645                let snapshot = buffer.read(cx).snapshot();
 3646                self.linked_edit_ranges
 3647                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3648                    .map(|ranges| (ranges, snapshot, buffer))
 3649            })?;
 3650        use text::ToOffset as TO;
 3651        // find offset from the start of current range to current cursor position
 3652        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3653
 3654        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3655        let start_difference = start_offset - start_byte_offset;
 3656        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3657        let end_difference = end_offset - start_byte_offset;
 3658        // Current range has associated linked ranges.
 3659        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3660        for range in linked_ranges.iter() {
 3661            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3662            let end_offset = start_offset + end_difference;
 3663            let start_offset = start_offset + start_difference;
 3664            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3665                continue;
 3666            }
 3667            if self.selections.disjoint_anchor_ranges().any(|s| {
 3668                if s.start.buffer_id != selection.start.buffer_id
 3669                    || s.end.buffer_id != selection.end.buffer_id
 3670                {
 3671                    return false;
 3672                }
 3673                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3674                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3675            }) {
 3676                continue;
 3677            }
 3678            let start = buffer_snapshot.anchor_after(start_offset);
 3679            let end = buffer_snapshot.anchor_after(end_offset);
 3680            linked_edits
 3681                .entry(buffer.clone())
 3682                .or_default()
 3683                .push(start..end);
 3684        }
 3685        Some(linked_edits)
 3686    }
 3687
 3688    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3689        let text: Arc<str> = text.into();
 3690
 3691        if self.read_only(cx) {
 3692            return;
 3693        }
 3694
 3695        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3696
 3697        let selections = self.selections.all_adjusted(cx);
 3698        let mut bracket_inserted = false;
 3699        let mut edits = Vec::new();
 3700        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3701        let mut new_selections = Vec::with_capacity(selections.len());
 3702        let mut new_autoclose_regions = Vec::new();
 3703        let snapshot = self.buffer.read(cx).read(cx);
 3704        let mut clear_linked_edit_ranges = false;
 3705
 3706        for (selection, autoclose_region) in
 3707            self.selections_with_autoclose_regions(selections, &snapshot)
 3708        {
 3709            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3710                // Determine if the inserted text matches the opening or closing
 3711                // bracket of any of this language's bracket pairs.
 3712                let mut bracket_pair = None;
 3713                let mut is_bracket_pair_start = false;
 3714                let mut is_bracket_pair_end = false;
 3715                if !text.is_empty() {
 3716                    let mut bracket_pair_matching_end = None;
 3717                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3718                    //  and they are removing the character that triggered IME popup.
 3719                    for (pair, enabled) in scope.brackets() {
 3720                        if !pair.close && !pair.surround {
 3721                            continue;
 3722                        }
 3723
 3724                        if enabled && pair.start.ends_with(text.as_ref()) {
 3725                            let prefix_len = pair.start.len() - text.len();
 3726                            let preceding_text_matches_prefix = prefix_len == 0
 3727                                || (selection.start.column >= (prefix_len as u32)
 3728                                    && snapshot.contains_str_at(
 3729                                        Point::new(
 3730                                            selection.start.row,
 3731                                            selection.start.column - (prefix_len as u32),
 3732                                        ),
 3733                                        &pair.start[..prefix_len],
 3734                                    ));
 3735                            if preceding_text_matches_prefix {
 3736                                bracket_pair = Some(pair.clone());
 3737                                is_bracket_pair_start = true;
 3738                                break;
 3739                            }
 3740                        }
 3741                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3742                        {
 3743                            // take first bracket pair matching end, but don't break in case a later bracket
 3744                            // pair matches start
 3745                            bracket_pair_matching_end = Some(pair.clone());
 3746                        }
 3747                    }
 3748                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3749                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3750                        is_bracket_pair_end = true;
 3751                    }
 3752                }
 3753
 3754                if let Some(bracket_pair) = bracket_pair {
 3755                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3756                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3757                    let auto_surround =
 3758                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3759                    if selection.is_empty() {
 3760                        if is_bracket_pair_start {
 3761                            // If the inserted text is a suffix of an opening bracket and the
 3762                            // selection is preceded by the rest of the opening bracket, then
 3763                            // insert the closing bracket.
 3764                            let following_text_allows_autoclose = snapshot
 3765                                .chars_at(selection.start)
 3766                                .next()
 3767                                .map_or(true, |c| scope.should_autoclose_before(c));
 3768
 3769                            let preceding_text_allows_autoclose = selection.start.column == 0
 3770                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3771                                    true,
 3772                                    |c| {
 3773                                        bracket_pair.start != bracket_pair.end
 3774                                            || !snapshot
 3775                                                .char_classifier_at(selection.start)
 3776                                                .is_word(c)
 3777                                    },
 3778                                );
 3779
 3780                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3781                                && bracket_pair.start.len() == 1
 3782                            {
 3783                                let target = bracket_pair.start.chars().next().unwrap();
 3784                                let current_line_count = snapshot
 3785                                    .reversed_chars_at(selection.start)
 3786                                    .take_while(|&c| c != '\n')
 3787                                    .filter(|&c| c == target)
 3788                                    .count();
 3789                                current_line_count % 2 == 1
 3790                            } else {
 3791                                false
 3792                            };
 3793
 3794                            if autoclose
 3795                                && bracket_pair.close
 3796                                && following_text_allows_autoclose
 3797                                && preceding_text_allows_autoclose
 3798                                && !is_closing_quote
 3799                            {
 3800                                let anchor = snapshot.anchor_before(selection.end);
 3801                                new_selections.push((selection.map(|_| anchor), text.len()));
 3802                                new_autoclose_regions.push((
 3803                                    anchor,
 3804                                    text.len(),
 3805                                    selection.id,
 3806                                    bracket_pair.clone(),
 3807                                ));
 3808                                edits.push((
 3809                                    selection.range(),
 3810                                    format!("{}{}", text, bracket_pair.end).into(),
 3811                                ));
 3812                                bracket_inserted = true;
 3813                                continue;
 3814                            }
 3815                        }
 3816
 3817                        if let Some(region) = autoclose_region {
 3818                            // If the selection is followed by an auto-inserted closing bracket,
 3819                            // then don't insert that closing bracket again; just move the selection
 3820                            // past the closing bracket.
 3821                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3822                                && text.as_ref() == region.pair.end.as_str();
 3823                            if should_skip {
 3824                                let anchor = snapshot.anchor_after(selection.end);
 3825                                new_selections
 3826                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3827                                continue;
 3828                            }
 3829                        }
 3830
 3831                        let always_treat_brackets_as_autoclosed = snapshot
 3832                            .language_settings_at(selection.start, cx)
 3833                            .always_treat_brackets_as_autoclosed;
 3834                        if always_treat_brackets_as_autoclosed
 3835                            && is_bracket_pair_end
 3836                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3837                        {
 3838                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3839                            // and the inserted text is a closing bracket and the selection is followed
 3840                            // by the closing bracket then move the selection past the closing bracket.
 3841                            let anchor = snapshot.anchor_after(selection.end);
 3842                            new_selections.push((selection.map(|_| anchor), text.len()));
 3843                            continue;
 3844                        }
 3845                    }
 3846                    // If an opening bracket is 1 character long and is typed while
 3847                    // text is selected, then surround that text with the bracket pair.
 3848                    else if auto_surround
 3849                        && bracket_pair.surround
 3850                        && is_bracket_pair_start
 3851                        && bracket_pair.start.chars().count() == 1
 3852                    {
 3853                        edits.push((selection.start..selection.start, text.clone()));
 3854                        edits.push((
 3855                            selection.end..selection.end,
 3856                            bracket_pair.end.as_str().into(),
 3857                        ));
 3858                        bracket_inserted = true;
 3859                        new_selections.push((
 3860                            Selection {
 3861                                id: selection.id,
 3862                                start: snapshot.anchor_after(selection.start),
 3863                                end: snapshot.anchor_before(selection.end),
 3864                                reversed: selection.reversed,
 3865                                goal: selection.goal,
 3866                            },
 3867                            0,
 3868                        ));
 3869                        continue;
 3870                    }
 3871                }
 3872            }
 3873
 3874            if self.auto_replace_emoji_shortcode
 3875                && selection.is_empty()
 3876                && text.as_ref().ends_with(':')
 3877            {
 3878                if let Some(possible_emoji_short_code) =
 3879                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3880                {
 3881                    if !possible_emoji_short_code.is_empty() {
 3882                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3883                            let emoji_shortcode_start = Point::new(
 3884                                selection.start.row,
 3885                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3886                            );
 3887
 3888                            // Remove shortcode from buffer
 3889                            edits.push((
 3890                                emoji_shortcode_start..selection.start,
 3891                                "".to_string().into(),
 3892                            ));
 3893                            new_selections.push((
 3894                                Selection {
 3895                                    id: selection.id,
 3896                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3897                                    end: snapshot.anchor_before(selection.start),
 3898                                    reversed: selection.reversed,
 3899                                    goal: selection.goal,
 3900                                },
 3901                                0,
 3902                            ));
 3903
 3904                            // Insert emoji
 3905                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3906                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3907                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3908
 3909                            continue;
 3910                        }
 3911                    }
 3912                }
 3913            }
 3914
 3915            // If not handling any auto-close operation, then just replace the selected
 3916            // text with the given input and move the selection to the end of the
 3917            // newly inserted text.
 3918            let anchor = snapshot.anchor_after(selection.end);
 3919            if !self.linked_edit_ranges.is_empty() {
 3920                let start_anchor = snapshot.anchor_before(selection.start);
 3921
 3922                let is_word_char = text.chars().next().map_or(true, |char| {
 3923                    let classifier = snapshot
 3924                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3925                        .ignore_punctuation(true);
 3926                    classifier.is_word(char)
 3927                });
 3928
 3929                if is_word_char {
 3930                    if let Some(ranges) = self
 3931                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3932                    {
 3933                        for (buffer, edits) in ranges {
 3934                            linked_edits
 3935                                .entry(buffer.clone())
 3936                                .or_default()
 3937                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3938                        }
 3939                    }
 3940                } else {
 3941                    clear_linked_edit_ranges = true;
 3942                }
 3943            }
 3944
 3945            new_selections.push((selection.map(|_| anchor), 0));
 3946            edits.push((selection.start..selection.end, text.clone()));
 3947        }
 3948
 3949        drop(snapshot);
 3950
 3951        self.transact(window, cx, |this, window, cx| {
 3952            if clear_linked_edit_ranges {
 3953                this.linked_edit_ranges.clear();
 3954            }
 3955            let initial_buffer_versions =
 3956                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3957
 3958            this.buffer.update(cx, |buffer, cx| {
 3959                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3960            });
 3961            for (buffer, edits) in linked_edits {
 3962                buffer.update(cx, |buffer, cx| {
 3963                    let snapshot = buffer.snapshot();
 3964                    let edits = edits
 3965                        .into_iter()
 3966                        .map(|(range, text)| {
 3967                            use text::ToPoint as TP;
 3968                            let end_point = TP::to_point(&range.end, &snapshot);
 3969                            let start_point = TP::to_point(&range.start, &snapshot);
 3970                            (start_point..end_point, text)
 3971                        })
 3972                        .sorted_by_key(|(range, _)| range.start);
 3973                    buffer.edit(edits, None, cx);
 3974                })
 3975            }
 3976            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3977            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3978            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3979            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3980                .zip(new_selection_deltas)
 3981                .map(|(selection, delta)| Selection {
 3982                    id: selection.id,
 3983                    start: selection.start + delta,
 3984                    end: selection.end + delta,
 3985                    reversed: selection.reversed,
 3986                    goal: SelectionGoal::None,
 3987                })
 3988                .collect::<Vec<_>>();
 3989
 3990            let mut i = 0;
 3991            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3992                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3993                let start = map.buffer_snapshot.anchor_before(position);
 3994                let end = map.buffer_snapshot.anchor_after(position);
 3995                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3996                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3997                        Ordering::Less => i += 1,
 3998                        Ordering::Greater => break,
 3999                        Ordering::Equal => {
 4000                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4001                                Ordering::Less => i += 1,
 4002                                Ordering::Equal => break,
 4003                                Ordering::Greater => break,
 4004                            }
 4005                        }
 4006                    }
 4007                }
 4008                this.autoclose_regions.insert(
 4009                    i,
 4010                    AutocloseRegion {
 4011                        selection_id,
 4012                        range: start..end,
 4013                        pair,
 4014                    },
 4015                );
 4016            }
 4017
 4018            let had_active_inline_completion = this.has_active_inline_completion();
 4019            this.change_selections_without_updating_completions(
 4020                Some(Autoscroll::fit()),
 4021                window,
 4022                cx,
 4023                |s| s.select(new_selections),
 4024            );
 4025
 4026            if !bracket_inserted {
 4027                if let Some(on_type_format_task) =
 4028                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4029                {
 4030                    on_type_format_task.detach_and_log_err(cx);
 4031                }
 4032            }
 4033
 4034            let editor_settings = EditorSettings::get_global(cx);
 4035            if bracket_inserted
 4036                && (editor_settings.auto_signature_help
 4037                    || editor_settings.show_signature_help_after_edits)
 4038            {
 4039                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4040            }
 4041
 4042            let trigger_in_words =
 4043                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4044            if this.hard_wrap.is_some() {
 4045                let latest: Range<Point> = this.selections.newest(cx).range();
 4046                if latest.is_empty()
 4047                    && this
 4048                        .buffer()
 4049                        .read(cx)
 4050                        .snapshot(cx)
 4051                        .line_len(MultiBufferRow(latest.start.row))
 4052                        == latest.start.column
 4053                {
 4054                    this.rewrap_impl(
 4055                        RewrapOptions {
 4056                            override_language_settings: true,
 4057                            preserve_existing_whitespace: true,
 4058                        },
 4059                        cx,
 4060                    )
 4061                }
 4062            }
 4063            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4064            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4065            this.refresh_inline_completion(true, false, window, cx);
 4066            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4067        });
 4068    }
 4069
 4070    fn find_possible_emoji_shortcode_at_position(
 4071        snapshot: &MultiBufferSnapshot,
 4072        position: Point,
 4073    ) -> Option<String> {
 4074        let mut chars = Vec::new();
 4075        let mut found_colon = false;
 4076        for char in snapshot.reversed_chars_at(position).take(100) {
 4077            // Found a possible emoji shortcode in the middle of the buffer
 4078            if found_colon {
 4079                if char.is_whitespace() {
 4080                    chars.reverse();
 4081                    return Some(chars.iter().collect());
 4082                }
 4083                // If the previous character is not a whitespace, we are in the middle of a word
 4084                // and we only want to complete the shortcode if the word is made up of other emojis
 4085                let mut containing_word = String::new();
 4086                for ch in snapshot
 4087                    .reversed_chars_at(position)
 4088                    .skip(chars.len() + 1)
 4089                    .take(100)
 4090                {
 4091                    if ch.is_whitespace() {
 4092                        break;
 4093                    }
 4094                    containing_word.push(ch);
 4095                }
 4096                let containing_word = containing_word.chars().rev().collect::<String>();
 4097                if util::word_consists_of_emojis(containing_word.as_str()) {
 4098                    chars.reverse();
 4099                    return Some(chars.iter().collect());
 4100                }
 4101            }
 4102
 4103            if char.is_whitespace() || !char.is_ascii() {
 4104                return None;
 4105            }
 4106            if char == ':' {
 4107                found_colon = true;
 4108            } else {
 4109                chars.push(char);
 4110            }
 4111        }
 4112        // Found a possible emoji shortcode at the beginning of the buffer
 4113        chars.reverse();
 4114        Some(chars.iter().collect())
 4115    }
 4116
 4117    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4118        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4119        self.transact(window, cx, |this, window, cx| {
 4120            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4121                let selections = this.selections.all::<usize>(cx);
 4122                let multi_buffer = this.buffer.read(cx);
 4123                let buffer = multi_buffer.snapshot(cx);
 4124                selections
 4125                    .iter()
 4126                    .map(|selection| {
 4127                        let start_point = selection.start.to_point(&buffer);
 4128                        let mut existing_indent =
 4129                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4130                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4131                        let start = selection.start;
 4132                        let end = selection.end;
 4133                        let selection_is_empty = start == end;
 4134                        let language_scope = buffer.language_scope_at(start);
 4135                        let (
 4136                            comment_delimiter,
 4137                            doc_delimiter,
 4138                            insert_extra_newline,
 4139                            indent_on_newline,
 4140                            indent_on_extra_newline,
 4141                        ) = if let Some(language) = &language_scope {
 4142                            let mut insert_extra_newline =
 4143                                insert_extra_newline_brackets(&buffer, start..end, language)
 4144                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4145
 4146                            // Comment extension on newline is allowed only for cursor selections
 4147                            let comment_delimiter = maybe!({
 4148                                if !selection_is_empty {
 4149                                    return None;
 4150                                }
 4151
 4152                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4153                                    return None;
 4154                                }
 4155
 4156                                let delimiters = language.line_comment_prefixes();
 4157                                let max_len_of_delimiter =
 4158                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4159                                let (snapshot, range) =
 4160                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4161
 4162                                let num_of_whitespaces = snapshot
 4163                                    .chars_for_range(range.clone())
 4164                                    .take_while(|c| c.is_whitespace())
 4165                                    .count();
 4166                                let comment_candidate = snapshot
 4167                                    .chars_for_range(range)
 4168                                    .skip(num_of_whitespaces)
 4169                                    .take(max_len_of_delimiter)
 4170                                    .collect::<String>();
 4171                                let (delimiter, trimmed_len) = delimiters
 4172                                    .iter()
 4173                                    .filter_map(|delimiter| {
 4174                                        let prefix = delimiter.trim_end();
 4175                                        if comment_candidate.starts_with(prefix) {
 4176                                            Some((delimiter, prefix.len()))
 4177                                        } else {
 4178                                            None
 4179                                        }
 4180                                    })
 4181                                    .max_by_key(|(_, len)| *len)?;
 4182
 4183                                let cursor_is_placed_after_comment_marker =
 4184                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4185                                if cursor_is_placed_after_comment_marker {
 4186                                    Some(delimiter.clone())
 4187                                } else {
 4188                                    None
 4189                                }
 4190                            });
 4191
 4192                            let mut indent_on_newline = IndentSize::spaces(0);
 4193                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4194
 4195                            let doc_delimiter = maybe!({
 4196                                if !selection_is_empty {
 4197                                    return None;
 4198                                }
 4199
 4200                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4201                                    return None;
 4202                                }
 4203
 4204                                let DocumentationConfig {
 4205                                    start: start_tag,
 4206                                    end: end_tag,
 4207                                    prefix: delimiter,
 4208                                    tab_size: len,
 4209                                } = language.documentation()?;
 4210
 4211                                let is_within_block_comment = buffer
 4212                                    .language_scope_at(start_point)
 4213                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4214                                if !is_within_block_comment {
 4215                                    return None;
 4216                                }
 4217
 4218                                let (snapshot, range) =
 4219                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4220
 4221                                let num_of_whitespaces = snapshot
 4222                                    .chars_for_range(range.clone())
 4223                                    .take_while(|c| c.is_whitespace())
 4224                                    .count();
 4225
 4226                                // 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.
 4227                                let column = start_point.column;
 4228                                let cursor_is_after_start_tag = {
 4229                                    let start_tag_len = start_tag.len();
 4230                                    let start_tag_line = snapshot
 4231                                        .chars_for_range(range.clone())
 4232                                        .skip(num_of_whitespaces)
 4233                                        .take(start_tag_len)
 4234                                        .collect::<String>();
 4235                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4236                                        num_of_whitespaces + start_tag_len <= column as usize
 4237                                    } else {
 4238                                        false
 4239                                    }
 4240                                };
 4241
 4242                                let cursor_is_after_delimiter = {
 4243                                    let delimiter_trim = delimiter.trim_end();
 4244                                    let delimiter_line = snapshot
 4245                                        .chars_for_range(range.clone())
 4246                                        .skip(num_of_whitespaces)
 4247                                        .take(delimiter_trim.len())
 4248                                        .collect::<String>();
 4249                                    if delimiter_line.starts_with(delimiter_trim) {
 4250                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4251                                    } else {
 4252                                        false
 4253                                    }
 4254                                };
 4255
 4256                                let cursor_is_before_end_tag_if_exists = {
 4257                                    let mut char_position = 0u32;
 4258                                    let mut end_tag_offset = None;
 4259
 4260                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4261                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4262                                            let chars_before_match =
 4263                                                chunk[..byte_pos].chars().count() as u32;
 4264                                            end_tag_offset =
 4265                                                Some(char_position + chars_before_match);
 4266                                            break 'outer;
 4267                                        }
 4268                                        char_position += chunk.chars().count() as u32;
 4269                                    }
 4270
 4271                                    if let Some(end_tag_offset) = end_tag_offset {
 4272                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4273                                        if cursor_is_after_start_tag {
 4274                                            if cursor_is_before_end_tag {
 4275                                                insert_extra_newline = true;
 4276                                            }
 4277                                            let cursor_is_at_start_of_end_tag =
 4278                                                column == end_tag_offset;
 4279                                            if cursor_is_at_start_of_end_tag {
 4280                                                indent_on_extra_newline.len = (*len).into();
 4281                                            }
 4282                                        }
 4283                                        cursor_is_before_end_tag
 4284                                    } else {
 4285                                        true
 4286                                    }
 4287                                };
 4288
 4289                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4290                                    && cursor_is_before_end_tag_if_exists
 4291                                {
 4292                                    if cursor_is_after_start_tag {
 4293                                        indent_on_newline.len = (*len).into();
 4294                                    }
 4295                                    Some(delimiter.clone())
 4296                                } else {
 4297                                    None
 4298                                }
 4299                            });
 4300
 4301                            (
 4302                                comment_delimiter,
 4303                                doc_delimiter,
 4304                                insert_extra_newline,
 4305                                indent_on_newline,
 4306                                indent_on_extra_newline,
 4307                            )
 4308                        } else {
 4309                            (
 4310                                None,
 4311                                None,
 4312                                false,
 4313                                IndentSize::default(),
 4314                                IndentSize::default(),
 4315                            )
 4316                        };
 4317
 4318                        let prevent_auto_indent = doc_delimiter.is_some();
 4319                        let delimiter = comment_delimiter.or(doc_delimiter);
 4320
 4321                        let capacity_for_delimiter =
 4322                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4323                        let mut new_text = String::with_capacity(
 4324                            1 + capacity_for_delimiter
 4325                                + existing_indent.len as usize
 4326                                + indent_on_newline.len as usize
 4327                                + indent_on_extra_newline.len as usize,
 4328                        );
 4329                        new_text.push('\n');
 4330                        new_text.extend(existing_indent.chars());
 4331                        new_text.extend(indent_on_newline.chars());
 4332
 4333                        if let Some(delimiter) = &delimiter {
 4334                            new_text.push_str(delimiter);
 4335                        }
 4336
 4337                        if insert_extra_newline {
 4338                            new_text.push('\n');
 4339                            new_text.extend(existing_indent.chars());
 4340                            new_text.extend(indent_on_extra_newline.chars());
 4341                        }
 4342
 4343                        let anchor = buffer.anchor_after(end);
 4344                        let new_selection = selection.map(|_| anchor);
 4345                        (
 4346                            ((start..end, new_text), prevent_auto_indent),
 4347                            (insert_extra_newline, new_selection),
 4348                        )
 4349                    })
 4350                    .unzip()
 4351            };
 4352
 4353            let mut auto_indent_edits = Vec::new();
 4354            let mut edits = Vec::new();
 4355            for (edit, prevent_auto_indent) in edits_with_flags {
 4356                if prevent_auto_indent {
 4357                    edits.push(edit);
 4358                } else {
 4359                    auto_indent_edits.push(edit);
 4360                }
 4361            }
 4362            if !edits.is_empty() {
 4363                this.edit(edits, cx);
 4364            }
 4365            if !auto_indent_edits.is_empty() {
 4366                this.edit_with_autoindent(auto_indent_edits, cx);
 4367            }
 4368
 4369            let buffer = this.buffer.read(cx).snapshot(cx);
 4370            let new_selections = selection_info
 4371                .into_iter()
 4372                .map(|(extra_newline_inserted, new_selection)| {
 4373                    let mut cursor = new_selection.end.to_point(&buffer);
 4374                    if extra_newline_inserted {
 4375                        cursor.row -= 1;
 4376                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4377                    }
 4378                    new_selection.map(|_| cursor)
 4379                })
 4380                .collect();
 4381
 4382            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4383                s.select(new_selections)
 4384            });
 4385            this.refresh_inline_completion(true, false, window, cx);
 4386        });
 4387    }
 4388
 4389    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4390        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4391
 4392        let buffer = self.buffer.read(cx);
 4393        let snapshot = buffer.snapshot(cx);
 4394
 4395        let mut edits = Vec::new();
 4396        let mut rows = Vec::new();
 4397
 4398        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4399            let cursor = selection.head();
 4400            let row = cursor.row;
 4401
 4402            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4403
 4404            let newline = "\n".to_string();
 4405            edits.push((start_of_line..start_of_line, newline));
 4406
 4407            rows.push(row + rows_inserted as u32);
 4408        }
 4409
 4410        self.transact(window, cx, |editor, window, cx| {
 4411            editor.edit(edits, cx);
 4412
 4413            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4414                let mut index = 0;
 4415                s.move_cursors_with(|map, _, _| {
 4416                    let row = rows[index];
 4417                    index += 1;
 4418
 4419                    let point = Point::new(row, 0);
 4420                    let boundary = map.next_line_boundary(point).1;
 4421                    let clipped = map.clip_point(boundary, Bias::Left);
 4422
 4423                    (clipped, SelectionGoal::None)
 4424                });
 4425            });
 4426
 4427            let mut indent_edits = Vec::new();
 4428            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4429            for row in rows {
 4430                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4431                for (row, indent) in indents {
 4432                    if indent.len == 0 {
 4433                        continue;
 4434                    }
 4435
 4436                    let text = match indent.kind {
 4437                        IndentKind::Space => " ".repeat(indent.len as usize),
 4438                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4439                    };
 4440                    let point = Point::new(row.0, 0);
 4441                    indent_edits.push((point..point, text));
 4442                }
 4443            }
 4444            editor.edit(indent_edits, cx);
 4445        });
 4446    }
 4447
 4448    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4449        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4450
 4451        let buffer = self.buffer.read(cx);
 4452        let snapshot = buffer.snapshot(cx);
 4453
 4454        let mut edits = Vec::new();
 4455        let mut rows = Vec::new();
 4456        let mut rows_inserted = 0;
 4457
 4458        for selection in self.selections.all_adjusted(cx) {
 4459            let cursor = selection.head();
 4460            let row = cursor.row;
 4461
 4462            let point = Point::new(row + 1, 0);
 4463            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4464
 4465            let newline = "\n".to_string();
 4466            edits.push((start_of_line..start_of_line, newline));
 4467
 4468            rows_inserted += 1;
 4469            rows.push(row + rows_inserted);
 4470        }
 4471
 4472        self.transact(window, cx, |editor, window, cx| {
 4473            editor.edit(edits, cx);
 4474
 4475            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4476                let mut index = 0;
 4477                s.move_cursors_with(|map, _, _| {
 4478                    let row = rows[index];
 4479                    index += 1;
 4480
 4481                    let point = Point::new(row, 0);
 4482                    let boundary = map.next_line_boundary(point).1;
 4483                    let clipped = map.clip_point(boundary, Bias::Left);
 4484
 4485                    (clipped, SelectionGoal::None)
 4486                });
 4487            });
 4488
 4489            let mut indent_edits = Vec::new();
 4490            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4491            for row in rows {
 4492                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4493                for (row, indent) in indents {
 4494                    if indent.len == 0 {
 4495                        continue;
 4496                    }
 4497
 4498                    let text = match indent.kind {
 4499                        IndentKind::Space => " ".repeat(indent.len as usize),
 4500                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4501                    };
 4502                    let point = Point::new(row.0, 0);
 4503                    indent_edits.push((point..point, text));
 4504                }
 4505            }
 4506            editor.edit(indent_edits, cx);
 4507        });
 4508    }
 4509
 4510    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4511        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4512            original_indent_columns: Vec::new(),
 4513        });
 4514        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4515    }
 4516
 4517    fn insert_with_autoindent_mode(
 4518        &mut self,
 4519        text: &str,
 4520        autoindent_mode: Option<AutoindentMode>,
 4521        window: &mut Window,
 4522        cx: &mut Context<Self>,
 4523    ) {
 4524        if self.read_only(cx) {
 4525            return;
 4526        }
 4527
 4528        let text: Arc<str> = text.into();
 4529        self.transact(window, cx, |this, window, cx| {
 4530            let old_selections = this.selections.all_adjusted(cx);
 4531            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4532                let anchors = {
 4533                    let snapshot = buffer.read(cx);
 4534                    old_selections
 4535                        .iter()
 4536                        .map(|s| {
 4537                            let anchor = snapshot.anchor_after(s.head());
 4538                            s.map(|_| anchor)
 4539                        })
 4540                        .collect::<Vec<_>>()
 4541                };
 4542                buffer.edit(
 4543                    old_selections
 4544                        .iter()
 4545                        .map(|s| (s.start..s.end, text.clone())),
 4546                    autoindent_mode,
 4547                    cx,
 4548                );
 4549                anchors
 4550            });
 4551
 4552            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4553                s.select_anchors(selection_anchors);
 4554            });
 4555
 4556            cx.notify();
 4557        });
 4558    }
 4559
 4560    fn trigger_completion_on_input(
 4561        &mut self,
 4562        text: &str,
 4563        trigger_in_words: bool,
 4564        window: &mut Window,
 4565        cx: &mut Context<Self>,
 4566    ) {
 4567        let completions_source = self
 4568            .context_menu
 4569            .borrow()
 4570            .as_ref()
 4571            .and_then(|menu| match menu {
 4572                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4573                CodeContextMenu::CodeActions(_) => None,
 4574            });
 4575
 4576        match completions_source {
 4577            Some(CompletionsMenuSource::Words) => {
 4578                self.show_word_completions(&ShowWordCompletions, window, cx)
 4579            }
 4580            Some(CompletionsMenuSource::Normal)
 4581            | Some(CompletionsMenuSource::SnippetChoices)
 4582            | None
 4583                if self.is_completion_trigger(
 4584                    text,
 4585                    trigger_in_words,
 4586                    completions_source.is_some(),
 4587                    cx,
 4588                ) =>
 4589            {
 4590                self.show_completions(
 4591                    &ShowCompletions {
 4592                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4593                    },
 4594                    window,
 4595                    cx,
 4596                )
 4597            }
 4598            _ => {
 4599                self.hide_context_menu(window, cx);
 4600            }
 4601        }
 4602    }
 4603
 4604    fn is_completion_trigger(
 4605        &self,
 4606        text: &str,
 4607        trigger_in_words: bool,
 4608        menu_is_open: bool,
 4609        cx: &mut Context<Self>,
 4610    ) -> bool {
 4611        let position = self.selections.newest_anchor().head();
 4612        let multibuffer = self.buffer.read(cx);
 4613        let Some(buffer) = position
 4614            .buffer_id
 4615            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4616        else {
 4617            return false;
 4618        };
 4619
 4620        if let Some(completion_provider) = &self.completion_provider {
 4621            completion_provider.is_completion_trigger(
 4622                &buffer,
 4623                position.text_anchor,
 4624                text,
 4625                trigger_in_words,
 4626                menu_is_open,
 4627                cx,
 4628            )
 4629        } else {
 4630            false
 4631        }
 4632    }
 4633
 4634    /// If any empty selections is touching the start of its innermost containing autoclose
 4635    /// region, expand it to select the brackets.
 4636    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4637        let selections = self.selections.all::<usize>(cx);
 4638        let buffer = self.buffer.read(cx).read(cx);
 4639        let new_selections = self
 4640            .selections_with_autoclose_regions(selections, &buffer)
 4641            .map(|(mut selection, region)| {
 4642                if !selection.is_empty() {
 4643                    return selection;
 4644                }
 4645
 4646                if let Some(region) = region {
 4647                    let mut range = region.range.to_offset(&buffer);
 4648                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4649                        range.start -= region.pair.start.len();
 4650                        if buffer.contains_str_at(range.start, &region.pair.start)
 4651                            && buffer.contains_str_at(range.end, &region.pair.end)
 4652                        {
 4653                            range.end += region.pair.end.len();
 4654                            selection.start = range.start;
 4655                            selection.end = range.end;
 4656
 4657                            return selection;
 4658                        }
 4659                    }
 4660                }
 4661
 4662                let always_treat_brackets_as_autoclosed = buffer
 4663                    .language_settings_at(selection.start, cx)
 4664                    .always_treat_brackets_as_autoclosed;
 4665
 4666                if !always_treat_brackets_as_autoclosed {
 4667                    return selection;
 4668                }
 4669
 4670                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4671                    for (pair, enabled) in scope.brackets() {
 4672                        if !enabled || !pair.close {
 4673                            continue;
 4674                        }
 4675
 4676                        if buffer.contains_str_at(selection.start, &pair.end) {
 4677                            let pair_start_len = pair.start.len();
 4678                            if buffer.contains_str_at(
 4679                                selection.start.saturating_sub(pair_start_len),
 4680                                &pair.start,
 4681                            ) {
 4682                                selection.start -= pair_start_len;
 4683                                selection.end += pair.end.len();
 4684
 4685                                return selection;
 4686                            }
 4687                        }
 4688                    }
 4689                }
 4690
 4691                selection
 4692            })
 4693            .collect();
 4694
 4695        drop(buffer);
 4696        self.change_selections(None, window, cx, |selections| {
 4697            selections.select(new_selections)
 4698        });
 4699    }
 4700
 4701    /// Iterate the given selections, and for each one, find the smallest surrounding
 4702    /// autoclose region. This uses the ordering of the selections and the autoclose
 4703    /// regions to avoid repeated comparisons.
 4704    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4705        &'a self,
 4706        selections: impl IntoIterator<Item = Selection<D>>,
 4707        buffer: &'a MultiBufferSnapshot,
 4708    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4709        let mut i = 0;
 4710        let mut regions = self.autoclose_regions.as_slice();
 4711        selections.into_iter().map(move |selection| {
 4712            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4713
 4714            let mut enclosing = None;
 4715            while let Some(pair_state) = regions.get(i) {
 4716                if pair_state.range.end.to_offset(buffer) < range.start {
 4717                    regions = &regions[i + 1..];
 4718                    i = 0;
 4719                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4720                    break;
 4721                } else {
 4722                    if pair_state.selection_id == selection.id {
 4723                        enclosing = Some(pair_state);
 4724                    }
 4725                    i += 1;
 4726                }
 4727            }
 4728
 4729            (selection, enclosing)
 4730        })
 4731    }
 4732
 4733    /// Remove any autoclose regions that no longer contain their selection.
 4734    fn invalidate_autoclose_regions(
 4735        &mut self,
 4736        mut selections: &[Selection<Anchor>],
 4737        buffer: &MultiBufferSnapshot,
 4738    ) {
 4739        self.autoclose_regions.retain(|state| {
 4740            let mut i = 0;
 4741            while let Some(selection) = selections.get(i) {
 4742                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4743                    selections = &selections[1..];
 4744                    continue;
 4745                }
 4746                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4747                    break;
 4748                }
 4749                if selection.id == state.selection_id {
 4750                    return true;
 4751                } else {
 4752                    i += 1;
 4753                }
 4754            }
 4755            false
 4756        });
 4757    }
 4758
 4759    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4760        let offset = position.to_offset(buffer);
 4761        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4762        if offset > word_range.start && kind == Some(CharKind::Word) {
 4763            Some(
 4764                buffer
 4765                    .text_for_range(word_range.start..offset)
 4766                    .collect::<String>(),
 4767            )
 4768        } else {
 4769            None
 4770        }
 4771    }
 4772
 4773    pub fn toggle_inline_values(
 4774        &mut self,
 4775        _: &ToggleInlineValues,
 4776        _: &mut Window,
 4777        cx: &mut Context<Self>,
 4778    ) {
 4779        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4780
 4781        self.refresh_inline_values(cx);
 4782    }
 4783
 4784    pub fn toggle_inlay_hints(
 4785        &mut self,
 4786        _: &ToggleInlayHints,
 4787        _: &mut Window,
 4788        cx: &mut Context<Self>,
 4789    ) {
 4790        self.refresh_inlay_hints(
 4791            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4792            cx,
 4793        );
 4794    }
 4795
 4796    pub fn inlay_hints_enabled(&self) -> bool {
 4797        self.inlay_hint_cache.enabled
 4798    }
 4799
 4800    pub fn inline_values_enabled(&self) -> bool {
 4801        self.inline_value_cache.enabled
 4802    }
 4803
 4804    #[cfg(any(test, feature = "test-support"))]
 4805    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4806        self.display_map
 4807            .read(cx)
 4808            .current_inlays()
 4809            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4810            .cloned()
 4811            .collect()
 4812    }
 4813
 4814    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4815        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4816            return;
 4817        }
 4818
 4819        let reason_description = reason.description();
 4820        let ignore_debounce = matches!(
 4821            reason,
 4822            InlayHintRefreshReason::SettingsChange(_)
 4823                | InlayHintRefreshReason::Toggle(_)
 4824                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4825                | InlayHintRefreshReason::ModifiersChanged(_)
 4826        );
 4827        let (invalidate_cache, required_languages) = match reason {
 4828            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4829                match self.inlay_hint_cache.modifiers_override(enabled) {
 4830                    Some(enabled) => {
 4831                        if enabled {
 4832                            (InvalidationStrategy::RefreshRequested, None)
 4833                        } else {
 4834                            self.splice_inlays(
 4835                                &self
 4836                                    .visible_inlay_hints(cx)
 4837                                    .iter()
 4838                                    .map(|inlay| inlay.id)
 4839                                    .collect::<Vec<InlayId>>(),
 4840                                Vec::new(),
 4841                                cx,
 4842                            );
 4843                            return;
 4844                        }
 4845                    }
 4846                    None => return,
 4847                }
 4848            }
 4849            InlayHintRefreshReason::Toggle(enabled) => {
 4850                if self.inlay_hint_cache.toggle(enabled) {
 4851                    if enabled {
 4852                        (InvalidationStrategy::RefreshRequested, None)
 4853                    } else {
 4854                        self.splice_inlays(
 4855                            &self
 4856                                .visible_inlay_hints(cx)
 4857                                .iter()
 4858                                .map(|inlay| inlay.id)
 4859                                .collect::<Vec<InlayId>>(),
 4860                            Vec::new(),
 4861                            cx,
 4862                        );
 4863                        return;
 4864                    }
 4865                } else {
 4866                    return;
 4867                }
 4868            }
 4869            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4870                match self.inlay_hint_cache.update_settings(
 4871                    &self.buffer,
 4872                    new_settings,
 4873                    self.visible_inlay_hints(cx),
 4874                    cx,
 4875                ) {
 4876                    ControlFlow::Break(Some(InlaySplice {
 4877                        to_remove,
 4878                        to_insert,
 4879                    })) => {
 4880                        self.splice_inlays(&to_remove, to_insert, cx);
 4881                        return;
 4882                    }
 4883                    ControlFlow::Break(None) => return,
 4884                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4885                }
 4886            }
 4887            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4888                if let Some(InlaySplice {
 4889                    to_remove,
 4890                    to_insert,
 4891                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4892                {
 4893                    self.splice_inlays(&to_remove, to_insert, cx);
 4894                }
 4895                self.display_map.update(cx, |display_map, _| {
 4896                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4897                });
 4898                return;
 4899            }
 4900            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4901            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4902                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4903            }
 4904            InlayHintRefreshReason::RefreshRequested => {
 4905                (InvalidationStrategy::RefreshRequested, None)
 4906            }
 4907        };
 4908
 4909        if let Some(InlaySplice {
 4910            to_remove,
 4911            to_insert,
 4912        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4913            reason_description,
 4914            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4915            invalidate_cache,
 4916            ignore_debounce,
 4917            cx,
 4918        ) {
 4919            self.splice_inlays(&to_remove, to_insert, cx);
 4920        }
 4921    }
 4922
 4923    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4924        self.display_map
 4925            .read(cx)
 4926            .current_inlays()
 4927            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4928            .cloned()
 4929            .collect()
 4930    }
 4931
 4932    pub fn excerpts_for_inlay_hints_query(
 4933        &self,
 4934        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4935        cx: &mut Context<Editor>,
 4936    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4937        let Some(project) = self.project.as_ref() else {
 4938            return HashMap::default();
 4939        };
 4940        let project = project.read(cx);
 4941        let multi_buffer = self.buffer().read(cx);
 4942        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4943        let multi_buffer_visible_start = self
 4944            .scroll_manager
 4945            .anchor()
 4946            .anchor
 4947            .to_point(&multi_buffer_snapshot);
 4948        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4949            multi_buffer_visible_start
 4950                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4951            Bias::Left,
 4952        );
 4953        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4954        multi_buffer_snapshot
 4955            .range_to_buffer_ranges(multi_buffer_visible_range)
 4956            .into_iter()
 4957            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4958            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4959                let buffer_file = project::File::from_dyn(buffer.file())?;
 4960                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4961                let worktree_entry = buffer_worktree
 4962                    .read(cx)
 4963                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4964                if worktree_entry.is_ignored {
 4965                    return None;
 4966                }
 4967
 4968                let language = buffer.language()?;
 4969                if let Some(restrict_to_languages) = restrict_to_languages {
 4970                    if !restrict_to_languages.contains(language) {
 4971                        return None;
 4972                    }
 4973                }
 4974                Some((
 4975                    excerpt_id,
 4976                    (
 4977                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4978                        buffer.version().clone(),
 4979                        excerpt_visible_range,
 4980                    ),
 4981                ))
 4982            })
 4983            .collect()
 4984    }
 4985
 4986    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4987        TextLayoutDetails {
 4988            text_system: window.text_system().clone(),
 4989            editor_style: self.style.clone().unwrap(),
 4990            rem_size: window.rem_size(),
 4991            scroll_anchor: self.scroll_manager.anchor(),
 4992            visible_rows: self.visible_line_count(),
 4993            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4994        }
 4995    }
 4996
 4997    pub fn splice_inlays(
 4998        &self,
 4999        to_remove: &[InlayId],
 5000        to_insert: Vec<Inlay>,
 5001        cx: &mut Context<Self>,
 5002    ) {
 5003        self.display_map.update(cx, |display_map, cx| {
 5004            display_map.splice_inlays(to_remove, to_insert, cx)
 5005        });
 5006        cx.notify();
 5007    }
 5008
 5009    fn trigger_on_type_formatting(
 5010        &self,
 5011        input: String,
 5012        window: &mut Window,
 5013        cx: &mut Context<Self>,
 5014    ) -> Option<Task<Result<()>>> {
 5015        if input.len() != 1 {
 5016            return None;
 5017        }
 5018
 5019        let project = self.project.as_ref()?;
 5020        let position = self.selections.newest_anchor().head();
 5021        let (buffer, buffer_position) = self
 5022            .buffer
 5023            .read(cx)
 5024            .text_anchor_for_position(position, cx)?;
 5025
 5026        let settings = language_settings::language_settings(
 5027            buffer
 5028                .read(cx)
 5029                .language_at(buffer_position)
 5030                .map(|l| l.name()),
 5031            buffer.read(cx).file(),
 5032            cx,
 5033        );
 5034        if !settings.use_on_type_format {
 5035            return None;
 5036        }
 5037
 5038        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5039        // hence we do LSP request & edit on host side only — add formats to host's history.
 5040        let push_to_lsp_host_history = true;
 5041        // If this is not the host, append its history with new edits.
 5042        let push_to_client_history = project.read(cx).is_via_collab();
 5043
 5044        let on_type_formatting = project.update(cx, |project, cx| {
 5045            project.on_type_format(
 5046                buffer.clone(),
 5047                buffer_position,
 5048                input,
 5049                push_to_lsp_host_history,
 5050                cx,
 5051            )
 5052        });
 5053        Some(cx.spawn_in(window, async move |editor, cx| {
 5054            if let Some(transaction) = on_type_formatting.await? {
 5055                if push_to_client_history {
 5056                    buffer
 5057                        .update(cx, |buffer, _| {
 5058                            buffer.push_transaction(transaction, Instant::now());
 5059                            buffer.finalize_last_transaction();
 5060                        })
 5061                        .ok();
 5062                }
 5063                editor.update(cx, |editor, cx| {
 5064                    editor.refresh_document_highlights(cx);
 5065                })?;
 5066            }
 5067            Ok(())
 5068        }))
 5069    }
 5070
 5071    pub fn show_word_completions(
 5072        &mut self,
 5073        _: &ShowWordCompletions,
 5074        window: &mut Window,
 5075        cx: &mut Context<Self>,
 5076    ) {
 5077        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5078    }
 5079
 5080    pub fn show_completions(
 5081        &mut self,
 5082        options: &ShowCompletions,
 5083        window: &mut Window,
 5084        cx: &mut Context<Self>,
 5085    ) {
 5086        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5087    }
 5088
 5089    fn open_or_update_completions_menu(
 5090        &mut self,
 5091        requested_source: Option<CompletionsMenuSource>,
 5092        trigger: Option<&str>,
 5093        window: &mut Window,
 5094        cx: &mut Context<Self>,
 5095    ) {
 5096        if self.pending_rename.is_some() {
 5097            return;
 5098        }
 5099
 5100        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5101
 5102        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5103        // inserted and selected. To handle that case, the start of the selection is used so that
 5104        // the menu starts with all choices.
 5105        let position = self
 5106            .selections
 5107            .newest_anchor()
 5108            .start
 5109            .bias_right(&multibuffer_snapshot);
 5110        if position.diff_base_anchor.is_some() {
 5111            return;
 5112        }
 5113        let (buffer, buffer_position) =
 5114            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5115                output
 5116            } else {
 5117                return;
 5118            };
 5119        let buffer_snapshot = buffer.read(cx).snapshot();
 5120
 5121        let query: Option<Arc<String>> =
 5122            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5123
 5124        drop(multibuffer_snapshot);
 5125
 5126        let provider = match requested_source {
 5127            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5128            Some(CompletionsMenuSource::Words) => None,
 5129            Some(CompletionsMenuSource::SnippetChoices) => {
 5130                log::error!("bug: SnippetChoices requested_source is not handled");
 5131                None
 5132            }
 5133        };
 5134
 5135        let sort_completions = provider
 5136            .as_ref()
 5137            .map_or(false, |provider| provider.sort_completions());
 5138
 5139        let filter_completions = provider
 5140            .as_ref()
 5141            .map_or(true, |provider| provider.filter_completions());
 5142
 5143        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5144            if filter_completions {
 5145                menu.filter(query.clone(), provider.clone(), window, cx);
 5146            }
 5147            // When `is_incomplete` is false, no need to re-query completions when the current query
 5148            // is a suffix of the initial query.
 5149            if !menu.is_incomplete {
 5150                // If the new query is a suffix of the old query (typing more characters) and
 5151                // the previous result was complete, the existing completions can be filtered.
 5152                //
 5153                // Note that this is always true for snippet completions.
 5154                let query_matches = match (&menu.initial_query, &query) {
 5155                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5156                    (None, _) => true,
 5157                    _ => false,
 5158                };
 5159                if query_matches {
 5160                    let position_matches = if menu.initial_position == position {
 5161                        true
 5162                    } else {
 5163                        let snapshot = self.buffer.read(cx).read(cx);
 5164                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5165                    };
 5166                    if position_matches {
 5167                        return;
 5168                    }
 5169                }
 5170            }
 5171        };
 5172
 5173        let trigger_kind = match trigger {
 5174            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5175                CompletionTriggerKind::TRIGGER_CHARACTER
 5176            }
 5177            _ => CompletionTriggerKind::INVOKED,
 5178        };
 5179        let completion_context = CompletionContext {
 5180            trigger_character: trigger.and_then(|trigger| {
 5181                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5182                    Some(String::from(trigger))
 5183                } else {
 5184                    None
 5185                }
 5186            }),
 5187            trigger_kind,
 5188        };
 5189
 5190        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5191            buffer_snapshot.surrounding_word(buffer_position)
 5192        {
 5193            let word_to_exclude = buffer_snapshot
 5194                .text_for_range(word_range.clone())
 5195                .collect::<String>();
 5196            (
 5197                buffer_snapshot.anchor_before(word_range.start)
 5198                    ..buffer_snapshot.anchor_after(buffer_position),
 5199                Some(word_to_exclude),
 5200            )
 5201        } else {
 5202            (buffer_position..buffer_position, None)
 5203        };
 5204
 5205        let language = buffer_snapshot
 5206            .language_at(buffer_position)
 5207            .map(|language| language.name());
 5208
 5209        let completion_settings =
 5210            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5211
 5212        let show_completion_documentation = buffer_snapshot
 5213            .settings_at(buffer_position, cx)
 5214            .show_completion_documentation;
 5215
 5216        // The document can be large, so stay in reasonable bounds when searching for words,
 5217        // otherwise completion pop-up might be slow to appear.
 5218        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5219        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5220        let min_word_search = buffer_snapshot.clip_point(
 5221            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5222            Bias::Left,
 5223        );
 5224        let max_word_search = buffer_snapshot.clip_point(
 5225            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5226            Bias::Right,
 5227        );
 5228        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5229            ..buffer_snapshot.point_to_offset(max_word_search);
 5230
 5231        let skip_digits = query
 5232            .as_ref()
 5233            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5234
 5235        let (mut words, provider_responses) = match &provider {
 5236            Some(provider) => {
 5237                let provider_responses = provider.completions(
 5238                    position.excerpt_id,
 5239                    &buffer,
 5240                    buffer_position,
 5241                    completion_context,
 5242                    window,
 5243                    cx,
 5244                );
 5245
 5246                let words = match completion_settings.words {
 5247                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5248                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5249                        .background_spawn(async move {
 5250                            buffer_snapshot.words_in_range(WordsQuery {
 5251                                fuzzy_contents: None,
 5252                                range: word_search_range,
 5253                                skip_digits,
 5254                            })
 5255                        }),
 5256                };
 5257
 5258                (words, provider_responses)
 5259            }
 5260            None => (
 5261                cx.background_spawn(async move {
 5262                    buffer_snapshot.words_in_range(WordsQuery {
 5263                        fuzzy_contents: None,
 5264                        range: word_search_range,
 5265                        skip_digits,
 5266                    })
 5267                }),
 5268                Task::ready(Ok(Vec::new())),
 5269            ),
 5270        };
 5271
 5272        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5273
 5274        let id = post_inc(&mut self.next_completion_id);
 5275        let task = cx.spawn_in(window, async move |editor, cx| {
 5276            let Ok(()) = editor.update(cx, |this, _| {
 5277                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5278            }) else {
 5279                return;
 5280            };
 5281
 5282            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5283            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5284            let mut completions = Vec::new();
 5285            let mut is_incomplete = false;
 5286            if let Some(provider_responses) = provider_responses.await.log_err() {
 5287                if !provider_responses.is_empty() {
 5288                    for response in provider_responses {
 5289                        completions.extend(response.completions);
 5290                        is_incomplete = is_incomplete || response.is_incomplete;
 5291                    }
 5292                    if completion_settings.words == WordsCompletionMode::Fallback {
 5293                        words = Task::ready(BTreeMap::default());
 5294                    }
 5295                }
 5296            }
 5297
 5298            let mut words = words.await;
 5299            if let Some(word_to_exclude) = &word_to_exclude {
 5300                words.remove(word_to_exclude);
 5301            }
 5302            for lsp_completion in &completions {
 5303                words.remove(&lsp_completion.new_text);
 5304            }
 5305            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5306                replace_range: word_replace_range.clone(),
 5307                new_text: word.clone(),
 5308                label: CodeLabel::plain(word, None),
 5309                icon_path: None,
 5310                documentation: None,
 5311                source: CompletionSource::BufferWord {
 5312                    word_range,
 5313                    resolved: false,
 5314                },
 5315                insert_text_mode: Some(InsertTextMode::AS_IS),
 5316                confirm: None,
 5317            }));
 5318
 5319            let menu = if completions.is_empty() {
 5320                None
 5321            } else {
 5322                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5323                    let languages = editor
 5324                        .workspace
 5325                        .as_ref()
 5326                        .and_then(|(workspace, _)| workspace.upgrade())
 5327                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5328                    let menu = CompletionsMenu::new(
 5329                        id,
 5330                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5331                        sort_completions,
 5332                        show_completion_documentation,
 5333                        position,
 5334                        query.clone(),
 5335                        is_incomplete,
 5336                        buffer.clone(),
 5337                        completions.into(),
 5338                        snippet_sort_order,
 5339                        languages,
 5340                        language,
 5341                        cx,
 5342                    );
 5343
 5344                    let query = if filter_completions { query } else { None };
 5345                    let matches_task = if let Some(query) = query {
 5346                        menu.do_async_filtering(query, cx)
 5347                    } else {
 5348                        Task::ready(menu.unfiltered_matches())
 5349                    };
 5350                    (menu, matches_task)
 5351                }) else {
 5352                    return;
 5353                };
 5354
 5355                let matches = matches_task.await;
 5356
 5357                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5358                    // Newer menu already set, so exit.
 5359                    match editor.context_menu.borrow().as_ref() {
 5360                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5361                            if prev_menu.id > id {
 5362                                return;
 5363                            }
 5364                        }
 5365                        _ => {}
 5366                    };
 5367
 5368                    // Only valid to take prev_menu because it the new menu is immediately set
 5369                    // below, or the menu is hidden.
 5370                    match editor.context_menu.borrow_mut().take() {
 5371                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5372                            let position_matches =
 5373                                if prev_menu.initial_position == menu.initial_position {
 5374                                    true
 5375                                } else {
 5376                                    let snapshot = editor.buffer.read(cx).read(cx);
 5377                                    prev_menu.initial_position.to_offset(&snapshot)
 5378                                        == menu.initial_position.to_offset(&snapshot)
 5379                                };
 5380                            if position_matches {
 5381                                // Preserve markdown cache before `set_filter_results` because it will
 5382                                // try to populate the documentation cache.
 5383                                menu.preserve_markdown_cache(prev_menu);
 5384                            }
 5385                        }
 5386                        _ => {}
 5387                    };
 5388
 5389                    menu.set_filter_results(matches, provider, window, cx);
 5390                }) else {
 5391                    return;
 5392                };
 5393
 5394                menu.visible().then_some(menu)
 5395            };
 5396
 5397            editor
 5398                .update_in(cx, |editor, window, cx| {
 5399                    if editor.focus_handle.is_focused(window) {
 5400                        if let Some(menu) = menu {
 5401                            *editor.context_menu.borrow_mut() =
 5402                                Some(CodeContextMenu::Completions(menu));
 5403
 5404                            crate::hover_popover::hide_hover(editor, cx);
 5405                            if editor.show_edit_predictions_in_menu() {
 5406                                editor.update_visible_inline_completion(window, cx);
 5407                            } else {
 5408                                editor.discard_inline_completion(false, cx);
 5409                            }
 5410
 5411                            cx.notify();
 5412                            return;
 5413                        }
 5414                    }
 5415
 5416                    if editor.completion_tasks.len() <= 1 {
 5417                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5418                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5419                        // If it was already hidden and we don't show inline completions in the menu, we should
 5420                        // also show the inline-completion when available.
 5421                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5422                            editor.update_visible_inline_completion(window, cx);
 5423                        }
 5424                    }
 5425                })
 5426                .ok();
 5427        });
 5428
 5429        self.completion_tasks.push((id, task));
 5430    }
 5431
 5432    #[cfg(feature = "test-support")]
 5433    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5434        let menu = self.context_menu.borrow();
 5435        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5436            let completions = menu.completions.borrow();
 5437            Some(completions.to_vec())
 5438        } else {
 5439            None
 5440        }
 5441    }
 5442
 5443    pub fn with_completions_menu_matching_id<R>(
 5444        &self,
 5445        id: CompletionId,
 5446        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5447    ) -> R {
 5448        let mut context_menu = self.context_menu.borrow_mut();
 5449        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5450            return f(None);
 5451        };
 5452        if completions_menu.id != id {
 5453            return f(None);
 5454        }
 5455        f(Some(completions_menu))
 5456    }
 5457
 5458    pub fn confirm_completion(
 5459        &mut self,
 5460        action: &ConfirmCompletion,
 5461        window: &mut Window,
 5462        cx: &mut Context<Self>,
 5463    ) -> Option<Task<Result<()>>> {
 5464        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5465        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5466    }
 5467
 5468    pub fn confirm_completion_insert(
 5469        &mut self,
 5470        _: &ConfirmCompletionInsert,
 5471        window: &mut Window,
 5472        cx: &mut Context<Self>,
 5473    ) -> Option<Task<Result<()>>> {
 5474        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5475        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5476    }
 5477
 5478    pub fn confirm_completion_replace(
 5479        &mut self,
 5480        _: &ConfirmCompletionReplace,
 5481        window: &mut Window,
 5482        cx: &mut Context<Self>,
 5483    ) -> Option<Task<Result<()>>> {
 5484        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5485        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5486    }
 5487
 5488    pub fn compose_completion(
 5489        &mut self,
 5490        action: &ComposeCompletion,
 5491        window: &mut Window,
 5492        cx: &mut Context<Self>,
 5493    ) -> Option<Task<Result<()>>> {
 5494        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5495        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5496    }
 5497
 5498    fn do_completion(
 5499        &mut self,
 5500        item_ix: Option<usize>,
 5501        intent: CompletionIntent,
 5502        window: &mut Window,
 5503        cx: &mut Context<Editor>,
 5504    ) -> Option<Task<Result<()>>> {
 5505        use language::ToOffset as _;
 5506
 5507        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5508        else {
 5509            return None;
 5510        };
 5511
 5512        let candidate_id = {
 5513            let entries = completions_menu.entries.borrow();
 5514            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5515            if self.show_edit_predictions_in_menu() {
 5516                self.discard_inline_completion(true, cx);
 5517            }
 5518            mat.candidate_id
 5519        };
 5520
 5521        let completion = completions_menu
 5522            .completions
 5523            .borrow()
 5524            .get(candidate_id)?
 5525            .clone();
 5526        cx.stop_propagation();
 5527
 5528        let buffer_handle = completions_menu.buffer.clone();
 5529
 5530        let CompletionEdit {
 5531            new_text,
 5532            snippet,
 5533            replace_range,
 5534        } = process_completion_for_edit(
 5535            &completion,
 5536            intent,
 5537            &buffer_handle,
 5538            &completions_menu.initial_position.text_anchor,
 5539            cx,
 5540        );
 5541
 5542        let buffer = buffer_handle.read(cx);
 5543        let snapshot = self.buffer.read(cx).snapshot(cx);
 5544        let newest_anchor = self.selections.newest_anchor();
 5545        let replace_range_multibuffer = {
 5546            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5547            let multibuffer_anchor = snapshot
 5548                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5549                .unwrap()
 5550                ..snapshot
 5551                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5552                    .unwrap();
 5553            multibuffer_anchor.start.to_offset(&snapshot)
 5554                ..multibuffer_anchor.end.to_offset(&snapshot)
 5555        };
 5556        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5557            return None;
 5558        }
 5559
 5560        let old_text = buffer
 5561            .text_for_range(replace_range.clone())
 5562            .collect::<String>();
 5563        let lookbehind = newest_anchor
 5564            .start
 5565            .text_anchor
 5566            .to_offset(buffer)
 5567            .saturating_sub(replace_range.start);
 5568        let lookahead = replace_range
 5569            .end
 5570            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5571        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5572        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5573
 5574        let selections = self.selections.all::<usize>(cx);
 5575        let mut ranges = Vec::new();
 5576        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5577
 5578        for selection in &selections {
 5579            let range = if selection.id == newest_anchor.id {
 5580                replace_range_multibuffer.clone()
 5581            } else {
 5582                let mut range = selection.range();
 5583
 5584                // if prefix is present, don't duplicate it
 5585                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5586                    range.start = range.start.saturating_sub(lookbehind);
 5587
 5588                    // if suffix is also present, mimic the newest cursor and replace it
 5589                    if selection.id != newest_anchor.id
 5590                        && snapshot.contains_str_at(range.end, suffix)
 5591                    {
 5592                        range.end += lookahead;
 5593                    }
 5594                }
 5595                range
 5596            };
 5597
 5598            ranges.push(range.clone());
 5599
 5600            if !self.linked_edit_ranges.is_empty() {
 5601                let start_anchor = snapshot.anchor_before(range.start);
 5602                let end_anchor = snapshot.anchor_after(range.end);
 5603                if let Some(ranges) = self
 5604                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5605                {
 5606                    for (buffer, edits) in ranges {
 5607                        linked_edits
 5608                            .entry(buffer.clone())
 5609                            .or_default()
 5610                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5611                    }
 5612                }
 5613            }
 5614        }
 5615
 5616        let common_prefix_len = old_text
 5617            .chars()
 5618            .zip(new_text.chars())
 5619            .take_while(|(a, b)| a == b)
 5620            .map(|(a, _)| a.len_utf8())
 5621            .sum::<usize>();
 5622
 5623        cx.emit(EditorEvent::InputHandled {
 5624            utf16_range_to_replace: None,
 5625            text: new_text[common_prefix_len..].into(),
 5626        });
 5627
 5628        self.transact(window, cx, |this, window, cx| {
 5629            if let Some(mut snippet) = snippet {
 5630                snippet.text = new_text.to_string();
 5631                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5632            } else {
 5633                this.buffer.update(cx, |buffer, cx| {
 5634                    let auto_indent = match completion.insert_text_mode {
 5635                        Some(InsertTextMode::AS_IS) => None,
 5636                        _ => this.autoindent_mode.clone(),
 5637                    };
 5638                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5639                    buffer.edit(edits, auto_indent, cx);
 5640                });
 5641            }
 5642            for (buffer, edits) in linked_edits {
 5643                buffer.update(cx, |buffer, cx| {
 5644                    let snapshot = buffer.snapshot();
 5645                    let edits = edits
 5646                        .into_iter()
 5647                        .map(|(range, text)| {
 5648                            use text::ToPoint as TP;
 5649                            let end_point = TP::to_point(&range.end, &snapshot);
 5650                            let start_point = TP::to_point(&range.start, &snapshot);
 5651                            (start_point..end_point, text)
 5652                        })
 5653                        .sorted_by_key(|(range, _)| range.start);
 5654                    buffer.edit(edits, None, cx);
 5655                })
 5656            }
 5657
 5658            this.refresh_inline_completion(true, false, window, cx);
 5659        });
 5660
 5661        let show_new_completions_on_confirm = completion
 5662            .confirm
 5663            .as_ref()
 5664            .map_or(false, |confirm| confirm(intent, window, cx));
 5665        if show_new_completions_on_confirm {
 5666            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5667        }
 5668
 5669        let provider = self.completion_provider.as_ref()?;
 5670        drop(completion);
 5671        let apply_edits = provider.apply_additional_edits_for_completion(
 5672            buffer_handle,
 5673            completions_menu.completions.clone(),
 5674            candidate_id,
 5675            true,
 5676            cx,
 5677        );
 5678
 5679        let editor_settings = EditorSettings::get_global(cx);
 5680        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5681            // After the code completion is finished, users often want to know what signatures are needed.
 5682            // so we should automatically call signature_help
 5683            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5684        }
 5685
 5686        Some(cx.foreground_executor().spawn(async move {
 5687            apply_edits.await?;
 5688            Ok(())
 5689        }))
 5690    }
 5691
 5692    pub fn toggle_code_actions(
 5693        &mut self,
 5694        action: &ToggleCodeActions,
 5695        window: &mut Window,
 5696        cx: &mut Context<Self>,
 5697    ) {
 5698        let quick_launch = action.quick_launch;
 5699        let mut context_menu = self.context_menu.borrow_mut();
 5700        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5701            if code_actions.deployed_from == action.deployed_from {
 5702                // Toggle if we're selecting the same one
 5703                *context_menu = None;
 5704                cx.notify();
 5705                return;
 5706            } else {
 5707                // Otherwise, clear it and start a new one
 5708                *context_menu = None;
 5709                cx.notify();
 5710            }
 5711        }
 5712        drop(context_menu);
 5713        let snapshot = self.snapshot(window, cx);
 5714        let deployed_from = action.deployed_from.clone();
 5715        let action = action.clone();
 5716        self.completion_tasks.clear();
 5717        self.discard_inline_completion(false, cx);
 5718
 5719        let multibuffer_point = match &action.deployed_from {
 5720            Some(CodeActionSource::Indicator(row)) => {
 5721                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5722            }
 5723            _ => self.selections.newest::<Point>(cx).head(),
 5724        };
 5725        let Some((buffer, buffer_row)) = snapshot
 5726            .buffer_snapshot
 5727            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5728            .and_then(|(buffer_snapshot, range)| {
 5729                self.buffer()
 5730                    .read(cx)
 5731                    .buffer(buffer_snapshot.remote_id())
 5732                    .map(|buffer| (buffer, range.start.row))
 5733            })
 5734        else {
 5735            return;
 5736        };
 5737        let buffer_id = buffer.read(cx).remote_id();
 5738        let tasks = self
 5739            .tasks
 5740            .get(&(buffer_id, buffer_row))
 5741            .map(|t| Arc::new(t.to_owned()));
 5742
 5743        if !self.focus_handle.is_focused(window) {
 5744            return;
 5745        }
 5746        let project = self.project.clone();
 5747
 5748        let code_actions_task = match deployed_from {
 5749            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5750            _ => self.code_actions(buffer_row, window, cx),
 5751        };
 5752
 5753        let runnable_task = match deployed_from {
 5754            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5755            _ => {
 5756                let mut task_context_task = Task::ready(None);
 5757                if let Some(tasks) = &tasks {
 5758                    if let Some(project) = project {
 5759                        task_context_task =
 5760                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5761                    }
 5762                }
 5763
 5764                cx.spawn_in(window, {
 5765                    let buffer = buffer.clone();
 5766                    async move |editor, cx| {
 5767                        let task_context = task_context_task.await;
 5768
 5769                        let resolved_tasks =
 5770                            tasks
 5771                                .zip(task_context.clone())
 5772                                .map(|(tasks, task_context)| ResolvedTasks {
 5773                                    templates: tasks.resolve(&task_context).collect(),
 5774                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5775                                        multibuffer_point.row,
 5776                                        tasks.column,
 5777                                    )),
 5778                                });
 5779                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5780                            editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5781                        })?;
 5782                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5783                    }
 5784                })
 5785            }
 5786        };
 5787
 5788        cx.spawn_in(window, async move |editor, cx| {
 5789            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5790            let code_actions = code_actions_task.await;
 5791            let spawn_straight_away = quick_launch
 5792                && resolved_tasks
 5793                    .as_ref()
 5794                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5795                && code_actions
 5796                    .as_ref()
 5797                    .map_or(true, |actions| actions.is_empty())
 5798                && debug_scenarios.is_empty();
 5799
 5800            editor.update_in(cx, |editor, window, cx| {
 5801                crate::hover_popover::hide_hover(editor, cx);
 5802                *editor.context_menu.borrow_mut() =
 5803                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5804                        buffer,
 5805                        actions: CodeActionContents::new(
 5806                            resolved_tasks,
 5807                            code_actions,
 5808                            debug_scenarios,
 5809                            task_context.unwrap_or_default(),
 5810                        ),
 5811                        selected_item: Default::default(),
 5812                        scroll_handle: UniformListScrollHandle::default(),
 5813                        deployed_from,
 5814                    }));
 5815                if spawn_straight_away {
 5816                    if let Some(task) = editor.confirm_code_action(
 5817                        &ConfirmCodeAction { item_ix: Some(0) },
 5818                        window,
 5819                        cx,
 5820                    ) {
 5821                        cx.notify();
 5822                        return task;
 5823                    }
 5824                }
 5825
 5826                Task::ready(Ok(()))
 5827            })
 5828        })
 5829        .detach_and_log_err(cx);
 5830    }
 5831
 5832    fn debug_scenarios(
 5833        &mut self,
 5834        resolved_tasks: &Option<ResolvedTasks>,
 5835        buffer: &Entity<Buffer>,
 5836        cx: &mut App,
 5837    ) -> Vec<task::DebugScenario> {
 5838        if cx.has_flag::<DebuggerFeatureFlag>() {
 5839            maybe!({
 5840                let project = self.project.as_ref()?;
 5841                let dap_store = project.read(cx).dap_store();
 5842                let mut scenarios = vec![];
 5843                let resolved_tasks = resolved_tasks.as_ref()?;
 5844                let buffer = buffer.read(cx);
 5845                let language = buffer.language()?;
 5846                let file = buffer.file();
 5847                let debug_adapter = language_settings(language.name().into(), file, cx)
 5848                    .debuggers
 5849                    .first()
 5850                    .map(SharedString::from)
 5851                    .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 5852
 5853                dap_store.update(cx, |dap_store, cx| {
 5854                    for (_, task) in &resolved_tasks.templates {
 5855                        if let Some(scenario) = dap_store.debug_scenario_for_build_task(
 5856                            task.original_task().clone(),
 5857                            debug_adapter.clone().into(),
 5858                            task.display_label().to_owned().into(),
 5859                            cx,
 5860                        ) {
 5861                            scenarios.push(scenario);
 5862                        }
 5863                    }
 5864                });
 5865                Some(scenarios)
 5866            })
 5867            .unwrap_or_default()
 5868        } else {
 5869            vec![]
 5870        }
 5871    }
 5872
 5873    fn code_actions(
 5874        &mut self,
 5875        buffer_row: u32,
 5876        window: &mut Window,
 5877        cx: &mut Context<Self>,
 5878    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 5879        let mut task = self.code_actions_task.take();
 5880        cx.spawn_in(window, async move |editor, cx| {
 5881            while let Some(prev_task) = task {
 5882                prev_task.await.log_err();
 5883                task = editor
 5884                    .update(cx, |this, _| this.code_actions_task.take())
 5885                    .ok()?;
 5886            }
 5887
 5888            editor
 5889                .update(cx, |editor, cx| {
 5890                    editor
 5891                        .available_code_actions
 5892                        .clone()
 5893                        .and_then(|(location, code_actions)| {
 5894                            let snapshot = location.buffer.read(cx).snapshot();
 5895                            let point_range = location.range.to_point(&snapshot);
 5896                            let point_range = point_range.start.row..=point_range.end.row;
 5897                            if point_range.contains(&buffer_row) {
 5898                                Some(code_actions)
 5899                            } else {
 5900                                None
 5901                            }
 5902                        })
 5903                })
 5904                .ok()
 5905                .flatten()
 5906        })
 5907    }
 5908
 5909    pub fn confirm_code_action(
 5910        &mut self,
 5911        action: &ConfirmCodeAction,
 5912        window: &mut Window,
 5913        cx: &mut Context<Self>,
 5914    ) -> Option<Task<Result<()>>> {
 5915        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5916
 5917        let actions_menu =
 5918            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5919                menu
 5920            } else {
 5921                return None;
 5922            };
 5923
 5924        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5925        let action = actions_menu.actions.get(action_ix)?;
 5926        let title = action.label();
 5927        let buffer = actions_menu.buffer;
 5928        let workspace = self.workspace()?;
 5929
 5930        match action {
 5931            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5932                workspace.update(cx, |workspace, cx| {
 5933                    workspace.schedule_resolved_task(
 5934                        task_source_kind,
 5935                        resolved_task,
 5936                        false,
 5937                        window,
 5938                        cx,
 5939                    );
 5940
 5941                    Some(Task::ready(Ok(())))
 5942                })
 5943            }
 5944            CodeActionsItem::CodeAction {
 5945                excerpt_id,
 5946                action,
 5947                provider,
 5948            } => {
 5949                let apply_code_action =
 5950                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5951                let workspace = workspace.downgrade();
 5952                Some(cx.spawn_in(window, async move |editor, cx| {
 5953                    let project_transaction = apply_code_action.await?;
 5954                    Self::open_project_transaction(
 5955                        &editor,
 5956                        workspace,
 5957                        project_transaction,
 5958                        title,
 5959                        cx,
 5960                    )
 5961                    .await
 5962                }))
 5963            }
 5964            CodeActionsItem::DebugScenario(scenario) => {
 5965                let context = actions_menu.actions.context.clone();
 5966
 5967                workspace.update(cx, |workspace, cx| {
 5968                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5969                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5970                });
 5971                Some(Task::ready(Ok(())))
 5972            }
 5973        }
 5974    }
 5975
 5976    pub async fn open_project_transaction(
 5977        this: &WeakEntity<Editor>,
 5978        workspace: WeakEntity<Workspace>,
 5979        transaction: ProjectTransaction,
 5980        title: String,
 5981        cx: &mut AsyncWindowContext,
 5982    ) -> Result<()> {
 5983        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5984        cx.update(|_, cx| {
 5985            entries.sort_unstable_by_key(|(buffer, _)| {
 5986                buffer.read(cx).file().map(|f| f.path().clone())
 5987            });
 5988        })?;
 5989
 5990        // If the project transaction's edits are all contained within this editor, then
 5991        // avoid opening a new editor to display them.
 5992
 5993        if let Some((buffer, transaction)) = entries.first() {
 5994            if entries.len() == 1 {
 5995                let excerpt = this.update(cx, |editor, cx| {
 5996                    editor
 5997                        .buffer()
 5998                        .read(cx)
 5999                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6000                })?;
 6001                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6002                    if excerpted_buffer == *buffer {
 6003                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6004                            let excerpt_range = excerpt_range.to_offset(buffer);
 6005                            buffer
 6006                                .edited_ranges_for_transaction::<usize>(transaction)
 6007                                .all(|range| {
 6008                                    excerpt_range.start <= range.start
 6009                                        && excerpt_range.end >= range.end
 6010                                })
 6011                        })?;
 6012
 6013                        if all_edits_within_excerpt {
 6014                            return Ok(());
 6015                        }
 6016                    }
 6017                }
 6018            }
 6019        } else {
 6020            return Ok(());
 6021        }
 6022
 6023        let mut ranges_to_highlight = Vec::new();
 6024        let excerpt_buffer = cx.new(|cx| {
 6025            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6026            for (buffer_handle, transaction) in &entries {
 6027                let edited_ranges = buffer_handle
 6028                    .read(cx)
 6029                    .edited_ranges_for_transaction::<Point>(transaction)
 6030                    .collect::<Vec<_>>();
 6031                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6032                    PathKey::for_buffer(buffer_handle, cx),
 6033                    buffer_handle.clone(),
 6034                    edited_ranges,
 6035                    DEFAULT_MULTIBUFFER_CONTEXT,
 6036                    cx,
 6037                );
 6038
 6039                ranges_to_highlight.extend(ranges);
 6040            }
 6041            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6042            multibuffer
 6043        })?;
 6044
 6045        workspace.update_in(cx, |workspace, window, cx| {
 6046            let project = workspace.project().clone();
 6047            let editor =
 6048                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6049            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6050            editor.update(cx, |editor, cx| {
 6051                editor.highlight_background::<Self>(
 6052                    &ranges_to_highlight,
 6053                    |theme| theme.editor_highlighted_line_background,
 6054                    cx,
 6055                );
 6056            });
 6057        })?;
 6058
 6059        Ok(())
 6060    }
 6061
 6062    pub fn clear_code_action_providers(&mut self) {
 6063        self.code_action_providers.clear();
 6064        self.available_code_actions.take();
 6065    }
 6066
 6067    pub fn add_code_action_provider(
 6068        &mut self,
 6069        provider: Rc<dyn CodeActionProvider>,
 6070        window: &mut Window,
 6071        cx: &mut Context<Self>,
 6072    ) {
 6073        if self
 6074            .code_action_providers
 6075            .iter()
 6076            .any(|existing_provider| existing_provider.id() == provider.id())
 6077        {
 6078            return;
 6079        }
 6080
 6081        self.code_action_providers.push(provider);
 6082        self.refresh_code_actions(window, cx);
 6083    }
 6084
 6085    pub fn remove_code_action_provider(
 6086        &mut self,
 6087        id: Arc<str>,
 6088        window: &mut Window,
 6089        cx: &mut Context<Self>,
 6090    ) {
 6091        self.code_action_providers
 6092            .retain(|provider| provider.id() != id);
 6093        self.refresh_code_actions(window, cx);
 6094    }
 6095
 6096    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6097        !self.code_action_providers.is_empty()
 6098            && EditorSettings::get_global(cx).toolbar.code_actions
 6099    }
 6100
 6101    pub fn has_available_code_actions(&self) -> bool {
 6102        self.available_code_actions
 6103            .as_ref()
 6104            .is_some_and(|(_, actions)| !actions.is_empty())
 6105    }
 6106
 6107    fn render_inline_code_actions(
 6108        &self,
 6109        icon_size: ui::IconSize,
 6110        display_row: DisplayRow,
 6111        is_active: bool,
 6112        cx: &mut Context<Self>,
 6113    ) -> AnyElement {
 6114        let show_tooltip = !self.context_menu_visible();
 6115        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6116            .icon_size(icon_size)
 6117            .shape(ui::IconButtonShape::Square)
 6118            .style(ButtonStyle::Transparent)
 6119            .icon_color(ui::Color::Hidden)
 6120            .toggle_state(is_active)
 6121            .when(show_tooltip, |this| {
 6122                this.tooltip({
 6123                    let focus_handle = self.focus_handle.clone();
 6124                    move |window, cx| {
 6125                        Tooltip::for_action_in(
 6126                            "Toggle Code Actions",
 6127                            &ToggleCodeActions {
 6128                                deployed_from: None,
 6129                                quick_launch: false,
 6130                            },
 6131                            &focus_handle,
 6132                            window,
 6133                            cx,
 6134                        )
 6135                    }
 6136                })
 6137            })
 6138            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6139                window.focus(&editor.focus_handle(cx));
 6140                editor.toggle_code_actions(
 6141                    &crate::actions::ToggleCodeActions {
 6142                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6143                            display_row,
 6144                        )),
 6145                        quick_launch: false,
 6146                    },
 6147                    window,
 6148                    cx,
 6149                );
 6150            }))
 6151            .into_any_element()
 6152    }
 6153
 6154    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6155        &self.context_menu
 6156    }
 6157
 6158    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6159        let newest_selection = self.selections.newest_anchor().clone();
 6160        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6161        let buffer = self.buffer.read(cx);
 6162        if newest_selection.head().diff_base_anchor.is_some() {
 6163            return None;
 6164        }
 6165        let (start_buffer, start) =
 6166            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6167        let (end_buffer, end) =
 6168            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6169        if start_buffer != end_buffer {
 6170            return None;
 6171        }
 6172
 6173        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6174            cx.background_executor()
 6175                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6176                .await;
 6177
 6178            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6179                let providers = this.code_action_providers.clone();
 6180                let tasks = this
 6181                    .code_action_providers
 6182                    .iter()
 6183                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6184                    .collect::<Vec<_>>();
 6185                (providers, tasks)
 6186            })?;
 6187
 6188            let mut actions = Vec::new();
 6189            for (provider, provider_actions) in
 6190                providers.into_iter().zip(future::join_all(tasks).await)
 6191            {
 6192                if let Some(provider_actions) = provider_actions.log_err() {
 6193                    actions.extend(provider_actions.into_iter().map(|action| {
 6194                        AvailableCodeAction {
 6195                            excerpt_id: newest_selection.start.excerpt_id,
 6196                            action,
 6197                            provider: provider.clone(),
 6198                        }
 6199                    }));
 6200                }
 6201            }
 6202
 6203            this.update(cx, |this, cx| {
 6204                this.available_code_actions = if actions.is_empty() {
 6205                    None
 6206                } else {
 6207                    Some((
 6208                        Location {
 6209                            buffer: start_buffer,
 6210                            range: start..end,
 6211                        },
 6212                        actions.into(),
 6213                    ))
 6214                };
 6215                cx.notify();
 6216            })
 6217        }));
 6218        None
 6219    }
 6220
 6221    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6222        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6223            self.show_git_blame_inline = false;
 6224
 6225            self.show_git_blame_inline_delay_task =
 6226                Some(cx.spawn_in(window, async move |this, cx| {
 6227                    cx.background_executor().timer(delay).await;
 6228
 6229                    this.update(cx, |this, cx| {
 6230                        this.show_git_blame_inline = true;
 6231                        cx.notify();
 6232                    })
 6233                    .log_err();
 6234                }));
 6235        }
 6236    }
 6237
 6238    fn show_blame_popover(
 6239        &mut self,
 6240        blame_entry: &BlameEntry,
 6241        position: gpui::Point<Pixels>,
 6242        cx: &mut Context<Self>,
 6243    ) {
 6244        if let Some(state) = &mut self.inline_blame_popover {
 6245            state.hide_task.take();
 6246            cx.notify();
 6247        } else {
 6248            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6249            let show_task = cx.spawn(async move |editor, cx| {
 6250                cx.background_executor()
 6251                    .timer(std::time::Duration::from_millis(delay))
 6252                    .await;
 6253                editor
 6254                    .update(cx, |editor, cx| {
 6255                        if let Some(state) = &mut editor.inline_blame_popover {
 6256                            state.show_task = None;
 6257                            cx.notify();
 6258                        }
 6259                    })
 6260                    .ok();
 6261            });
 6262            let Some(blame) = self.blame.as_ref() else {
 6263                return;
 6264            };
 6265            let blame = blame.read(cx);
 6266            let details = blame.details_for_entry(&blame_entry);
 6267            let markdown = cx.new(|cx| {
 6268                Markdown::new(
 6269                    details
 6270                        .as_ref()
 6271                        .map(|message| message.message.clone())
 6272                        .unwrap_or_default(),
 6273                    None,
 6274                    None,
 6275                    cx,
 6276                )
 6277            });
 6278            self.inline_blame_popover = Some(InlineBlamePopover {
 6279                position,
 6280                show_task: Some(show_task),
 6281                hide_task: None,
 6282                popover_bounds: None,
 6283                popover_state: InlineBlamePopoverState {
 6284                    scroll_handle: ScrollHandle::new(),
 6285                    commit_message: details,
 6286                    markdown,
 6287                },
 6288            });
 6289        }
 6290    }
 6291
 6292    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6293        if let Some(state) = &mut self.inline_blame_popover {
 6294            if state.show_task.is_some() {
 6295                self.inline_blame_popover.take();
 6296                cx.notify();
 6297            } else {
 6298                let hide_task = cx.spawn(async move |editor, cx| {
 6299                    cx.background_executor()
 6300                        .timer(std::time::Duration::from_millis(100))
 6301                        .await;
 6302                    editor
 6303                        .update(cx, |editor, cx| {
 6304                            editor.inline_blame_popover.take();
 6305                            cx.notify();
 6306                        })
 6307                        .ok();
 6308                });
 6309                state.hide_task = Some(hide_task);
 6310            }
 6311        }
 6312    }
 6313
 6314    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6315        if self.pending_rename.is_some() {
 6316            return None;
 6317        }
 6318
 6319        let provider = self.semantics_provider.clone()?;
 6320        let buffer = self.buffer.read(cx);
 6321        let newest_selection = self.selections.newest_anchor().clone();
 6322        let cursor_position = newest_selection.head();
 6323        let (cursor_buffer, cursor_buffer_position) =
 6324            buffer.text_anchor_for_position(cursor_position, cx)?;
 6325        let (tail_buffer, tail_buffer_position) =
 6326            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6327        if cursor_buffer != tail_buffer {
 6328            return None;
 6329        }
 6330
 6331        let snapshot = cursor_buffer.read(cx).snapshot();
 6332        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6333        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6334        if start_word_range != end_word_range {
 6335            self.document_highlights_task.take();
 6336            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6337            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6338            return None;
 6339        }
 6340
 6341        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6342        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6343            cx.background_executor()
 6344                .timer(Duration::from_millis(debounce))
 6345                .await;
 6346
 6347            let highlights = if let Some(highlights) = cx
 6348                .update(|cx| {
 6349                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6350                })
 6351                .ok()
 6352                .flatten()
 6353            {
 6354                highlights.await.log_err()
 6355            } else {
 6356                None
 6357            };
 6358
 6359            if let Some(highlights) = highlights {
 6360                this.update(cx, |this, cx| {
 6361                    if this.pending_rename.is_some() {
 6362                        return;
 6363                    }
 6364
 6365                    let buffer_id = cursor_position.buffer_id;
 6366                    let buffer = this.buffer.read(cx);
 6367                    if !buffer
 6368                        .text_anchor_for_position(cursor_position, cx)
 6369                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6370                    {
 6371                        return;
 6372                    }
 6373
 6374                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6375                    let mut write_ranges = Vec::new();
 6376                    let mut read_ranges = Vec::new();
 6377                    for highlight in highlights {
 6378                        for (excerpt_id, excerpt_range) in
 6379                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6380                        {
 6381                            let start = highlight
 6382                                .range
 6383                                .start
 6384                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6385                            let end = highlight
 6386                                .range
 6387                                .end
 6388                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6389                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6390                                continue;
 6391                            }
 6392
 6393                            let range = Anchor {
 6394                                buffer_id,
 6395                                excerpt_id,
 6396                                text_anchor: start,
 6397                                diff_base_anchor: None,
 6398                            }..Anchor {
 6399                                buffer_id,
 6400                                excerpt_id,
 6401                                text_anchor: end,
 6402                                diff_base_anchor: None,
 6403                            };
 6404                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6405                                write_ranges.push(range);
 6406                            } else {
 6407                                read_ranges.push(range);
 6408                            }
 6409                        }
 6410                    }
 6411
 6412                    this.highlight_background::<DocumentHighlightRead>(
 6413                        &read_ranges,
 6414                        |theme| theme.editor_document_highlight_read_background,
 6415                        cx,
 6416                    );
 6417                    this.highlight_background::<DocumentHighlightWrite>(
 6418                        &write_ranges,
 6419                        |theme| theme.editor_document_highlight_write_background,
 6420                        cx,
 6421                    );
 6422                    cx.notify();
 6423                })
 6424                .log_err();
 6425            }
 6426        }));
 6427        None
 6428    }
 6429
 6430    fn prepare_highlight_query_from_selection(
 6431        &mut self,
 6432        cx: &mut Context<Editor>,
 6433    ) -> Option<(String, Range<Anchor>)> {
 6434        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6435            return None;
 6436        }
 6437        if !EditorSettings::get_global(cx).selection_highlight {
 6438            return None;
 6439        }
 6440        if self.selections.count() != 1 || self.selections.line_mode {
 6441            return None;
 6442        }
 6443        let selection = self.selections.newest::<Point>(cx);
 6444        if selection.is_empty() || selection.start.row != selection.end.row {
 6445            return None;
 6446        }
 6447        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6448        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6449        let query = multi_buffer_snapshot
 6450            .text_for_range(selection_anchor_range.clone())
 6451            .collect::<String>();
 6452        if query.trim().is_empty() {
 6453            return None;
 6454        }
 6455        Some((query, selection_anchor_range))
 6456    }
 6457
 6458    fn update_selection_occurrence_highlights(
 6459        &mut self,
 6460        query_text: String,
 6461        query_range: Range<Anchor>,
 6462        multi_buffer_range_to_query: Range<Point>,
 6463        use_debounce: bool,
 6464        window: &mut Window,
 6465        cx: &mut Context<Editor>,
 6466    ) -> Task<()> {
 6467        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6468        cx.spawn_in(window, async move |editor, cx| {
 6469            if use_debounce {
 6470                cx.background_executor()
 6471                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6472                    .await;
 6473            }
 6474            let match_task = cx.background_spawn(async move {
 6475                let buffer_ranges = multi_buffer_snapshot
 6476                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6477                    .into_iter()
 6478                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6479                let mut match_ranges = Vec::new();
 6480                let Ok(regex) = project::search::SearchQuery::text(
 6481                    query_text.clone(),
 6482                    false,
 6483                    false,
 6484                    false,
 6485                    Default::default(),
 6486                    Default::default(),
 6487                    false,
 6488                    None,
 6489                ) else {
 6490                    return Vec::default();
 6491                };
 6492                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6493                    match_ranges.extend(
 6494                        regex
 6495                            .search(&buffer_snapshot, Some(search_range.clone()))
 6496                            .await
 6497                            .into_iter()
 6498                            .filter_map(|match_range| {
 6499                                let match_start = buffer_snapshot
 6500                                    .anchor_after(search_range.start + match_range.start);
 6501                                let match_end = buffer_snapshot
 6502                                    .anchor_before(search_range.start + match_range.end);
 6503                                let match_anchor_range = Anchor::range_in_buffer(
 6504                                    excerpt_id,
 6505                                    buffer_snapshot.remote_id(),
 6506                                    match_start..match_end,
 6507                                );
 6508                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6509                            }),
 6510                    );
 6511                }
 6512                match_ranges
 6513            });
 6514            let match_ranges = match_task.await;
 6515            editor
 6516                .update_in(cx, |editor, _, cx| {
 6517                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6518                    if !match_ranges.is_empty() {
 6519                        editor.highlight_background::<SelectedTextHighlight>(
 6520                            &match_ranges,
 6521                            |theme| theme.editor_document_highlight_bracket_background,
 6522                            cx,
 6523                        )
 6524                    }
 6525                })
 6526                .log_err();
 6527        })
 6528    }
 6529
 6530    fn refresh_selected_text_highlights(
 6531        &mut self,
 6532        on_buffer_edit: bool,
 6533        window: &mut Window,
 6534        cx: &mut Context<Editor>,
 6535    ) {
 6536        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6537        else {
 6538            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6539            self.quick_selection_highlight_task.take();
 6540            self.debounced_selection_highlight_task.take();
 6541            return;
 6542        };
 6543        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6544        if on_buffer_edit
 6545            || self
 6546                .quick_selection_highlight_task
 6547                .as_ref()
 6548                .map_or(true, |(prev_anchor_range, _)| {
 6549                    prev_anchor_range != &query_range
 6550                })
 6551        {
 6552            let multi_buffer_visible_start = self
 6553                .scroll_manager
 6554                .anchor()
 6555                .anchor
 6556                .to_point(&multi_buffer_snapshot);
 6557            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6558                multi_buffer_visible_start
 6559                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6560                Bias::Left,
 6561            );
 6562            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6563            self.quick_selection_highlight_task = Some((
 6564                query_range.clone(),
 6565                self.update_selection_occurrence_highlights(
 6566                    query_text.clone(),
 6567                    query_range.clone(),
 6568                    multi_buffer_visible_range,
 6569                    false,
 6570                    window,
 6571                    cx,
 6572                ),
 6573            ));
 6574        }
 6575        if on_buffer_edit
 6576            || self
 6577                .debounced_selection_highlight_task
 6578                .as_ref()
 6579                .map_or(true, |(prev_anchor_range, _)| {
 6580                    prev_anchor_range != &query_range
 6581                })
 6582        {
 6583            let multi_buffer_start = multi_buffer_snapshot
 6584                .anchor_before(0)
 6585                .to_point(&multi_buffer_snapshot);
 6586            let multi_buffer_end = multi_buffer_snapshot
 6587                .anchor_after(multi_buffer_snapshot.len())
 6588                .to_point(&multi_buffer_snapshot);
 6589            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6590            self.debounced_selection_highlight_task = Some((
 6591                query_range.clone(),
 6592                self.update_selection_occurrence_highlights(
 6593                    query_text,
 6594                    query_range,
 6595                    multi_buffer_full_range,
 6596                    true,
 6597                    window,
 6598                    cx,
 6599                ),
 6600            ));
 6601        }
 6602    }
 6603
 6604    pub fn refresh_inline_completion(
 6605        &mut self,
 6606        debounce: bool,
 6607        user_requested: bool,
 6608        window: &mut Window,
 6609        cx: &mut Context<Self>,
 6610    ) -> Option<()> {
 6611        let provider = self.edit_prediction_provider()?;
 6612        let cursor = self.selections.newest_anchor().head();
 6613        let (buffer, cursor_buffer_position) =
 6614            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6615
 6616        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6617            self.discard_inline_completion(false, cx);
 6618            return None;
 6619        }
 6620
 6621        if !user_requested
 6622            && (!self.should_show_edit_predictions()
 6623                || !self.is_focused(window)
 6624                || buffer.read(cx).is_empty())
 6625        {
 6626            self.discard_inline_completion(false, cx);
 6627            return None;
 6628        }
 6629
 6630        self.update_visible_inline_completion(window, cx);
 6631        provider.refresh(
 6632            self.project.clone(),
 6633            buffer,
 6634            cursor_buffer_position,
 6635            debounce,
 6636            cx,
 6637        );
 6638        Some(())
 6639    }
 6640
 6641    fn show_edit_predictions_in_menu(&self) -> bool {
 6642        match self.edit_prediction_settings {
 6643            EditPredictionSettings::Disabled => false,
 6644            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6645        }
 6646    }
 6647
 6648    pub fn edit_predictions_enabled(&self) -> bool {
 6649        match self.edit_prediction_settings {
 6650            EditPredictionSettings::Disabled => false,
 6651            EditPredictionSettings::Enabled { .. } => true,
 6652        }
 6653    }
 6654
 6655    fn edit_prediction_requires_modifier(&self) -> bool {
 6656        match self.edit_prediction_settings {
 6657            EditPredictionSettings::Disabled => false,
 6658            EditPredictionSettings::Enabled {
 6659                preview_requires_modifier,
 6660                ..
 6661            } => preview_requires_modifier,
 6662        }
 6663    }
 6664
 6665    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6666        if self.edit_prediction_provider.is_none() {
 6667            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6668        } else {
 6669            let selection = self.selections.newest_anchor();
 6670            let cursor = selection.head();
 6671
 6672            if let Some((buffer, cursor_buffer_position)) =
 6673                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6674            {
 6675                self.edit_prediction_settings =
 6676                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6677            }
 6678        }
 6679    }
 6680
 6681    fn edit_prediction_settings_at_position(
 6682        &self,
 6683        buffer: &Entity<Buffer>,
 6684        buffer_position: language::Anchor,
 6685        cx: &App,
 6686    ) -> EditPredictionSettings {
 6687        if !self.mode.is_full()
 6688            || !self.show_inline_completions_override.unwrap_or(true)
 6689            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6690        {
 6691            return EditPredictionSettings::Disabled;
 6692        }
 6693
 6694        let buffer = buffer.read(cx);
 6695
 6696        let file = buffer.file();
 6697
 6698        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6699            return EditPredictionSettings::Disabled;
 6700        };
 6701
 6702        let by_provider = matches!(
 6703            self.menu_inline_completions_policy,
 6704            MenuInlineCompletionsPolicy::ByProvider
 6705        );
 6706
 6707        let show_in_menu = by_provider
 6708            && self
 6709                .edit_prediction_provider
 6710                .as_ref()
 6711                .map_or(false, |provider| {
 6712                    provider.provider.show_completions_in_menu()
 6713                });
 6714
 6715        let preview_requires_modifier =
 6716            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6717
 6718        EditPredictionSettings::Enabled {
 6719            show_in_menu,
 6720            preview_requires_modifier,
 6721        }
 6722    }
 6723
 6724    fn should_show_edit_predictions(&self) -> bool {
 6725        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6726    }
 6727
 6728    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6729        matches!(
 6730            self.edit_prediction_preview,
 6731            EditPredictionPreview::Active { .. }
 6732        )
 6733    }
 6734
 6735    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6736        let cursor = self.selections.newest_anchor().head();
 6737        if let Some((buffer, cursor_position)) =
 6738            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6739        {
 6740            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6741        } else {
 6742            false
 6743        }
 6744    }
 6745
 6746    pub fn supports_minimap(&self, cx: &App) -> bool {
 6747        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6748    }
 6749
 6750    fn edit_predictions_enabled_in_buffer(
 6751        &self,
 6752        buffer: &Entity<Buffer>,
 6753        buffer_position: language::Anchor,
 6754        cx: &App,
 6755    ) -> bool {
 6756        maybe!({
 6757            if self.read_only(cx) {
 6758                return Some(false);
 6759            }
 6760            let provider = self.edit_prediction_provider()?;
 6761            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6762                return Some(false);
 6763            }
 6764            let buffer = buffer.read(cx);
 6765            let Some(file) = buffer.file() else {
 6766                return Some(true);
 6767            };
 6768            let settings = all_language_settings(Some(file), cx);
 6769            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6770        })
 6771        .unwrap_or(false)
 6772    }
 6773
 6774    fn cycle_inline_completion(
 6775        &mut self,
 6776        direction: Direction,
 6777        window: &mut Window,
 6778        cx: &mut Context<Self>,
 6779    ) -> Option<()> {
 6780        let provider = self.edit_prediction_provider()?;
 6781        let cursor = self.selections.newest_anchor().head();
 6782        let (buffer, cursor_buffer_position) =
 6783            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6784        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6785            return None;
 6786        }
 6787
 6788        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6789        self.update_visible_inline_completion(window, cx);
 6790
 6791        Some(())
 6792    }
 6793
 6794    pub fn show_inline_completion(
 6795        &mut self,
 6796        _: &ShowEditPrediction,
 6797        window: &mut Window,
 6798        cx: &mut Context<Self>,
 6799    ) {
 6800        if !self.has_active_inline_completion() {
 6801            self.refresh_inline_completion(false, true, window, cx);
 6802            return;
 6803        }
 6804
 6805        self.update_visible_inline_completion(window, cx);
 6806    }
 6807
 6808    pub fn display_cursor_names(
 6809        &mut self,
 6810        _: &DisplayCursorNames,
 6811        window: &mut Window,
 6812        cx: &mut Context<Self>,
 6813    ) {
 6814        self.show_cursor_names(window, cx);
 6815    }
 6816
 6817    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6818        self.show_cursor_names = true;
 6819        cx.notify();
 6820        cx.spawn_in(window, async move |this, cx| {
 6821            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6822            this.update(cx, |this, cx| {
 6823                this.show_cursor_names = false;
 6824                cx.notify()
 6825            })
 6826            .ok()
 6827        })
 6828        .detach();
 6829    }
 6830
 6831    pub fn next_edit_prediction(
 6832        &mut self,
 6833        _: &NextEditPrediction,
 6834        window: &mut Window,
 6835        cx: &mut Context<Self>,
 6836    ) {
 6837        if self.has_active_inline_completion() {
 6838            self.cycle_inline_completion(Direction::Next, window, cx);
 6839        } else {
 6840            let is_copilot_disabled = self
 6841                .refresh_inline_completion(false, true, window, cx)
 6842                .is_none();
 6843            if is_copilot_disabled {
 6844                cx.propagate();
 6845            }
 6846        }
 6847    }
 6848
 6849    pub fn previous_edit_prediction(
 6850        &mut self,
 6851        _: &PreviousEditPrediction,
 6852        window: &mut Window,
 6853        cx: &mut Context<Self>,
 6854    ) {
 6855        if self.has_active_inline_completion() {
 6856            self.cycle_inline_completion(Direction::Prev, window, cx);
 6857        } else {
 6858            let is_copilot_disabled = self
 6859                .refresh_inline_completion(false, true, window, cx)
 6860                .is_none();
 6861            if is_copilot_disabled {
 6862                cx.propagate();
 6863            }
 6864        }
 6865    }
 6866
 6867    pub fn accept_edit_prediction(
 6868        &mut self,
 6869        _: &AcceptEditPrediction,
 6870        window: &mut Window,
 6871        cx: &mut Context<Self>,
 6872    ) {
 6873        if self.show_edit_predictions_in_menu() {
 6874            self.hide_context_menu(window, cx);
 6875        }
 6876
 6877        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6878            return;
 6879        };
 6880
 6881        self.report_inline_completion_event(
 6882            active_inline_completion.completion_id.clone(),
 6883            true,
 6884            cx,
 6885        );
 6886
 6887        match &active_inline_completion.completion {
 6888            InlineCompletion::Move { target, .. } => {
 6889                let target = *target;
 6890
 6891                if let Some(position_map) = &self.last_position_map {
 6892                    if position_map
 6893                        .visible_row_range
 6894                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6895                        || !self.edit_prediction_requires_modifier()
 6896                    {
 6897                        self.unfold_ranges(&[target..target], true, false, cx);
 6898                        // Note that this is also done in vim's handler of the Tab action.
 6899                        self.change_selections(
 6900                            Some(Autoscroll::newest()),
 6901                            window,
 6902                            cx,
 6903                            |selections| {
 6904                                selections.select_anchor_ranges([target..target]);
 6905                            },
 6906                        );
 6907                        self.clear_row_highlights::<EditPredictionPreview>();
 6908
 6909                        self.edit_prediction_preview
 6910                            .set_previous_scroll_position(None);
 6911                    } else {
 6912                        self.edit_prediction_preview
 6913                            .set_previous_scroll_position(Some(
 6914                                position_map.snapshot.scroll_anchor,
 6915                            ));
 6916
 6917                        self.highlight_rows::<EditPredictionPreview>(
 6918                            target..target,
 6919                            cx.theme().colors().editor_highlighted_line_background,
 6920                            RowHighlightOptions {
 6921                                autoscroll: true,
 6922                                ..Default::default()
 6923                            },
 6924                            cx,
 6925                        );
 6926                        self.request_autoscroll(Autoscroll::fit(), cx);
 6927                    }
 6928                }
 6929            }
 6930            InlineCompletion::Edit { edits, .. } => {
 6931                if let Some(provider) = self.edit_prediction_provider() {
 6932                    provider.accept(cx);
 6933                }
 6934
 6935                // Store the transaction ID and selections before applying the edit
 6936                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6937
 6938                let snapshot = self.buffer.read(cx).snapshot(cx);
 6939                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6940
 6941                self.buffer.update(cx, |buffer, cx| {
 6942                    buffer.edit(edits.iter().cloned(), None, cx)
 6943                });
 6944
 6945                self.change_selections(None, window, cx, |s| {
 6946                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6947                });
 6948
 6949                let selections = self.selections.disjoint_anchors();
 6950                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6951                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6952                    if has_new_transaction {
 6953                        self.selection_history
 6954                            .insert_transaction(transaction_id_now, selections);
 6955                    }
 6956                }
 6957
 6958                self.update_visible_inline_completion(window, cx);
 6959                if self.active_inline_completion.is_none() {
 6960                    self.refresh_inline_completion(true, true, window, cx);
 6961                }
 6962
 6963                cx.notify();
 6964            }
 6965        }
 6966
 6967        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6968    }
 6969
 6970    pub fn accept_partial_inline_completion(
 6971        &mut self,
 6972        _: &AcceptPartialEditPrediction,
 6973        window: &mut Window,
 6974        cx: &mut Context<Self>,
 6975    ) {
 6976        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6977            return;
 6978        };
 6979        if self.selections.count() != 1 {
 6980            return;
 6981        }
 6982
 6983        self.report_inline_completion_event(
 6984            active_inline_completion.completion_id.clone(),
 6985            true,
 6986            cx,
 6987        );
 6988
 6989        match &active_inline_completion.completion {
 6990            InlineCompletion::Move { target, .. } => {
 6991                let target = *target;
 6992                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6993                    selections.select_anchor_ranges([target..target]);
 6994                });
 6995            }
 6996            InlineCompletion::Edit { edits, .. } => {
 6997                // Find an insertion that starts at the cursor position.
 6998                let snapshot = self.buffer.read(cx).snapshot(cx);
 6999                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7000                let insertion = edits.iter().find_map(|(range, text)| {
 7001                    let range = range.to_offset(&snapshot);
 7002                    if range.is_empty() && range.start == cursor_offset {
 7003                        Some(text)
 7004                    } else {
 7005                        None
 7006                    }
 7007                });
 7008
 7009                if let Some(text) = insertion {
 7010                    let mut partial_completion = text
 7011                        .chars()
 7012                        .by_ref()
 7013                        .take_while(|c| c.is_alphabetic())
 7014                        .collect::<String>();
 7015                    if partial_completion.is_empty() {
 7016                        partial_completion = text
 7017                            .chars()
 7018                            .by_ref()
 7019                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7020                            .collect::<String>();
 7021                    }
 7022
 7023                    cx.emit(EditorEvent::InputHandled {
 7024                        utf16_range_to_replace: None,
 7025                        text: partial_completion.clone().into(),
 7026                    });
 7027
 7028                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7029
 7030                    self.refresh_inline_completion(true, true, window, cx);
 7031                    cx.notify();
 7032                } else {
 7033                    self.accept_edit_prediction(&Default::default(), window, cx);
 7034                }
 7035            }
 7036        }
 7037    }
 7038
 7039    fn discard_inline_completion(
 7040        &mut self,
 7041        should_report_inline_completion_event: bool,
 7042        cx: &mut Context<Self>,
 7043    ) -> bool {
 7044        if should_report_inline_completion_event {
 7045            let completion_id = self
 7046                .active_inline_completion
 7047                .as_ref()
 7048                .and_then(|active_completion| active_completion.completion_id.clone());
 7049
 7050            self.report_inline_completion_event(completion_id, false, cx);
 7051        }
 7052
 7053        if let Some(provider) = self.edit_prediction_provider() {
 7054            provider.discard(cx);
 7055        }
 7056
 7057        self.take_active_inline_completion(cx)
 7058    }
 7059
 7060    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7061        let Some(provider) = self.edit_prediction_provider() else {
 7062            return;
 7063        };
 7064
 7065        let Some((_, buffer, _)) = self
 7066            .buffer
 7067            .read(cx)
 7068            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7069        else {
 7070            return;
 7071        };
 7072
 7073        let extension = buffer
 7074            .read(cx)
 7075            .file()
 7076            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7077
 7078        let event_type = match accepted {
 7079            true => "Edit Prediction Accepted",
 7080            false => "Edit Prediction Discarded",
 7081        };
 7082        telemetry::event!(
 7083            event_type,
 7084            provider = provider.name(),
 7085            prediction_id = id,
 7086            suggestion_accepted = accepted,
 7087            file_extension = extension,
 7088        );
 7089    }
 7090
 7091    pub fn has_active_inline_completion(&self) -> bool {
 7092        self.active_inline_completion.is_some()
 7093    }
 7094
 7095    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7096        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7097            return false;
 7098        };
 7099
 7100        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7101        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7102        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7103        true
 7104    }
 7105
 7106    /// Returns true when we're displaying the edit prediction popover below the cursor
 7107    /// like we are not previewing and the LSP autocomplete menu is visible
 7108    /// or we are in `when_holding_modifier` mode.
 7109    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7110        if self.edit_prediction_preview_is_active()
 7111            || !self.show_edit_predictions_in_menu()
 7112            || !self.edit_predictions_enabled()
 7113        {
 7114            return false;
 7115        }
 7116
 7117        if self.has_visible_completions_menu() {
 7118            return true;
 7119        }
 7120
 7121        has_completion && self.edit_prediction_requires_modifier()
 7122    }
 7123
 7124    fn handle_modifiers_changed(
 7125        &mut self,
 7126        modifiers: Modifiers,
 7127        position_map: &PositionMap,
 7128        window: &mut Window,
 7129        cx: &mut Context<Self>,
 7130    ) {
 7131        if self.show_edit_predictions_in_menu() {
 7132            self.update_edit_prediction_preview(&modifiers, window, cx);
 7133        }
 7134
 7135        self.update_selection_mode(&modifiers, position_map, window, cx);
 7136
 7137        let mouse_position = window.mouse_position();
 7138        if !position_map.text_hitbox.is_hovered(window) {
 7139            return;
 7140        }
 7141
 7142        self.update_hovered_link(
 7143            position_map.point_for_position(mouse_position),
 7144            &position_map.snapshot,
 7145            modifiers,
 7146            window,
 7147            cx,
 7148        )
 7149    }
 7150
 7151    fn multi_cursor_modifier(
 7152        cursor_event: bool,
 7153        modifiers: &Modifiers,
 7154        cx: &mut Context<Self>,
 7155    ) -> bool {
 7156        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7157        if cursor_event {
 7158            match multi_cursor_setting {
 7159                MultiCursorModifier::Alt => modifiers.alt,
 7160                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7161            }
 7162        } else {
 7163            match multi_cursor_setting {
 7164                MultiCursorModifier::Alt => modifiers.secondary(),
 7165                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7166            }
 7167        }
 7168    }
 7169
 7170    fn columnar_selection_modifiers(multi_cursor_modifier: bool, modifiers: &Modifiers) -> bool {
 7171        modifiers.shift && multi_cursor_modifier && modifiers.number_of_modifiers() == 2
 7172    }
 7173
 7174    fn update_selection_mode(
 7175        &mut self,
 7176        modifiers: &Modifiers,
 7177        position_map: &PositionMap,
 7178        window: &mut Window,
 7179        cx: &mut Context<Self>,
 7180    ) {
 7181        let multi_cursor_modifier = Self::multi_cursor_modifier(true, modifiers, cx);
 7182        if !Self::columnar_selection_modifiers(multi_cursor_modifier, modifiers)
 7183            || self.selections.pending.is_none()
 7184        {
 7185            return;
 7186        }
 7187
 7188        let mouse_position = window.mouse_position();
 7189        let point_for_position = position_map.point_for_position(mouse_position);
 7190        let position = point_for_position.previous_valid;
 7191
 7192        self.select(
 7193            SelectPhase::BeginColumnar {
 7194                position,
 7195                reset: false,
 7196                goal_column: point_for_position.exact_unclipped.column(),
 7197            },
 7198            window,
 7199            cx,
 7200        );
 7201    }
 7202
 7203    fn update_edit_prediction_preview(
 7204        &mut self,
 7205        modifiers: &Modifiers,
 7206        window: &mut Window,
 7207        cx: &mut Context<Self>,
 7208    ) {
 7209        let mut modifiers_held = false;
 7210        if let Some(accept_keystroke) = self
 7211            .accept_edit_prediction_keybind(false, window, cx)
 7212            .keystroke()
 7213        {
 7214            modifiers_held = modifiers_held
 7215                || (&accept_keystroke.modifiers == modifiers
 7216                    && accept_keystroke.modifiers.modified());
 7217        };
 7218        if let Some(accept_partial_keystroke) = self
 7219            .accept_edit_prediction_keybind(true, window, cx)
 7220            .keystroke()
 7221        {
 7222            modifiers_held = modifiers_held
 7223                || (&accept_partial_keystroke.modifiers == modifiers
 7224                    && accept_partial_keystroke.modifiers.modified());
 7225        }
 7226
 7227        if modifiers_held {
 7228            if matches!(
 7229                self.edit_prediction_preview,
 7230                EditPredictionPreview::Inactive { .. }
 7231            ) {
 7232                self.edit_prediction_preview = EditPredictionPreview::Active {
 7233                    previous_scroll_position: None,
 7234                    since: Instant::now(),
 7235                };
 7236
 7237                self.update_visible_inline_completion(window, cx);
 7238                cx.notify();
 7239            }
 7240        } else if let EditPredictionPreview::Active {
 7241            previous_scroll_position,
 7242            since,
 7243        } = self.edit_prediction_preview
 7244        {
 7245            if let (Some(previous_scroll_position), Some(position_map)) =
 7246                (previous_scroll_position, self.last_position_map.as_ref())
 7247            {
 7248                self.set_scroll_position(
 7249                    previous_scroll_position
 7250                        .scroll_position(&position_map.snapshot.display_snapshot),
 7251                    window,
 7252                    cx,
 7253                );
 7254            }
 7255
 7256            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7257                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7258            };
 7259            self.clear_row_highlights::<EditPredictionPreview>();
 7260            self.update_visible_inline_completion(window, cx);
 7261            cx.notify();
 7262        }
 7263    }
 7264
 7265    fn update_visible_inline_completion(
 7266        &mut self,
 7267        _window: &mut Window,
 7268        cx: &mut Context<Self>,
 7269    ) -> Option<()> {
 7270        let selection = self.selections.newest_anchor();
 7271        let cursor = selection.head();
 7272        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7273        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7274        let excerpt_id = cursor.excerpt_id;
 7275
 7276        let show_in_menu = self.show_edit_predictions_in_menu();
 7277        let completions_menu_has_precedence = !show_in_menu
 7278            && (self.context_menu.borrow().is_some()
 7279                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7280
 7281        if completions_menu_has_precedence
 7282            || !offset_selection.is_empty()
 7283            || self
 7284                .active_inline_completion
 7285                .as_ref()
 7286                .map_or(false, |completion| {
 7287                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7288                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7289                    !invalidation_range.contains(&offset_selection.head())
 7290                })
 7291        {
 7292            self.discard_inline_completion(false, cx);
 7293            return None;
 7294        }
 7295
 7296        self.take_active_inline_completion(cx);
 7297        let Some(provider) = self.edit_prediction_provider() else {
 7298            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7299            return None;
 7300        };
 7301
 7302        let (buffer, cursor_buffer_position) =
 7303            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7304
 7305        self.edit_prediction_settings =
 7306            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7307
 7308        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7309
 7310        if self.edit_prediction_indent_conflict {
 7311            let cursor_point = cursor.to_point(&multibuffer);
 7312
 7313            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7314
 7315            if let Some((_, indent)) = indents.iter().next() {
 7316                if indent.len == cursor_point.column {
 7317                    self.edit_prediction_indent_conflict = false;
 7318                }
 7319            }
 7320        }
 7321
 7322        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7323        let edits = inline_completion
 7324            .edits
 7325            .into_iter()
 7326            .flat_map(|(range, new_text)| {
 7327                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7328                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7329                Some((start..end, new_text))
 7330            })
 7331            .collect::<Vec<_>>();
 7332        if edits.is_empty() {
 7333            return None;
 7334        }
 7335
 7336        let first_edit_start = edits.first().unwrap().0.start;
 7337        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7338        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7339
 7340        let last_edit_end = edits.last().unwrap().0.end;
 7341        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7342        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7343
 7344        let cursor_row = cursor.to_point(&multibuffer).row;
 7345
 7346        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7347
 7348        let mut inlay_ids = Vec::new();
 7349        let invalidation_row_range;
 7350        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7351            Some(cursor_row..edit_end_row)
 7352        } else if cursor_row > edit_end_row {
 7353            Some(edit_start_row..cursor_row)
 7354        } else {
 7355            None
 7356        };
 7357        let is_move =
 7358            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7359        let completion = if is_move {
 7360            invalidation_row_range =
 7361                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7362            let target = first_edit_start;
 7363            InlineCompletion::Move { target, snapshot }
 7364        } else {
 7365            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7366                && !self.inline_completions_hidden_for_vim_mode;
 7367
 7368            if show_completions_in_buffer {
 7369                if edits
 7370                    .iter()
 7371                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7372                {
 7373                    let mut inlays = Vec::new();
 7374                    for (range, new_text) in &edits {
 7375                        let inlay = Inlay::inline_completion(
 7376                            post_inc(&mut self.next_inlay_id),
 7377                            range.start,
 7378                            new_text.as_str(),
 7379                        );
 7380                        inlay_ids.push(inlay.id);
 7381                        inlays.push(inlay);
 7382                    }
 7383
 7384                    self.splice_inlays(&[], inlays, cx);
 7385                } else {
 7386                    let background_color = cx.theme().status().deleted_background;
 7387                    self.highlight_text::<InlineCompletionHighlight>(
 7388                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7389                        HighlightStyle {
 7390                            background_color: Some(background_color),
 7391                            ..Default::default()
 7392                        },
 7393                        cx,
 7394                    );
 7395                }
 7396            }
 7397
 7398            invalidation_row_range = edit_start_row..edit_end_row;
 7399
 7400            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7401                if provider.show_tab_accept_marker() {
 7402                    EditDisplayMode::TabAccept
 7403                } else {
 7404                    EditDisplayMode::Inline
 7405                }
 7406            } else {
 7407                EditDisplayMode::DiffPopover
 7408            };
 7409
 7410            InlineCompletion::Edit {
 7411                edits,
 7412                edit_preview: inline_completion.edit_preview,
 7413                display_mode,
 7414                snapshot,
 7415            }
 7416        };
 7417
 7418        let invalidation_range = multibuffer
 7419            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7420            ..multibuffer.anchor_after(Point::new(
 7421                invalidation_row_range.end,
 7422                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7423            ));
 7424
 7425        self.stale_inline_completion_in_menu = None;
 7426        self.active_inline_completion = Some(InlineCompletionState {
 7427            inlay_ids,
 7428            completion,
 7429            completion_id: inline_completion.id,
 7430            invalidation_range,
 7431        });
 7432
 7433        cx.notify();
 7434
 7435        Some(())
 7436    }
 7437
 7438    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7439        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7440    }
 7441
 7442    fn clear_tasks(&mut self) {
 7443        self.tasks.clear()
 7444    }
 7445
 7446    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7447        if self.tasks.insert(key, value).is_some() {
 7448            // This case should hopefully be rare, but just in case...
 7449            log::error!(
 7450                "multiple different run targets found on a single line, only the last target will be rendered"
 7451            )
 7452        }
 7453    }
 7454
 7455    /// Get all display points of breakpoints that will be rendered within editor
 7456    ///
 7457    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7458    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7459    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7460    fn active_breakpoints(
 7461        &self,
 7462        range: Range<DisplayRow>,
 7463        window: &mut Window,
 7464        cx: &mut Context<Self>,
 7465    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7466        let mut breakpoint_display_points = HashMap::default();
 7467
 7468        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7469            return breakpoint_display_points;
 7470        };
 7471
 7472        let snapshot = self.snapshot(window, cx);
 7473
 7474        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7475        let Some(project) = self.project.as_ref() else {
 7476            return breakpoint_display_points;
 7477        };
 7478
 7479        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7480            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7481
 7482        for (buffer_snapshot, range, excerpt_id) in
 7483            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7484        {
 7485            let Some(buffer) = project
 7486                .read(cx)
 7487                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7488            else {
 7489                continue;
 7490            };
 7491            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7492                &buffer,
 7493                Some(
 7494                    buffer_snapshot.anchor_before(range.start)
 7495                        ..buffer_snapshot.anchor_after(range.end),
 7496                ),
 7497                buffer_snapshot,
 7498                cx,
 7499            );
 7500            for (breakpoint, state) in breakpoints {
 7501                let multi_buffer_anchor =
 7502                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7503                let position = multi_buffer_anchor
 7504                    .to_point(&multi_buffer_snapshot)
 7505                    .to_display_point(&snapshot);
 7506
 7507                breakpoint_display_points.insert(
 7508                    position.row(),
 7509                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7510                );
 7511            }
 7512        }
 7513
 7514        breakpoint_display_points
 7515    }
 7516
 7517    fn breakpoint_context_menu(
 7518        &self,
 7519        anchor: Anchor,
 7520        window: &mut Window,
 7521        cx: &mut Context<Self>,
 7522    ) -> Entity<ui::ContextMenu> {
 7523        let weak_editor = cx.weak_entity();
 7524        let focus_handle = self.focus_handle(cx);
 7525
 7526        let row = self
 7527            .buffer
 7528            .read(cx)
 7529            .snapshot(cx)
 7530            .summary_for_anchor::<Point>(&anchor)
 7531            .row;
 7532
 7533        let breakpoint = self
 7534            .breakpoint_at_row(row, window, cx)
 7535            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7536
 7537        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7538            "Edit Log Breakpoint"
 7539        } else {
 7540            "Set Log Breakpoint"
 7541        };
 7542
 7543        let condition_breakpoint_msg = if breakpoint
 7544            .as_ref()
 7545            .is_some_and(|bp| bp.1.condition.is_some())
 7546        {
 7547            "Edit Condition Breakpoint"
 7548        } else {
 7549            "Set Condition Breakpoint"
 7550        };
 7551
 7552        let hit_condition_breakpoint_msg = if breakpoint
 7553            .as_ref()
 7554            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7555        {
 7556            "Edit Hit Condition Breakpoint"
 7557        } else {
 7558            "Set Hit Condition Breakpoint"
 7559        };
 7560
 7561        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7562            "Unset Breakpoint"
 7563        } else {
 7564            "Set Breakpoint"
 7565        };
 7566
 7567        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7568
 7569        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7570            BreakpointState::Enabled => Some("Disable"),
 7571            BreakpointState::Disabled => Some("Enable"),
 7572        });
 7573
 7574        let (anchor, breakpoint) =
 7575            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7576
 7577        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7578            menu.on_blur_subscription(Subscription::new(|| {}))
 7579                .context(focus_handle)
 7580                .when(run_to_cursor, |this| {
 7581                    let weak_editor = weak_editor.clone();
 7582                    this.entry("Run to cursor", None, move |window, cx| {
 7583                        weak_editor
 7584                            .update(cx, |editor, cx| {
 7585                                editor.change_selections(None, window, cx, |s| {
 7586                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7587                                });
 7588                            })
 7589                            .ok();
 7590
 7591                        window.dispatch_action(Box::new(RunToCursor), cx);
 7592                    })
 7593                    .separator()
 7594                })
 7595                .when_some(toggle_state_msg, |this, msg| {
 7596                    this.entry(msg, None, {
 7597                        let weak_editor = weak_editor.clone();
 7598                        let breakpoint = breakpoint.clone();
 7599                        move |_window, cx| {
 7600                            weak_editor
 7601                                .update(cx, |this, cx| {
 7602                                    this.edit_breakpoint_at_anchor(
 7603                                        anchor,
 7604                                        breakpoint.as_ref().clone(),
 7605                                        BreakpointEditAction::InvertState,
 7606                                        cx,
 7607                                    );
 7608                                })
 7609                                .log_err();
 7610                        }
 7611                    })
 7612                })
 7613                .entry(set_breakpoint_msg, None, {
 7614                    let weak_editor = weak_editor.clone();
 7615                    let breakpoint = breakpoint.clone();
 7616                    move |_window, cx| {
 7617                        weak_editor
 7618                            .update(cx, |this, cx| {
 7619                                this.edit_breakpoint_at_anchor(
 7620                                    anchor,
 7621                                    breakpoint.as_ref().clone(),
 7622                                    BreakpointEditAction::Toggle,
 7623                                    cx,
 7624                                );
 7625                            })
 7626                            .log_err();
 7627                    }
 7628                })
 7629                .entry(log_breakpoint_msg, None, {
 7630                    let breakpoint = breakpoint.clone();
 7631                    let weak_editor = weak_editor.clone();
 7632                    move |window, cx| {
 7633                        weak_editor
 7634                            .update(cx, |this, cx| {
 7635                                this.add_edit_breakpoint_block(
 7636                                    anchor,
 7637                                    breakpoint.as_ref(),
 7638                                    BreakpointPromptEditAction::Log,
 7639                                    window,
 7640                                    cx,
 7641                                );
 7642                            })
 7643                            .log_err();
 7644                    }
 7645                })
 7646                .entry(condition_breakpoint_msg, None, {
 7647                    let breakpoint = breakpoint.clone();
 7648                    let weak_editor = weak_editor.clone();
 7649                    move |window, cx| {
 7650                        weak_editor
 7651                            .update(cx, |this, cx| {
 7652                                this.add_edit_breakpoint_block(
 7653                                    anchor,
 7654                                    breakpoint.as_ref(),
 7655                                    BreakpointPromptEditAction::Condition,
 7656                                    window,
 7657                                    cx,
 7658                                );
 7659                            })
 7660                            .log_err();
 7661                    }
 7662                })
 7663                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7664                    weak_editor
 7665                        .update(cx, |this, cx| {
 7666                            this.add_edit_breakpoint_block(
 7667                                anchor,
 7668                                breakpoint.as_ref(),
 7669                                BreakpointPromptEditAction::HitCondition,
 7670                                window,
 7671                                cx,
 7672                            );
 7673                        })
 7674                        .log_err();
 7675                })
 7676        })
 7677    }
 7678
 7679    fn render_breakpoint(
 7680        &self,
 7681        position: Anchor,
 7682        row: DisplayRow,
 7683        breakpoint: &Breakpoint,
 7684        state: Option<BreakpointSessionState>,
 7685        cx: &mut Context<Self>,
 7686    ) -> IconButton {
 7687        let is_rejected = state.is_some_and(|s| !s.verified);
 7688        // Is it a breakpoint that shows up when hovering over gutter?
 7689        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7690            (false, false),
 7691            |PhantomBreakpointIndicator {
 7692                 is_active,
 7693                 display_row,
 7694                 collides_with_existing_breakpoint,
 7695             }| {
 7696                (
 7697                    is_active && display_row == row,
 7698                    collides_with_existing_breakpoint,
 7699                )
 7700            },
 7701        );
 7702
 7703        let (color, icon) = {
 7704            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7705                (false, false) => ui::IconName::DebugBreakpoint,
 7706                (true, false) => ui::IconName::DebugLogBreakpoint,
 7707                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7708                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7709            };
 7710
 7711            let color = if is_phantom {
 7712                Color::Hint
 7713            } else if is_rejected {
 7714                Color::Disabled
 7715            } else {
 7716                Color::Debugger
 7717            };
 7718
 7719            (color, icon)
 7720        };
 7721
 7722        let breakpoint = Arc::from(breakpoint.clone());
 7723
 7724        let alt_as_text = gpui::Keystroke {
 7725            modifiers: Modifiers::secondary_key(),
 7726            ..Default::default()
 7727        };
 7728        let primary_action_text = if breakpoint.is_disabled() {
 7729            "Enable breakpoint"
 7730        } else if is_phantom && !collides_with_existing {
 7731            "Set breakpoint"
 7732        } else {
 7733            "Unset breakpoint"
 7734        };
 7735        let focus_handle = self.focus_handle.clone();
 7736
 7737        let meta = if is_rejected {
 7738            SharedString::from("No executable code is associated with this line.")
 7739        } else if collides_with_existing && !breakpoint.is_disabled() {
 7740            SharedString::from(format!(
 7741                "{alt_as_text}-click to disable,\nright-click for more options."
 7742            ))
 7743        } else {
 7744            SharedString::from("Right-click for more options.")
 7745        };
 7746        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7747            .icon_size(IconSize::XSmall)
 7748            .size(ui::ButtonSize::None)
 7749            .when(is_rejected, |this| {
 7750                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7751            })
 7752            .icon_color(color)
 7753            .style(ButtonStyle::Transparent)
 7754            .on_click(cx.listener({
 7755                let breakpoint = breakpoint.clone();
 7756
 7757                move |editor, event: &ClickEvent, window, cx| {
 7758                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7759                        BreakpointEditAction::InvertState
 7760                    } else {
 7761                        BreakpointEditAction::Toggle
 7762                    };
 7763
 7764                    window.focus(&editor.focus_handle(cx));
 7765                    editor.edit_breakpoint_at_anchor(
 7766                        position,
 7767                        breakpoint.as_ref().clone(),
 7768                        edit_action,
 7769                        cx,
 7770                    );
 7771                }
 7772            }))
 7773            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7774                editor.set_breakpoint_context_menu(
 7775                    row,
 7776                    Some(position),
 7777                    event.down.position,
 7778                    window,
 7779                    cx,
 7780                );
 7781            }))
 7782            .tooltip(move |window, cx| {
 7783                Tooltip::with_meta_in(
 7784                    primary_action_text,
 7785                    Some(&ToggleBreakpoint),
 7786                    meta.clone(),
 7787                    &focus_handle,
 7788                    window,
 7789                    cx,
 7790                )
 7791            })
 7792    }
 7793
 7794    fn build_tasks_context(
 7795        project: &Entity<Project>,
 7796        buffer: &Entity<Buffer>,
 7797        buffer_row: u32,
 7798        tasks: &Arc<RunnableTasks>,
 7799        cx: &mut Context<Self>,
 7800    ) -> Task<Option<task::TaskContext>> {
 7801        let position = Point::new(buffer_row, tasks.column);
 7802        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7803        let location = Location {
 7804            buffer: buffer.clone(),
 7805            range: range_start..range_start,
 7806        };
 7807        // Fill in the environmental variables from the tree-sitter captures
 7808        let mut captured_task_variables = TaskVariables::default();
 7809        for (capture_name, value) in tasks.extra_variables.clone() {
 7810            captured_task_variables.insert(
 7811                task::VariableName::Custom(capture_name.into()),
 7812                value.clone(),
 7813            );
 7814        }
 7815        project.update(cx, |project, cx| {
 7816            project.task_store().update(cx, |task_store, cx| {
 7817                task_store.task_context_for_location(captured_task_variables, location, cx)
 7818            })
 7819        })
 7820    }
 7821
 7822    pub fn spawn_nearest_task(
 7823        &mut self,
 7824        action: &SpawnNearestTask,
 7825        window: &mut Window,
 7826        cx: &mut Context<Self>,
 7827    ) {
 7828        let Some((workspace, _)) = self.workspace.clone() else {
 7829            return;
 7830        };
 7831        let Some(project) = self.project.clone() else {
 7832            return;
 7833        };
 7834
 7835        // Try to find a closest, enclosing node using tree-sitter that has a
 7836        // task
 7837        let Some((buffer, buffer_row, tasks)) = self
 7838            .find_enclosing_node_task(cx)
 7839            // Or find the task that's closest in row-distance.
 7840            .or_else(|| self.find_closest_task(cx))
 7841        else {
 7842            return;
 7843        };
 7844
 7845        let reveal_strategy = action.reveal;
 7846        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7847        cx.spawn_in(window, async move |_, cx| {
 7848            let context = task_context.await?;
 7849            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7850
 7851            let resolved = &mut resolved_task.resolved;
 7852            resolved.reveal = reveal_strategy;
 7853
 7854            workspace
 7855                .update_in(cx, |workspace, window, cx| {
 7856                    workspace.schedule_resolved_task(
 7857                        task_source_kind,
 7858                        resolved_task,
 7859                        false,
 7860                        window,
 7861                        cx,
 7862                    );
 7863                })
 7864                .ok()
 7865        })
 7866        .detach();
 7867    }
 7868
 7869    fn find_closest_task(
 7870        &mut self,
 7871        cx: &mut Context<Self>,
 7872    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7873        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7874
 7875        let ((buffer_id, row), tasks) = self
 7876            .tasks
 7877            .iter()
 7878            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7879
 7880        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7881        let tasks = Arc::new(tasks.to_owned());
 7882        Some((buffer, *row, tasks))
 7883    }
 7884
 7885    fn find_enclosing_node_task(
 7886        &mut self,
 7887        cx: &mut Context<Self>,
 7888    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7889        let snapshot = self.buffer.read(cx).snapshot(cx);
 7890        let offset = self.selections.newest::<usize>(cx).head();
 7891        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7892        let buffer_id = excerpt.buffer().remote_id();
 7893
 7894        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7895        let mut cursor = layer.node().walk();
 7896
 7897        while cursor.goto_first_child_for_byte(offset).is_some() {
 7898            if cursor.node().end_byte() == offset {
 7899                cursor.goto_next_sibling();
 7900            }
 7901        }
 7902
 7903        // Ascend to the smallest ancestor that contains the range and has a task.
 7904        loop {
 7905            let node = cursor.node();
 7906            let node_range = node.byte_range();
 7907            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7908
 7909            // Check if this node contains our offset
 7910            if node_range.start <= offset && node_range.end >= offset {
 7911                // If it contains offset, check for task
 7912                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7913                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7914                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7915                }
 7916            }
 7917
 7918            if !cursor.goto_parent() {
 7919                break;
 7920            }
 7921        }
 7922        None
 7923    }
 7924
 7925    fn render_run_indicator(
 7926        &self,
 7927        _style: &EditorStyle,
 7928        is_active: bool,
 7929        row: DisplayRow,
 7930        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7931        cx: &mut Context<Self>,
 7932    ) -> IconButton {
 7933        let color = Color::Muted;
 7934        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7935
 7936        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7937            .shape(ui::IconButtonShape::Square)
 7938            .icon_size(IconSize::XSmall)
 7939            .icon_color(color)
 7940            .toggle_state(is_active)
 7941            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7942                let quick_launch = e.down.button == MouseButton::Left;
 7943                window.focus(&editor.focus_handle(cx));
 7944                editor.toggle_code_actions(
 7945                    &ToggleCodeActions {
 7946                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 7947                        quick_launch,
 7948                    },
 7949                    window,
 7950                    cx,
 7951                );
 7952            }))
 7953            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7954                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7955            }))
 7956    }
 7957
 7958    pub fn context_menu_visible(&self) -> bool {
 7959        !self.edit_prediction_preview_is_active()
 7960            && self
 7961                .context_menu
 7962                .borrow()
 7963                .as_ref()
 7964                .map_or(false, |menu| menu.visible())
 7965    }
 7966
 7967    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7968        self.context_menu
 7969            .borrow()
 7970            .as_ref()
 7971            .map(|menu| menu.origin())
 7972    }
 7973
 7974    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7975        self.context_menu_options = Some(options);
 7976    }
 7977
 7978    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7979    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7980
 7981    fn render_edit_prediction_popover(
 7982        &mut self,
 7983        text_bounds: &Bounds<Pixels>,
 7984        content_origin: gpui::Point<Pixels>,
 7985        right_margin: Pixels,
 7986        editor_snapshot: &EditorSnapshot,
 7987        visible_row_range: Range<DisplayRow>,
 7988        scroll_top: f32,
 7989        scroll_bottom: f32,
 7990        line_layouts: &[LineWithInvisibles],
 7991        line_height: Pixels,
 7992        scroll_pixel_position: gpui::Point<Pixels>,
 7993        newest_selection_head: Option<DisplayPoint>,
 7994        editor_width: Pixels,
 7995        style: &EditorStyle,
 7996        window: &mut Window,
 7997        cx: &mut App,
 7998    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7999        if self.mode().is_minimap() {
 8000            return None;
 8001        }
 8002        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8003
 8004        if self.edit_prediction_visible_in_cursor_popover(true) {
 8005            return None;
 8006        }
 8007
 8008        match &active_inline_completion.completion {
 8009            InlineCompletion::Move { target, .. } => {
 8010                let target_display_point = target.to_display_point(editor_snapshot);
 8011
 8012                if self.edit_prediction_requires_modifier() {
 8013                    if !self.edit_prediction_preview_is_active() {
 8014                        return None;
 8015                    }
 8016
 8017                    self.render_edit_prediction_modifier_jump_popover(
 8018                        text_bounds,
 8019                        content_origin,
 8020                        visible_row_range,
 8021                        line_layouts,
 8022                        line_height,
 8023                        scroll_pixel_position,
 8024                        newest_selection_head,
 8025                        target_display_point,
 8026                        window,
 8027                        cx,
 8028                    )
 8029                } else {
 8030                    self.render_edit_prediction_eager_jump_popover(
 8031                        text_bounds,
 8032                        content_origin,
 8033                        editor_snapshot,
 8034                        visible_row_range,
 8035                        scroll_top,
 8036                        scroll_bottom,
 8037                        line_height,
 8038                        scroll_pixel_position,
 8039                        target_display_point,
 8040                        editor_width,
 8041                        window,
 8042                        cx,
 8043                    )
 8044                }
 8045            }
 8046            InlineCompletion::Edit {
 8047                display_mode: EditDisplayMode::Inline,
 8048                ..
 8049            } => None,
 8050            InlineCompletion::Edit {
 8051                display_mode: EditDisplayMode::TabAccept,
 8052                edits,
 8053                ..
 8054            } => {
 8055                let range = &edits.first()?.0;
 8056                let target_display_point = range.end.to_display_point(editor_snapshot);
 8057
 8058                self.render_edit_prediction_end_of_line_popover(
 8059                    "Accept",
 8060                    editor_snapshot,
 8061                    visible_row_range,
 8062                    target_display_point,
 8063                    line_height,
 8064                    scroll_pixel_position,
 8065                    content_origin,
 8066                    editor_width,
 8067                    window,
 8068                    cx,
 8069                )
 8070            }
 8071            InlineCompletion::Edit {
 8072                edits,
 8073                edit_preview,
 8074                display_mode: EditDisplayMode::DiffPopover,
 8075                snapshot,
 8076            } => self.render_edit_prediction_diff_popover(
 8077                text_bounds,
 8078                content_origin,
 8079                right_margin,
 8080                editor_snapshot,
 8081                visible_row_range,
 8082                line_layouts,
 8083                line_height,
 8084                scroll_pixel_position,
 8085                newest_selection_head,
 8086                editor_width,
 8087                style,
 8088                edits,
 8089                edit_preview,
 8090                snapshot,
 8091                window,
 8092                cx,
 8093            ),
 8094        }
 8095    }
 8096
 8097    fn render_edit_prediction_modifier_jump_popover(
 8098        &mut self,
 8099        text_bounds: &Bounds<Pixels>,
 8100        content_origin: gpui::Point<Pixels>,
 8101        visible_row_range: Range<DisplayRow>,
 8102        line_layouts: &[LineWithInvisibles],
 8103        line_height: Pixels,
 8104        scroll_pixel_position: gpui::Point<Pixels>,
 8105        newest_selection_head: Option<DisplayPoint>,
 8106        target_display_point: DisplayPoint,
 8107        window: &mut Window,
 8108        cx: &mut App,
 8109    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8110        let scrolled_content_origin =
 8111            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8112
 8113        const SCROLL_PADDING_Y: Pixels = px(12.);
 8114
 8115        if target_display_point.row() < visible_row_range.start {
 8116            return self.render_edit_prediction_scroll_popover(
 8117                |_| SCROLL_PADDING_Y,
 8118                IconName::ArrowUp,
 8119                visible_row_range,
 8120                line_layouts,
 8121                newest_selection_head,
 8122                scrolled_content_origin,
 8123                window,
 8124                cx,
 8125            );
 8126        } else if target_display_point.row() >= visible_row_range.end {
 8127            return self.render_edit_prediction_scroll_popover(
 8128                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8129                IconName::ArrowDown,
 8130                visible_row_range,
 8131                line_layouts,
 8132                newest_selection_head,
 8133                scrolled_content_origin,
 8134                window,
 8135                cx,
 8136            );
 8137        }
 8138
 8139        const POLE_WIDTH: Pixels = px(2.);
 8140
 8141        let line_layout =
 8142            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8143        let target_column = target_display_point.column() as usize;
 8144
 8145        let target_x = line_layout.x_for_index(target_column);
 8146        let target_y =
 8147            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8148
 8149        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8150
 8151        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8152        border_color.l += 0.001;
 8153
 8154        let mut element = v_flex()
 8155            .items_end()
 8156            .when(flag_on_right, |el| el.items_start())
 8157            .child(if flag_on_right {
 8158                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8159                    .rounded_bl(px(0.))
 8160                    .rounded_tl(px(0.))
 8161                    .border_l_2()
 8162                    .border_color(border_color)
 8163            } else {
 8164                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8165                    .rounded_br(px(0.))
 8166                    .rounded_tr(px(0.))
 8167                    .border_r_2()
 8168                    .border_color(border_color)
 8169            })
 8170            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8171            .into_any();
 8172
 8173        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8174
 8175        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8176            - point(
 8177                if flag_on_right {
 8178                    POLE_WIDTH
 8179                } else {
 8180                    size.width - POLE_WIDTH
 8181                },
 8182                size.height - line_height,
 8183            );
 8184
 8185        origin.x = origin.x.max(content_origin.x);
 8186
 8187        element.prepaint_at(origin, window, cx);
 8188
 8189        Some((element, origin))
 8190    }
 8191
 8192    fn render_edit_prediction_scroll_popover(
 8193        &mut self,
 8194        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8195        scroll_icon: IconName,
 8196        visible_row_range: Range<DisplayRow>,
 8197        line_layouts: &[LineWithInvisibles],
 8198        newest_selection_head: Option<DisplayPoint>,
 8199        scrolled_content_origin: gpui::Point<Pixels>,
 8200        window: &mut Window,
 8201        cx: &mut App,
 8202    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8203        let mut element = self
 8204            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8205            .into_any();
 8206
 8207        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8208
 8209        let cursor = newest_selection_head?;
 8210        let cursor_row_layout =
 8211            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8212        let cursor_column = cursor.column() as usize;
 8213
 8214        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8215
 8216        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8217
 8218        element.prepaint_at(origin, window, cx);
 8219        Some((element, origin))
 8220    }
 8221
 8222    fn render_edit_prediction_eager_jump_popover(
 8223        &mut self,
 8224        text_bounds: &Bounds<Pixels>,
 8225        content_origin: gpui::Point<Pixels>,
 8226        editor_snapshot: &EditorSnapshot,
 8227        visible_row_range: Range<DisplayRow>,
 8228        scroll_top: f32,
 8229        scroll_bottom: f32,
 8230        line_height: Pixels,
 8231        scroll_pixel_position: gpui::Point<Pixels>,
 8232        target_display_point: DisplayPoint,
 8233        editor_width: Pixels,
 8234        window: &mut Window,
 8235        cx: &mut App,
 8236    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8237        if target_display_point.row().as_f32() < scroll_top {
 8238            let mut element = self
 8239                .render_edit_prediction_line_popover(
 8240                    "Jump to Edit",
 8241                    Some(IconName::ArrowUp),
 8242                    window,
 8243                    cx,
 8244                )?
 8245                .into_any();
 8246
 8247            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8248            let offset = point(
 8249                (text_bounds.size.width - size.width) / 2.,
 8250                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8251            );
 8252
 8253            let origin = text_bounds.origin + offset;
 8254            element.prepaint_at(origin, window, cx);
 8255            Some((element, origin))
 8256        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8257            let mut element = self
 8258                .render_edit_prediction_line_popover(
 8259                    "Jump to Edit",
 8260                    Some(IconName::ArrowDown),
 8261                    window,
 8262                    cx,
 8263                )?
 8264                .into_any();
 8265
 8266            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8267            let offset = point(
 8268                (text_bounds.size.width - size.width) / 2.,
 8269                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8270            );
 8271
 8272            let origin = text_bounds.origin + offset;
 8273            element.prepaint_at(origin, window, cx);
 8274            Some((element, origin))
 8275        } else {
 8276            self.render_edit_prediction_end_of_line_popover(
 8277                "Jump to Edit",
 8278                editor_snapshot,
 8279                visible_row_range,
 8280                target_display_point,
 8281                line_height,
 8282                scroll_pixel_position,
 8283                content_origin,
 8284                editor_width,
 8285                window,
 8286                cx,
 8287            )
 8288        }
 8289    }
 8290
 8291    fn render_edit_prediction_end_of_line_popover(
 8292        self: &mut Editor,
 8293        label: &'static str,
 8294        editor_snapshot: &EditorSnapshot,
 8295        visible_row_range: Range<DisplayRow>,
 8296        target_display_point: DisplayPoint,
 8297        line_height: Pixels,
 8298        scroll_pixel_position: gpui::Point<Pixels>,
 8299        content_origin: gpui::Point<Pixels>,
 8300        editor_width: Pixels,
 8301        window: &mut Window,
 8302        cx: &mut App,
 8303    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8304        let target_line_end = DisplayPoint::new(
 8305            target_display_point.row(),
 8306            editor_snapshot.line_len(target_display_point.row()),
 8307        );
 8308
 8309        let mut element = self
 8310            .render_edit_prediction_line_popover(label, None, window, cx)?
 8311            .into_any();
 8312
 8313        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8314
 8315        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8316
 8317        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8318        let mut origin = start_point
 8319            + line_origin
 8320            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8321        origin.x = origin.x.max(content_origin.x);
 8322
 8323        let max_x = content_origin.x + editor_width - size.width;
 8324
 8325        if origin.x > max_x {
 8326            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8327
 8328            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8329                origin.y += offset;
 8330                IconName::ArrowUp
 8331            } else {
 8332                origin.y -= offset;
 8333                IconName::ArrowDown
 8334            };
 8335
 8336            element = self
 8337                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8338                .into_any();
 8339
 8340            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8341
 8342            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8343        }
 8344
 8345        element.prepaint_at(origin, window, cx);
 8346        Some((element, origin))
 8347    }
 8348
 8349    fn render_edit_prediction_diff_popover(
 8350        self: &Editor,
 8351        text_bounds: &Bounds<Pixels>,
 8352        content_origin: gpui::Point<Pixels>,
 8353        right_margin: Pixels,
 8354        editor_snapshot: &EditorSnapshot,
 8355        visible_row_range: Range<DisplayRow>,
 8356        line_layouts: &[LineWithInvisibles],
 8357        line_height: Pixels,
 8358        scroll_pixel_position: gpui::Point<Pixels>,
 8359        newest_selection_head: Option<DisplayPoint>,
 8360        editor_width: Pixels,
 8361        style: &EditorStyle,
 8362        edits: &Vec<(Range<Anchor>, String)>,
 8363        edit_preview: &Option<language::EditPreview>,
 8364        snapshot: &language::BufferSnapshot,
 8365        window: &mut Window,
 8366        cx: &mut App,
 8367    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8368        let edit_start = edits
 8369            .first()
 8370            .unwrap()
 8371            .0
 8372            .start
 8373            .to_display_point(editor_snapshot);
 8374        let edit_end = edits
 8375            .last()
 8376            .unwrap()
 8377            .0
 8378            .end
 8379            .to_display_point(editor_snapshot);
 8380
 8381        let is_visible = visible_row_range.contains(&edit_start.row())
 8382            || visible_row_range.contains(&edit_end.row());
 8383        if !is_visible {
 8384            return None;
 8385        }
 8386
 8387        let highlighted_edits =
 8388            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8389
 8390        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8391        let line_count = highlighted_edits.text.lines().count();
 8392
 8393        const BORDER_WIDTH: Pixels = px(1.);
 8394
 8395        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8396        let has_keybind = keybind.is_some();
 8397
 8398        let mut element = h_flex()
 8399            .items_start()
 8400            .child(
 8401                h_flex()
 8402                    .bg(cx.theme().colors().editor_background)
 8403                    .border(BORDER_WIDTH)
 8404                    .shadow_sm()
 8405                    .border_color(cx.theme().colors().border)
 8406                    .rounded_l_lg()
 8407                    .when(line_count > 1, |el| el.rounded_br_lg())
 8408                    .pr_1()
 8409                    .child(styled_text),
 8410            )
 8411            .child(
 8412                h_flex()
 8413                    .h(line_height + BORDER_WIDTH * 2.)
 8414                    .px_1p5()
 8415                    .gap_1()
 8416                    // Workaround: For some reason, there's a gap if we don't do this
 8417                    .ml(-BORDER_WIDTH)
 8418                    .shadow(vec![gpui::BoxShadow {
 8419                        color: gpui::black().opacity(0.05),
 8420                        offset: point(px(1.), px(1.)),
 8421                        blur_radius: px(2.),
 8422                        spread_radius: px(0.),
 8423                    }])
 8424                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8425                    .border(BORDER_WIDTH)
 8426                    .border_color(cx.theme().colors().border)
 8427                    .rounded_r_lg()
 8428                    .id("edit_prediction_diff_popover_keybind")
 8429                    .when(!has_keybind, |el| {
 8430                        let status_colors = cx.theme().status();
 8431
 8432                        el.bg(status_colors.error_background)
 8433                            .border_color(status_colors.error.opacity(0.6))
 8434                            .child(Icon::new(IconName::Info).color(Color::Error))
 8435                            .cursor_default()
 8436                            .hoverable_tooltip(move |_window, cx| {
 8437                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8438                            })
 8439                    })
 8440                    .children(keybind),
 8441            )
 8442            .into_any();
 8443
 8444        let longest_row =
 8445            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8446        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8447            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8448        } else {
 8449            layout_line(
 8450                longest_row,
 8451                editor_snapshot,
 8452                style,
 8453                editor_width,
 8454                |_| false,
 8455                window,
 8456                cx,
 8457            )
 8458            .width
 8459        };
 8460
 8461        let viewport_bounds =
 8462            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8463                right: -right_margin,
 8464                ..Default::default()
 8465            });
 8466
 8467        let x_after_longest =
 8468            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8469                - scroll_pixel_position.x;
 8470
 8471        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8472
 8473        // Fully visible if it can be displayed within the window (allow overlapping other
 8474        // panes). However, this is only allowed if the popover starts within text_bounds.
 8475        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8476            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8477
 8478        let mut origin = if can_position_to_the_right {
 8479            point(
 8480                x_after_longest,
 8481                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8482                    - scroll_pixel_position.y,
 8483            )
 8484        } else {
 8485            let cursor_row = newest_selection_head.map(|head| head.row());
 8486            let above_edit = edit_start
 8487                .row()
 8488                .0
 8489                .checked_sub(line_count as u32)
 8490                .map(DisplayRow);
 8491            let below_edit = Some(edit_end.row() + 1);
 8492            let above_cursor =
 8493                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8494            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8495
 8496            // Place the edit popover adjacent to the edit if there is a location
 8497            // available that is onscreen and does not obscure the cursor. Otherwise,
 8498            // place it adjacent to the cursor.
 8499            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8500                .into_iter()
 8501                .flatten()
 8502                .find(|&start_row| {
 8503                    let end_row = start_row + line_count as u32;
 8504                    visible_row_range.contains(&start_row)
 8505                        && visible_row_range.contains(&end_row)
 8506                        && cursor_row.map_or(true, |cursor_row| {
 8507                            !((start_row..end_row).contains(&cursor_row))
 8508                        })
 8509                })?;
 8510
 8511            content_origin
 8512                + point(
 8513                    -scroll_pixel_position.x,
 8514                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8515                )
 8516        };
 8517
 8518        origin.x -= BORDER_WIDTH;
 8519
 8520        window.defer_draw(element, origin, 1);
 8521
 8522        // Do not return an element, since it will already be drawn due to defer_draw.
 8523        None
 8524    }
 8525
 8526    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8527        px(30.)
 8528    }
 8529
 8530    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8531        if self.read_only(cx) {
 8532            cx.theme().players().read_only()
 8533        } else {
 8534            self.style.as_ref().unwrap().local_player
 8535        }
 8536    }
 8537
 8538    fn render_edit_prediction_accept_keybind(
 8539        &self,
 8540        window: &mut Window,
 8541        cx: &App,
 8542    ) -> Option<AnyElement> {
 8543        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8544        let accept_keystroke = accept_binding.keystroke()?;
 8545
 8546        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8547
 8548        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8549            Color::Accent
 8550        } else {
 8551            Color::Muted
 8552        };
 8553
 8554        h_flex()
 8555            .px_0p5()
 8556            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8557            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8558            .text_size(TextSize::XSmall.rems(cx))
 8559            .child(h_flex().children(ui::render_modifiers(
 8560                &accept_keystroke.modifiers,
 8561                PlatformStyle::platform(),
 8562                Some(modifiers_color),
 8563                Some(IconSize::XSmall.rems().into()),
 8564                true,
 8565            )))
 8566            .when(is_platform_style_mac, |parent| {
 8567                parent.child(accept_keystroke.key.clone())
 8568            })
 8569            .when(!is_platform_style_mac, |parent| {
 8570                parent.child(
 8571                    Key::new(
 8572                        util::capitalize(&accept_keystroke.key),
 8573                        Some(Color::Default),
 8574                    )
 8575                    .size(Some(IconSize::XSmall.rems().into())),
 8576                )
 8577            })
 8578            .into_any()
 8579            .into()
 8580    }
 8581
 8582    fn render_edit_prediction_line_popover(
 8583        &self,
 8584        label: impl Into<SharedString>,
 8585        icon: Option<IconName>,
 8586        window: &mut Window,
 8587        cx: &App,
 8588    ) -> Option<Stateful<Div>> {
 8589        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8590
 8591        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8592        let has_keybind = keybind.is_some();
 8593
 8594        let result = h_flex()
 8595            .id("ep-line-popover")
 8596            .py_0p5()
 8597            .pl_1()
 8598            .pr(padding_right)
 8599            .gap_1()
 8600            .rounded_md()
 8601            .border_1()
 8602            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8603            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8604            .shadow_sm()
 8605            .when(!has_keybind, |el| {
 8606                let status_colors = cx.theme().status();
 8607
 8608                el.bg(status_colors.error_background)
 8609                    .border_color(status_colors.error.opacity(0.6))
 8610                    .pl_2()
 8611                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8612                    .cursor_default()
 8613                    .hoverable_tooltip(move |_window, cx| {
 8614                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8615                    })
 8616            })
 8617            .children(keybind)
 8618            .child(
 8619                Label::new(label)
 8620                    .size(LabelSize::Small)
 8621                    .when(!has_keybind, |el| {
 8622                        el.color(cx.theme().status().error.into()).strikethrough()
 8623                    }),
 8624            )
 8625            .when(!has_keybind, |el| {
 8626                el.child(
 8627                    h_flex().ml_1().child(
 8628                        Icon::new(IconName::Info)
 8629                            .size(IconSize::Small)
 8630                            .color(cx.theme().status().error.into()),
 8631                    ),
 8632                )
 8633            })
 8634            .when_some(icon, |element, icon| {
 8635                element.child(
 8636                    div()
 8637                        .mt(px(1.5))
 8638                        .child(Icon::new(icon).size(IconSize::Small)),
 8639                )
 8640            });
 8641
 8642        Some(result)
 8643    }
 8644
 8645    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8646        let accent_color = cx.theme().colors().text_accent;
 8647        let editor_bg_color = cx.theme().colors().editor_background;
 8648        editor_bg_color.blend(accent_color.opacity(0.1))
 8649    }
 8650
 8651    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8652        let accent_color = cx.theme().colors().text_accent;
 8653        let editor_bg_color = cx.theme().colors().editor_background;
 8654        editor_bg_color.blend(accent_color.opacity(0.6))
 8655    }
 8656
 8657    fn render_edit_prediction_cursor_popover(
 8658        &self,
 8659        min_width: Pixels,
 8660        max_width: Pixels,
 8661        cursor_point: Point,
 8662        style: &EditorStyle,
 8663        accept_keystroke: Option<&gpui::Keystroke>,
 8664        _window: &Window,
 8665        cx: &mut Context<Editor>,
 8666    ) -> Option<AnyElement> {
 8667        let provider = self.edit_prediction_provider.as_ref()?;
 8668
 8669        if provider.provider.needs_terms_acceptance(cx) {
 8670            return Some(
 8671                h_flex()
 8672                    .min_w(min_width)
 8673                    .flex_1()
 8674                    .px_2()
 8675                    .py_1()
 8676                    .gap_3()
 8677                    .elevation_2(cx)
 8678                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8679                    .id("accept-terms")
 8680                    .cursor_pointer()
 8681                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8682                    .on_click(cx.listener(|this, _event, window, cx| {
 8683                        cx.stop_propagation();
 8684                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8685                        window.dispatch_action(
 8686                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8687                            cx,
 8688                        );
 8689                    }))
 8690                    .child(
 8691                        h_flex()
 8692                            .flex_1()
 8693                            .gap_2()
 8694                            .child(Icon::new(IconName::ZedPredict))
 8695                            .child(Label::new("Accept Terms of Service"))
 8696                            .child(div().w_full())
 8697                            .child(
 8698                                Icon::new(IconName::ArrowUpRight)
 8699                                    .color(Color::Muted)
 8700                                    .size(IconSize::Small),
 8701                            )
 8702                            .into_any_element(),
 8703                    )
 8704                    .into_any(),
 8705            );
 8706        }
 8707
 8708        let is_refreshing = provider.provider.is_refreshing(cx);
 8709
 8710        fn pending_completion_container() -> Div {
 8711            h_flex()
 8712                .h_full()
 8713                .flex_1()
 8714                .gap_2()
 8715                .child(Icon::new(IconName::ZedPredict))
 8716        }
 8717
 8718        let completion = match &self.active_inline_completion {
 8719            Some(prediction) => {
 8720                if !self.has_visible_completions_menu() {
 8721                    const RADIUS: Pixels = px(6.);
 8722                    const BORDER_WIDTH: Pixels = px(1.);
 8723
 8724                    return Some(
 8725                        h_flex()
 8726                            .elevation_2(cx)
 8727                            .border(BORDER_WIDTH)
 8728                            .border_color(cx.theme().colors().border)
 8729                            .when(accept_keystroke.is_none(), |el| {
 8730                                el.border_color(cx.theme().status().error)
 8731                            })
 8732                            .rounded(RADIUS)
 8733                            .rounded_tl(px(0.))
 8734                            .overflow_hidden()
 8735                            .child(div().px_1p5().child(match &prediction.completion {
 8736                                InlineCompletion::Move { target, snapshot } => {
 8737                                    use text::ToPoint as _;
 8738                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8739                                    {
 8740                                        Icon::new(IconName::ZedPredictDown)
 8741                                    } else {
 8742                                        Icon::new(IconName::ZedPredictUp)
 8743                                    }
 8744                                }
 8745                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8746                            }))
 8747                            .child(
 8748                                h_flex()
 8749                                    .gap_1()
 8750                                    .py_1()
 8751                                    .px_2()
 8752                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8753                                    .border_l_1()
 8754                                    .border_color(cx.theme().colors().border)
 8755                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8756                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8757                                        el.child(
 8758                                            Label::new("Hold")
 8759                                                .size(LabelSize::Small)
 8760                                                .when(accept_keystroke.is_none(), |el| {
 8761                                                    el.strikethrough()
 8762                                                })
 8763                                                .line_height_style(LineHeightStyle::UiLabel),
 8764                                        )
 8765                                    })
 8766                                    .id("edit_prediction_cursor_popover_keybind")
 8767                                    .when(accept_keystroke.is_none(), |el| {
 8768                                        let status_colors = cx.theme().status();
 8769
 8770                                        el.bg(status_colors.error_background)
 8771                                            .border_color(status_colors.error.opacity(0.6))
 8772                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8773                                            .cursor_default()
 8774                                            .hoverable_tooltip(move |_window, cx| {
 8775                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8776                                                    .into()
 8777                                            })
 8778                                    })
 8779                                    .when_some(
 8780                                        accept_keystroke.as_ref(),
 8781                                        |el, accept_keystroke| {
 8782                                            el.child(h_flex().children(ui::render_modifiers(
 8783                                                &accept_keystroke.modifiers,
 8784                                                PlatformStyle::platform(),
 8785                                                Some(Color::Default),
 8786                                                Some(IconSize::XSmall.rems().into()),
 8787                                                false,
 8788                                            )))
 8789                                        },
 8790                                    ),
 8791                            )
 8792                            .into_any(),
 8793                    );
 8794                }
 8795
 8796                self.render_edit_prediction_cursor_popover_preview(
 8797                    prediction,
 8798                    cursor_point,
 8799                    style,
 8800                    cx,
 8801                )?
 8802            }
 8803
 8804            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8805                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8806                    stale_completion,
 8807                    cursor_point,
 8808                    style,
 8809                    cx,
 8810                )?,
 8811
 8812                None => {
 8813                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8814                }
 8815            },
 8816
 8817            None => pending_completion_container().child(Label::new("No Prediction")),
 8818        };
 8819
 8820        let completion = if is_refreshing {
 8821            completion
 8822                .with_animation(
 8823                    "loading-completion",
 8824                    Animation::new(Duration::from_secs(2))
 8825                        .repeat()
 8826                        .with_easing(pulsating_between(0.4, 0.8)),
 8827                    |label, delta| label.opacity(delta),
 8828                )
 8829                .into_any_element()
 8830        } else {
 8831            completion.into_any_element()
 8832        };
 8833
 8834        let has_completion = self.active_inline_completion.is_some();
 8835
 8836        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8837        Some(
 8838            h_flex()
 8839                .min_w(min_width)
 8840                .max_w(max_width)
 8841                .flex_1()
 8842                .elevation_2(cx)
 8843                .border_color(cx.theme().colors().border)
 8844                .child(
 8845                    div()
 8846                        .flex_1()
 8847                        .py_1()
 8848                        .px_2()
 8849                        .overflow_hidden()
 8850                        .child(completion),
 8851                )
 8852                .when_some(accept_keystroke, |el, accept_keystroke| {
 8853                    if !accept_keystroke.modifiers.modified() {
 8854                        return el;
 8855                    }
 8856
 8857                    el.child(
 8858                        h_flex()
 8859                            .h_full()
 8860                            .border_l_1()
 8861                            .rounded_r_lg()
 8862                            .border_color(cx.theme().colors().border)
 8863                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8864                            .gap_1()
 8865                            .py_1()
 8866                            .px_2()
 8867                            .child(
 8868                                h_flex()
 8869                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8870                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8871                                    .child(h_flex().children(ui::render_modifiers(
 8872                                        &accept_keystroke.modifiers,
 8873                                        PlatformStyle::platform(),
 8874                                        Some(if !has_completion {
 8875                                            Color::Muted
 8876                                        } else {
 8877                                            Color::Default
 8878                                        }),
 8879                                        None,
 8880                                        false,
 8881                                    ))),
 8882                            )
 8883                            .child(Label::new("Preview").into_any_element())
 8884                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8885                    )
 8886                })
 8887                .into_any(),
 8888        )
 8889    }
 8890
 8891    fn render_edit_prediction_cursor_popover_preview(
 8892        &self,
 8893        completion: &InlineCompletionState,
 8894        cursor_point: Point,
 8895        style: &EditorStyle,
 8896        cx: &mut Context<Editor>,
 8897    ) -> Option<Div> {
 8898        use text::ToPoint as _;
 8899
 8900        fn render_relative_row_jump(
 8901            prefix: impl Into<String>,
 8902            current_row: u32,
 8903            target_row: u32,
 8904        ) -> Div {
 8905            let (row_diff, arrow) = if target_row < current_row {
 8906                (current_row - target_row, IconName::ArrowUp)
 8907            } else {
 8908                (target_row - current_row, IconName::ArrowDown)
 8909            };
 8910
 8911            h_flex()
 8912                .child(
 8913                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8914                        .color(Color::Muted)
 8915                        .size(LabelSize::Small),
 8916                )
 8917                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8918        }
 8919
 8920        match &completion.completion {
 8921            InlineCompletion::Move {
 8922                target, snapshot, ..
 8923            } => Some(
 8924                h_flex()
 8925                    .px_2()
 8926                    .gap_2()
 8927                    .flex_1()
 8928                    .child(
 8929                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8930                            Icon::new(IconName::ZedPredictDown)
 8931                        } else {
 8932                            Icon::new(IconName::ZedPredictUp)
 8933                        },
 8934                    )
 8935                    .child(Label::new("Jump to Edit")),
 8936            ),
 8937
 8938            InlineCompletion::Edit {
 8939                edits,
 8940                edit_preview,
 8941                snapshot,
 8942                display_mode: _,
 8943            } => {
 8944                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8945
 8946                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8947                    &snapshot,
 8948                    &edits,
 8949                    edit_preview.as_ref()?,
 8950                    true,
 8951                    cx,
 8952                )
 8953                .first_line_preview();
 8954
 8955                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8956                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8957
 8958                let preview = h_flex()
 8959                    .gap_1()
 8960                    .min_w_16()
 8961                    .child(styled_text)
 8962                    .when(has_more_lines, |parent| parent.child(""));
 8963
 8964                let left = if first_edit_row != cursor_point.row {
 8965                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8966                        .into_any_element()
 8967                } else {
 8968                    Icon::new(IconName::ZedPredict).into_any_element()
 8969                };
 8970
 8971                Some(
 8972                    h_flex()
 8973                        .h_full()
 8974                        .flex_1()
 8975                        .gap_2()
 8976                        .pr_1()
 8977                        .overflow_x_hidden()
 8978                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8979                        .child(left)
 8980                        .child(preview),
 8981                )
 8982            }
 8983        }
 8984    }
 8985
 8986    pub fn render_context_menu(
 8987        &self,
 8988        style: &EditorStyle,
 8989        max_height_in_lines: u32,
 8990        window: &mut Window,
 8991        cx: &mut Context<Editor>,
 8992    ) -> Option<AnyElement> {
 8993        let menu = self.context_menu.borrow();
 8994        let menu = menu.as_ref()?;
 8995        if !menu.visible() {
 8996            return None;
 8997        };
 8998        Some(menu.render(style, max_height_in_lines, window, cx))
 8999    }
 9000
 9001    fn render_context_menu_aside(
 9002        &mut self,
 9003        max_size: Size<Pixels>,
 9004        window: &mut Window,
 9005        cx: &mut Context<Editor>,
 9006    ) -> Option<AnyElement> {
 9007        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9008            if menu.visible() {
 9009                menu.render_aside(max_size, window, cx)
 9010            } else {
 9011                None
 9012            }
 9013        })
 9014    }
 9015
 9016    fn hide_context_menu(
 9017        &mut self,
 9018        window: &mut Window,
 9019        cx: &mut Context<Self>,
 9020    ) -> Option<CodeContextMenu> {
 9021        cx.notify();
 9022        self.completion_tasks.clear();
 9023        let context_menu = self.context_menu.borrow_mut().take();
 9024        self.stale_inline_completion_in_menu.take();
 9025        self.update_visible_inline_completion(window, cx);
 9026        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9027            if let Some(completion_provider) = &self.completion_provider {
 9028                completion_provider.selection_changed(None, window, cx);
 9029            }
 9030        }
 9031        context_menu
 9032    }
 9033
 9034    fn show_snippet_choices(
 9035        &mut self,
 9036        choices: &Vec<String>,
 9037        selection: Range<Anchor>,
 9038        cx: &mut Context<Self>,
 9039    ) {
 9040        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9041            (Some(a), Some(b)) if a == b => a,
 9042            _ => {
 9043                log::error!("expected anchor range to have matching buffer IDs");
 9044                return;
 9045            }
 9046        };
 9047        let multi_buffer = self.buffer().read(cx);
 9048        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9049            return;
 9050        };
 9051
 9052        let id = post_inc(&mut self.next_completion_id);
 9053        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9054        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9055            CompletionsMenu::new_snippet_choices(
 9056                id,
 9057                true,
 9058                choices,
 9059                selection,
 9060                buffer,
 9061                snippet_sort_order,
 9062            ),
 9063        ));
 9064    }
 9065
 9066    pub fn insert_snippet(
 9067        &mut self,
 9068        insertion_ranges: &[Range<usize>],
 9069        snippet: Snippet,
 9070        window: &mut Window,
 9071        cx: &mut Context<Self>,
 9072    ) -> Result<()> {
 9073        struct Tabstop<T> {
 9074            is_end_tabstop: bool,
 9075            ranges: Vec<Range<T>>,
 9076            choices: Option<Vec<String>>,
 9077        }
 9078
 9079        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9080            let snippet_text: Arc<str> = snippet.text.clone().into();
 9081            let edits = insertion_ranges
 9082                .iter()
 9083                .cloned()
 9084                .map(|range| (range, snippet_text.clone()));
 9085            let autoindent_mode = AutoindentMode::Block {
 9086                original_indent_columns: Vec::new(),
 9087            };
 9088            buffer.edit(edits, Some(autoindent_mode), cx);
 9089
 9090            let snapshot = &*buffer.read(cx);
 9091            let snippet = &snippet;
 9092            snippet
 9093                .tabstops
 9094                .iter()
 9095                .map(|tabstop| {
 9096                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9097                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9098                    });
 9099                    let mut tabstop_ranges = tabstop
 9100                        .ranges
 9101                        .iter()
 9102                        .flat_map(|tabstop_range| {
 9103                            let mut delta = 0_isize;
 9104                            insertion_ranges.iter().map(move |insertion_range| {
 9105                                let insertion_start = insertion_range.start as isize + delta;
 9106                                delta +=
 9107                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9108
 9109                                let start = ((insertion_start + tabstop_range.start) as usize)
 9110                                    .min(snapshot.len());
 9111                                let end = ((insertion_start + tabstop_range.end) as usize)
 9112                                    .min(snapshot.len());
 9113                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9114                            })
 9115                        })
 9116                        .collect::<Vec<_>>();
 9117                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9118
 9119                    Tabstop {
 9120                        is_end_tabstop,
 9121                        ranges: tabstop_ranges,
 9122                        choices: tabstop.choices.clone(),
 9123                    }
 9124                })
 9125                .collect::<Vec<_>>()
 9126        });
 9127        if let Some(tabstop) = tabstops.first() {
 9128            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9129                // Reverse order so that the first range is the newest created selection.
 9130                // Completions will use it and autoscroll will prioritize it.
 9131                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9132            });
 9133
 9134            if let Some(choices) = &tabstop.choices {
 9135                if let Some(selection) = tabstop.ranges.first() {
 9136                    self.show_snippet_choices(choices, selection.clone(), cx)
 9137                }
 9138            }
 9139
 9140            // If we're already at the last tabstop and it's at the end of the snippet,
 9141            // we're done, we don't need to keep the state around.
 9142            if !tabstop.is_end_tabstop {
 9143                let choices = tabstops
 9144                    .iter()
 9145                    .map(|tabstop| tabstop.choices.clone())
 9146                    .collect();
 9147
 9148                let ranges = tabstops
 9149                    .into_iter()
 9150                    .map(|tabstop| tabstop.ranges)
 9151                    .collect::<Vec<_>>();
 9152
 9153                self.snippet_stack.push(SnippetState {
 9154                    active_index: 0,
 9155                    ranges,
 9156                    choices,
 9157                });
 9158            }
 9159
 9160            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9161            if self.autoclose_regions.is_empty() {
 9162                let snapshot = self.buffer.read(cx).snapshot(cx);
 9163                for selection in &mut self.selections.all::<Point>(cx) {
 9164                    let selection_head = selection.head();
 9165                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9166                        continue;
 9167                    };
 9168
 9169                    let mut bracket_pair = None;
 9170                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9171                    let prev_chars = snapshot
 9172                        .reversed_chars_at(selection_head)
 9173                        .collect::<String>();
 9174                    for (pair, enabled) in scope.brackets() {
 9175                        if enabled
 9176                            && pair.close
 9177                            && prev_chars.starts_with(pair.start.as_str())
 9178                            && next_chars.starts_with(pair.end.as_str())
 9179                        {
 9180                            bracket_pair = Some(pair.clone());
 9181                            break;
 9182                        }
 9183                    }
 9184                    if let Some(pair) = bracket_pair {
 9185                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9186                        let autoclose_enabled =
 9187                            self.use_autoclose && snapshot_settings.use_autoclose;
 9188                        if autoclose_enabled {
 9189                            let start = snapshot.anchor_after(selection_head);
 9190                            let end = snapshot.anchor_after(selection_head);
 9191                            self.autoclose_regions.push(AutocloseRegion {
 9192                                selection_id: selection.id,
 9193                                range: start..end,
 9194                                pair,
 9195                            });
 9196                        }
 9197                    }
 9198                }
 9199            }
 9200        }
 9201        Ok(())
 9202    }
 9203
 9204    pub fn move_to_next_snippet_tabstop(
 9205        &mut self,
 9206        window: &mut Window,
 9207        cx: &mut Context<Self>,
 9208    ) -> bool {
 9209        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9210    }
 9211
 9212    pub fn move_to_prev_snippet_tabstop(
 9213        &mut self,
 9214        window: &mut Window,
 9215        cx: &mut Context<Self>,
 9216    ) -> bool {
 9217        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9218    }
 9219
 9220    pub fn move_to_snippet_tabstop(
 9221        &mut self,
 9222        bias: Bias,
 9223        window: &mut Window,
 9224        cx: &mut Context<Self>,
 9225    ) -> bool {
 9226        if let Some(mut snippet) = self.snippet_stack.pop() {
 9227            match bias {
 9228                Bias::Left => {
 9229                    if snippet.active_index > 0 {
 9230                        snippet.active_index -= 1;
 9231                    } else {
 9232                        self.snippet_stack.push(snippet);
 9233                        return false;
 9234                    }
 9235                }
 9236                Bias::Right => {
 9237                    if snippet.active_index + 1 < snippet.ranges.len() {
 9238                        snippet.active_index += 1;
 9239                    } else {
 9240                        self.snippet_stack.push(snippet);
 9241                        return false;
 9242                    }
 9243                }
 9244            }
 9245            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9246                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9247                    // Reverse order so that the first range is the newest created selection.
 9248                    // Completions will use it and autoscroll will prioritize it.
 9249                    s.select_ranges(current_ranges.iter().rev().cloned())
 9250                });
 9251
 9252                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9253                    if let Some(selection) = current_ranges.first() {
 9254                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9255                    }
 9256                }
 9257
 9258                // If snippet state is not at the last tabstop, push it back on the stack
 9259                if snippet.active_index + 1 < snippet.ranges.len() {
 9260                    self.snippet_stack.push(snippet);
 9261                }
 9262                return true;
 9263            }
 9264        }
 9265
 9266        false
 9267    }
 9268
 9269    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9270        self.transact(window, cx, |this, window, cx| {
 9271            this.select_all(&SelectAll, window, cx);
 9272            this.insert("", window, cx);
 9273        });
 9274    }
 9275
 9276    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9277        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9278        self.transact(window, cx, |this, window, cx| {
 9279            this.select_autoclose_pair(window, cx);
 9280            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9281            if !this.linked_edit_ranges.is_empty() {
 9282                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9283                let snapshot = this.buffer.read(cx).snapshot(cx);
 9284
 9285                for selection in selections.iter() {
 9286                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9287                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9288                    if selection_start.buffer_id != selection_end.buffer_id {
 9289                        continue;
 9290                    }
 9291                    if let Some(ranges) =
 9292                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9293                    {
 9294                        for (buffer, entries) in ranges {
 9295                            linked_ranges.entry(buffer).or_default().extend(entries);
 9296                        }
 9297                    }
 9298                }
 9299            }
 9300
 9301            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9302            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9303            for selection in &mut selections {
 9304                if selection.is_empty() {
 9305                    let old_head = selection.head();
 9306                    let mut new_head =
 9307                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9308                            .to_point(&display_map);
 9309                    if let Some((buffer, line_buffer_range)) = display_map
 9310                        .buffer_snapshot
 9311                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9312                    {
 9313                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9314                        let indent_len = match indent_size.kind {
 9315                            IndentKind::Space => {
 9316                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9317                            }
 9318                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9319                        };
 9320                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9321                            let indent_len = indent_len.get();
 9322                            new_head = cmp::min(
 9323                                new_head,
 9324                                MultiBufferPoint::new(
 9325                                    old_head.row,
 9326                                    ((old_head.column - 1) / indent_len) * indent_len,
 9327                                ),
 9328                            );
 9329                        }
 9330                    }
 9331
 9332                    selection.set_head(new_head, SelectionGoal::None);
 9333                }
 9334            }
 9335
 9336            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9337                s.select(selections)
 9338            });
 9339            this.insert("", window, cx);
 9340            let empty_str: Arc<str> = Arc::from("");
 9341            for (buffer, edits) in linked_ranges {
 9342                let snapshot = buffer.read(cx).snapshot();
 9343                use text::ToPoint as TP;
 9344
 9345                let edits = edits
 9346                    .into_iter()
 9347                    .map(|range| {
 9348                        let end_point = TP::to_point(&range.end, &snapshot);
 9349                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9350
 9351                        if end_point == start_point {
 9352                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9353                                .saturating_sub(1);
 9354                            start_point =
 9355                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9356                        };
 9357
 9358                        (start_point..end_point, empty_str.clone())
 9359                    })
 9360                    .sorted_by_key(|(range, _)| range.start)
 9361                    .collect::<Vec<_>>();
 9362                buffer.update(cx, |this, cx| {
 9363                    this.edit(edits, None, cx);
 9364                })
 9365            }
 9366            this.refresh_inline_completion(true, false, window, cx);
 9367            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9368        });
 9369    }
 9370
 9371    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9372        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9373        self.transact(window, cx, |this, window, cx| {
 9374            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9375                s.move_with(|map, selection| {
 9376                    if selection.is_empty() {
 9377                        let cursor = movement::right(map, selection.head());
 9378                        selection.end = cursor;
 9379                        selection.reversed = true;
 9380                        selection.goal = SelectionGoal::None;
 9381                    }
 9382                })
 9383            });
 9384            this.insert("", window, cx);
 9385            this.refresh_inline_completion(true, false, window, cx);
 9386        });
 9387    }
 9388
 9389    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9390        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9391        if self.move_to_prev_snippet_tabstop(window, cx) {
 9392            return;
 9393        }
 9394        self.outdent(&Outdent, window, cx);
 9395    }
 9396
 9397    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9398        if self.move_to_next_snippet_tabstop(window, cx) {
 9399            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9400            return;
 9401        }
 9402        if self.read_only(cx) {
 9403            return;
 9404        }
 9405        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9406        let mut selections = self.selections.all_adjusted(cx);
 9407        let buffer = self.buffer.read(cx);
 9408        let snapshot = buffer.snapshot(cx);
 9409        let rows_iter = selections.iter().map(|s| s.head().row);
 9410        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9411
 9412        let has_some_cursor_in_whitespace = selections
 9413            .iter()
 9414            .filter(|selection| selection.is_empty())
 9415            .any(|selection| {
 9416                let cursor = selection.head();
 9417                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9418                cursor.column < current_indent.len
 9419            });
 9420
 9421        let mut edits = Vec::new();
 9422        let mut prev_edited_row = 0;
 9423        let mut row_delta = 0;
 9424        for selection in &mut selections {
 9425            if selection.start.row != prev_edited_row {
 9426                row_delta = 0;
 9427            }
 9428            prev_edited_row = selection.end.row;
 9429
 9430            // If the selection is non-empty, then increase the indentation of the selected lines.
 9431            if !selection.is_empty() {
 9432                row_delta =
 9433                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9434                continue;
 9435            }
 9436
 9437            let cursor = selection.head();
 9438            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9439            if let Some(suggested_indent) =
 9440                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9441            {
 9442                // Don't do anything if already at suggested indent
 9443                // and there is any other cursor which is not
 9444                if has_some_cursor_in_whitespace
 9445                    && cursor.column == current_indent.len
 9446                    && current_indent.len == suggested_indent.len
 9447                {
 9448                    continue;
 9449                }
 9450
 9451                // Adjust line and move cursor to suggested indent
 9452                // if cursor is not at suggested indent
 9453                if cursor.column < suggested_indent.len
 9454                    && cursor.column <= current_indent.len
 9455                    && current_indent.len <= suggested_indent.len
 9456                {
 9457                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9458                    selection.end = selection.start;
 9459                    if row_delta == 0 {
 9460                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9461                            cursor.row,
 9462                            current_indent,
 9463                            suggested_indent,
 9464                        ));
 9465                        row_delta = suggested_indent.len - current_indent.len;
 9466                    }
 9467                    continue;
 9468                }
 9469
 9470                // If current indent is more than suggested indent
 9471                // only move cursor to current indent and skip indent
 9472                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9473                    selection.start = Point::new(cursor.row, current_indent.len);
 9474                    selection.end = selection.start;
 9475                    continue;
 9476                }
 9477            }
 9478
 9479            // Otherwise, insert a hard or soft tab.
 9480            let settings = buffer.language_settings_at(cursor, cx);
 9481            let tab_size = if settings.hard_tabs {
 9482                IndentSize::tab()
 9483            } else {
 9484                let tab_size = settings.tab_size.get();
 9485                let indent_remainder = snapshot
 9486                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9487                    .flat_map(str::chars)
 9488                    .fold(row_delta % tab_size, |counter: u32, c| {
 9489                        if c == '\t' {
 9490                            0
 9491                        } else {
 9492                            (counter + 1) % tab_size
 9493                        }
 9494                    });
 9495
 9496                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9497                IndentSize::spaces(chars_to_next_tab_stop)
 9498            };
 9499            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9500            selection.end = selection.start;
 9501            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9502            row_delta += tab_size.len;
 9503        }
 9504
 9505        self.transact(window, cx, |this, window, cx| {
 9506            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9507            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9508                s.select(selections)
 9509            });
 9510            this.refresh_inline_completion(true, false, window, cx);
 9511        });
 9512    }
 9513
 9514    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9515        if self.read_only(cx) {
 9516            return;
 9517        }
 9518        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9519        let mut selections = self.selections.all::<Point>(cx);
 9520        let mut prev_edited_row = 0;
 9521        let mut row_delta = 0;
 9522        let mut edits = Vec::new();
 9523        let buffer = self.buffer.read(cx);
 9524        let snapshot = buffer.snapshot(cx);
 9525        for selection in &mut selections {
 9526            if selection.start.row != prev_edited_row {
 9527                row_delta = 0;
 9528            }
 9529            prev_edited_row = selection.end.row;
 9530
 9531            row_delta =
 9532                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9533        }
 9534
 9535        self.transact(window, cx, |this, window, cx| {
 9536            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9537            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9538                s.select(selections)
 9539            });
 9540        });
 9541    }
 9542
 9543    fn indent_selection(
 9544        buffer: &MultiBuffer,
 9545        snapshot: &MultiBufferSnapshot,
 9546        selection: &mut Selection<Point>,
 9547        edits: &mut Vec<(Range<Point>, String)>,
 9548        delta_for_start_row: u32,
 9549        cx: &App,
 9550    ) -> u32 {
 9551        let settings = buffer.language_settings_at(selection.start, cx);
 9552        let tab_size = settings.tab_size.get();
 9553        let indent_kind = if settings.hard_tabs {
 9554            IndentKind::Tab
 9555        } else {
 9556            IndentKind::Space
 9557        };
 9558        let mut start_row = selection.start.row;
 9559        let mut end_row = selection.end.row + 1;
 9560
 9561        // If a selection ends at the beginning of a line, don't indent
 9562        // that last line.
 9563        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9564            end_row -= 1;
 9565        }
 9566
 9567        // Avoid re-indenting a row that has already been indented by a
 9568        // previous selection, but still update this selection's column
 9569        // to reflect that indentation.
 9570        if delta_for_start_row > 0 {
 9571            start_row += 1;
 9572            selection.start.column += delta_for_start_row;
 9573            if selection.end.row == selection.start.row {
 9574                selection.end.column += delta_for_start_row;
 9575            }
 9576        }
 9577
 9578        let mut delta_for_end_row = 0;
 9579        let has_multiple_rows = start_row + 1 != end_row;
 9580        for row in start_row..end_row {
 9581            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9582            let indent_delta = match (current_indent.kind, indent_kind) {
 9583                (IndentKind::Space, IndentKind::Space) => {
 9584                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9585                    IndentSize::spaces(columns_to_next_tab_stop)
 9586                }
 9587                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9588                (_, IndentKind::Tab) => IndentSize::tab(),
 9589            };
 9590
 9591            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9592                0
 9593            } else {
 9594                selection.start.column
 9595            };
 9596            let row_start = Point::new(row, start);
 9597            edits.push((
 9598                row_start..row_start,
 9599                indent_delta.chars().collect::<String>(),
 9600            ));
 9601
 9602            // Update this selection's endpoints to reflect the indentation.
 9603            if row == selection.start.row {
 9604                selection.start.column += indent_delta.len;
 9605            }
 9606            if row == selection.end.row {
 9607                selection.end.column += indent_delta.len;
 9608                delta_for_end_row = indent_delta.len;
 9609            }
 9610        }
 9611
 9612        if selection.start.row == selection.end.row {
 9613            delta_for_start_row + delta_for_end_row
 9614        } else {
 9615            delta_for_end_row
 9616        }
 9617    }
 9618
 9619    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9620        if self.read_only(cx) {
 9621            return;
 9622        }
 9623        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9624        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9625        let selections = self.selections.all::<Point>(cx);
 9626        let mut deletion_ranges = Vec::new();
 9627        let mut last_outdent = None;
 9628        {
 9629            let buffer = self.buffer.read(cx);
 9630            let snapshot = buffer.snapshot(cx);
 9631            for selection in &selections {
 9632                let settings = buffer.language_settings_at(selection.start, cx);
 9633                let tab_size = settings.tab_size.get();
 9634                let mut rows = selection.spanned_rows(false, &display_map);
 9635
 9636                // Avoid re-outdenting a row that has already been outdented by a
 9637                // previous selection.
 9638                if let Some(last_row) = last_outdent {
 9639                    if last_row == rows.start {
 9640                        rows.start = rows.start.next_row();
 9641                    }
 9642                }
 9643                let has_multiple_rows = rows.len() > 1;
 9644                for row in rows.iter_rows() {
 9645                    let indent_size = snapshot.indent_size_for_line(row);
 9646                    if indent_size.len > 0 {
 9647                        let deletion_len = match indent_size.kind {
 9648                            IndentKind::Space => {
 9649                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9650                                if columns_to_prev_tab_stop == 0 {
 9651                                    tab_size
 9652                                } else {
 9653                                    columns_to_prev_tab_stop
 9654                                }
 9655                            }
 9656                            IndentKind::Tab => 1,
 9657                        };
 9658                        let start = if has_multiple_rows
 9659                            || deletion_len > selection.start.column
 9660                            || indent_size.len < selection.start.column
 9661                        {
 9662                            0
 9663                        } else {
 9664                            selection.start.column - deletion_len
 9665                        };
 9666                        deletion_ranges.push(
 9667                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9668                        );
 9669                        last_outdent = Some(row);
 9670                    }
 9671                }
 9672            }
 9673        }
 9674
 9675        self.transact(window, cx, |this, window, cx| {
 9676            this.buffer.update(cx, |buffer, cx| {
 9677                let empty_str: Arc<str> = Arc::default();
 9678                buffer.edit(
 9679                    deletion_ranges
 9680                        .into_iter()
 9681                        .map(|range| (range, empty_str.clone())),
 9682                    None,
 9683                    cx,
 9684                );
 9685            });
 9686            let selections = this.selections.all::<usize>(cx);
 9687            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9688                s.select(selections)
 9689            });
 9690        });
 9691    }
 9692
 9693    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9694        if self.read_only(cx) {
 9695            return;
 9696        }
 9697        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9698        let selections = self
 9699            .selections
 9700            .all::<usize>(cx)
 9701            .into_iter()
 9702            .map(|s| s.range());
 9703
 9704        self.transact(window, cx, |this, window, cx| {
 9705            this.buffer.update(cx, |buffer, cx| {
 9706                buffer.autoindent_ranges(selections, cx);
 9707            });
 9708            let selections = this.selections.all::<usize>(cx);
 9709            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9710                s.select(selections)
 9711            });
 9712        });
 9713    }
 9714
 9715    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9716        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9717        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9718        let selections = self.selections.all::<Point>(cx);
 9719
 9720        let mut new_cursors = Vec::new();
 9721        let mut edit_ranges = Vec::new();
 9722        let mut selections = selections.iter().peekable();
 9723        while let Some(selection) = selections.next() {
 9724            let mut rows = selection.spanned_rows(false, &display_map);
 9725            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9726
 9727            // Accumulate contiguous regions of rows that we want to delete.
 9728            while let Some(next_selection) = selections.peek() {
 9729                let next_rows = next_selection.spanned_rows(false, &display_map);
 9730                if next_rows.start <= rows.end {
 9731                    rows.end = next_rows.end;
 9732                    selections.next().unwrap();
 9733                } else {
 9734                    break;
 9735                }
 9736            }
 9737
 9738            let buffer = &display_map.buffer_snapshot;
 9739            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9740            let edit_end;
 9741            let cursor_buffer_row;
 9742            if buffer.max_point().row >= rows.end.0 {
 9743                // If there's a line after the range, delete the \n from the end of the row range
 9744                // and position the cursor on the next line.
 9745                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9746                cursor_buffer_row = rows.end;
 9747            } else {
 9748                // If there isn't a line after the range, delete the \n from the line before the
 9749                // start of the row range and position the cursor there.
 9750                edit_start = edit_start.saturating_sub(1);
 9751                edit_end = buffer.len();
 9752                cursor_buffer_row = rows.start.previous_row();
 9753            }
 9754
 9755            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9756            *cursor.column_mut() =
 9757                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9758
 9759            new_cursors.push((
 9760                selection.id,
 9761                buffer.anchor_after(cursor.to_point(&display_map)),
 9762            ));
 9763            edit_ranges.push(edit_start..edit_end);
 9764        }
 9765
 9766        self.transact(window, cx, |this, window, cx| {
 9767            let buffer = this.buffer.update(cx, |buffer, cx| {
 9768                let empty_str: Arc<str> = Arc::default();
 9769                buffer.edit(
 9770                    edit_ranges
 9771                        .into_iter()
 9772                        .map(|range| (range, empty_str.clone())),
 9773                    None,
 9774                    cx,
 9775                );
 9776                buffer.snapshot(cx)
 9777            });
 9778            let new_selections = new_cursors
 9779                .into_iter()
 9780                .map(|(id, cursor)| {
 9781                    let cursor = cursor.to_point(&buffer);
 9782                    Selection {
 9783                        id,
 9784                        start: cursor,
 9785                        end: cursor,
 9786                        reversed: false,
 9787                        goal: SelectionGoal::None,
 9788                    }
 9789                })
 9790                .collect();
 9791
 9792            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9793                s.select(new_selections);
 9794            });
 9795        });
 9796    }
 9797
 9798    pub fn join_lines_impl(
 9799        &mut self,
 9800        insert_whitespace: bool,
 9801        window: &mut Window,
 9802        cx: &mut Context<Self>,
 9803    ) {
 9804        if self.read_only(cx) {
 9805            return;
 9806        }
 9807        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9808        for selection in self.selections.all::<Point>(cx) {
 9809            let start = MultiBufferRow(selection.start.row);
 9810            // Treat single line selections as if they include the next line. Otherwise this action
 9811            // would do nothing for single line selections individual cursors.
 9812            let end = if selection.start.row == selection.end.row {
 9813                MultiBufferRow(selection.start.row + 1)
 9814            } else {
 9815                MultiBufferRow(selection.end.row)
 9816            };
 9817
 9818            if let Some(last_row_range) = row_ranges.last_mut() {
 9819                if start <= last_row_range.end {
 9820                    last_row_range.end = end;
 9821                    continue;
 9822                }
 9823            }
 9824            row_ranges.push(start..end);
 9825        }
 9826
 9827        let snapshot = self.buffer.read(cx).snapshot(cx);
 9828        let mut cursor_positions = Vec::new();
 9829        for row_range in &row_ranges {
 9830            let anchor = snapshot.anchor_before(Point::new(
 9831                row_range.end.previous_row().0,
 9832                snapshot.line_len(row_range.end.previous_row()),
 9833            ));
 9834            cursor_positions.push(anchor..anchor);
 9835        }
 9836
 9837        self.transact(window, cx, |this, window, cx| {
 9838            for row_range in row_ranges.into_iter().rev() {
 9839                for row in row_range.iter_rows().rev() {
 9840                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9841                    let next_line_row = row.next_row();
 9842                    let indent = snapshot.indent_size_for_line(next_line_row);
 9843                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9844
 9845                    let replace =
 9846                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9847                            " "
 9848                        } else {
 9849                            ""
 9850                        };
 9851
 9852                    this.buffer.update(cx, |buffer, cx| {
 9853                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9854                    });
 9855                }
 9856            }
 9857
 9858            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9859                s.select_anchor_ranges(cursor_positions)
 9860            });
 9861        });
 9862    }
 9863
 9864    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9865        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9866        self.join_lines_impl(true, window, cx);
 9867    }
 9868
 9869    pub fn sort_lines_case_sensitive(
 9870        &mut self,
 9871        _: &SortLinesCaseSensitive,
 9872        window: &mut Window,
 9873        cx: &mut Context<Self>,
 9874    ) {
 9875        self.manipulate_lines(window, cx, |lines| lines.sort())
 9876    }
 9877
 9878    pub fn sort_lines_case_insensitive(
 9879        &mut self,
 9880        _: &SortLinesCaseInsensitive,
 9881        window: &mut Window,
 9882        cx: &mut Context<Self>,
 9883    ) {
 9884        self.manipulate_lines(window, cx, |lines| {
 9885            lines.sort_by_key(|line| line.to_lowercase())
 9886        })
 9887    }
 9888
 9889    pub fn unique_lines_case_insensitive(
 9890        &mut self,
 9891        _: &UniqueLinesCaseInsensitive,
 9892        window: &mut Window,
 9893        cx: &mut Context<Self>,
 9894    ) {
 9895        self.manipulate_lines(window, cx, |lines| {
 9896            let mut seen = HashSet::default();
 9897            lines.retain(|line| seen.insert(line.to_lowercase()));
 9898        })
 9899    }
 9900
 9901    pub fn unique_lines_case_sensitive(
 9902        &mut self,
 9903        _: &UniqueLinesCaseSensitive,
 9904        window: &mut Window,
 9905        cx: &mut Context<Self>,
 9906    ) {
 9907        self.manipulate_lines(window, cx, |lines| {
 9908            let mut seen = HashSet::default();
 9909            lines.retain(|line| seen.insert(*line));
 9910        })
 9911    }
 9912
 9913    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9914        let Some(project) = self.project.clone() else {
 9915            return;
 9916        };
 9917        self.reload(project, window, cx)
 9918            .detach_and_notify_err(window, cx);
 9919    }
 9920
 9921    pub fn restore_file(
 9922        &mut self,
 9923        _: &::git::RestoreFile,
 9924        window: &mut Window,
 9925        cx: &mut Context<Self>,
 9926    ) {
 9927        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9928        let mut buffer_ids = HashSet::default();
 9929        let snapshot = self.buffer().read(cx).snapshot(cx);
 9930        for selection in self.selections.all::<usize>(cx) {
 9931            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9932        }
 9933
 9934        let buffer = self.buffer().read(cx);
 9935        let ranges = buffer_ids
 9936            .into_iter()
 9937            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9938            .collect::<Vec<_>>();
 9939
 9940        self.restore_hunks_in_ranges(ranges, window, cx);
 9941    }
 9942
 9943    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9944        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9945        let selections = self
 9946            .selections
 9947            .all(cx)
 9948            .into_iter()
 9949            .map(|s| s.range())
 9950            .collect();
 9951        self.restore_hunks_in_ranges(selections, window, cx);
 9952    }
 9953
 9954    pub fn restore_hunks_in_ranges(
 9955        &mut self,
 9956        ranges: Vec<Range<Point>>,
 9957        window: &mut Window,
 9958        cx: &mut Context<Editor>,
 9959    ) {
 9960        let mut revert_changes = HashMap::default();
 9961        let chunk_by = self
 9962            .snapshot(window, cx)
 9963            .hunks_for_ranges(ranges)
 9964            .into_iter()
 9965            .chunk_by(|hunk| hunk.buffer_id);
 9966        for (buffer_id, hunks) in &chunk_by {
 9967            let hunks = hunks.collect::<Vec<_>>();
 9968            for hunk in &hunks {
 9969                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9970            }
 9971            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9972        }
 9973        drop(chunk_by);
 9974        if !revert_changes.is_empty() {
 9975            self.transact(window, cx, |editor, window, cx| {
 9976                editor.restore(revert_changes, window, cx);
 9977            });
 9978        }
 9979    }
 9980
 9981    pub fn open_active_item_in_terminal(
 9982        &mut self,
 9983        _: &OpenInTerminal,
 9984        window: &mut Window,
 9985        cx: &mut Context<Self>,
 9986    ) {
 9987        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9988            let project_path = buffer.read(cx).project_path(cx)?;
 9989            let project = self.project.as_ref()?.read(cx);
 9990            let entry = project.entry_for_path(&project_path, cx)?;
 9991            let parent = match &entry.canonical_path {
 9992                Some(canonical_path) => canonical_path.to_path_buf(),
 9993                None => project.absolute_path(&project_path, cx)?,
 9994            }
 9995            .parent()?
 9996            .to_path_buf();
 9997            Some(parent)
 9998        }) {
 9999            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10000        }
10001    }
10002
10003    fn set_breakpoint_context_menu(
10004        &mut self,
10005        display_row: DisplayRow,
10006        position: Option<Anchor>,
10007        clicked_point: gpui::Point<Pixels>,
10008        window: &mut Window,
10009        cx: &mut Context<Self>,
10010    ) {
10011        if !cx.has_flag::<DebuggerFeatureFlag>() {
10012            return;
10013        }
10014        let source = self
10015            .buffer
10016            .read(cx)
10017            .snapshot(cx)
10018            .anchor_before(Point::new(display_row.0, 0u32));
10019
10020        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10021
10022        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10023            self,
10024            source,
10025            clicked_point,
10026            context_menu,
10027            window,
10028            cx,
10029        );
10030    }
10031
10032    fn add_edit_breakpoint_block(
10033        &mut self,
10034        anchor: Anchor,
10035        breakpoint: &Breakpoint,
10036        edit_action: BreakpointPromptEditAction,
10037        window: &mut Window,
10038        cx: &mut Context<Self>,
10039    ) {
10040        let weak_editor = cx.weak_entity();
10041        let bp_prompt = cx.new(|cx| {
10042            BreakpointPromptEditor::new(
10043                weak_editor,
10044                anchor,
10045                breakpoint.clone(),
10046                edit_action,
10047                window,
10048                cx,
10049            )
10050        });
10051
10052        let height = bp_prompt.update(cx, |this, cx| {
10053            this.prompt
10054                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10055        });
10056        let cloned_prompt = bp_prompt.clone();
10057        let blocks = vec![BlockProperties {
10058            style: BlockStyle::Sticky,
10059            placement: BlockPlacement::Above(anchor),
10060            height: Some(height),
10061            render: Arc::new(move |cx| {
10062                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10063                cloned_prompt.clone().into_any_element()
10064            }),
10065            priority: 0,
10066            render_in_minimap: true,
10067        }];
10068
10069        let focus_handle = bp_prompt.focus_handle(cx);
10070        window.focus(&focus_handle);
10071
10072        let block_ids = self.insert_blocks(blocks, None, cx);
10073        bp_prompt.update(cx, |prompt, _| {
10074            prompt.add_block_ids(block_ids);
10075        });
10076    }
10077
10078    pub(crate) fn breakpoint_at_row(
10079        &self,
10080        row: u32,
10081        window: &mut Window,
10082        cx: &mut Context<Self>,
10083    ) -> Option<(Anchor, Breakpoint)> {
10084        let snapshot = self.snapshot(window, cx);
10085        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10086
10087        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10088    }
10089
10090    pub(crate) fn breakpoint_at_anchor(
10091        &self,
10092        breakpoint_position: Anchor,
10093        snapshot: &EditorSnapshot,
10094        cx: &mut Context<Self>,
10095    ) -> Option<(Anchor, Breakpoint)> {
10096        let project = self.project.clone()?;
10097
10098        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10099            snapshot
10100                .buffer_snapshot
10101                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10102        })?;
10103
10104        let enclosing_excerpt = breakpoint_position.excerpt_id;
10105        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10106        let buffer_snapshot = buffer.read(cx).snapshot();
10107
10108        let row = buffer_snapshot
10109            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10110            .row;
10111
10112        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10113        let anchor_end = snapshot
10114            .buffer_snapshot
10115            .anchor_after(Point::new(row, line_len));
10116
10117        let bp = self
10118            .breakpoint_store
10119            .as_ref()?
10120            .read_with(cx, |breakpoint_store, cx| {
10121                breakpoint_store
10122                    .breakpoints(
10123                        &buffer,
10124                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10125                        &buffer_snapshot,
10126                        cx,
10127                    )
10128                    .next()
10129                    .and_then(|(bp, _)| {
10130                        let breakpoint_row = buffer_snapshot
10131                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10132                            .row;
10133
10134                        if breakpoint_row == row {
10135                            snapshot
10136                                .buffer_snapshot
10137                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10138                                .map(|position| (position, bp.bp.clone()))
10139                        } else {
10140                            None
10141                        }
10142                    })
10143            });
10144        bp
10145    }
10146
10147    pub fn edit_log_breakpoint(
10148        &mut self,
10149        _: &EditLogBreakpoint,
10150        window: &mut Window,
10151        cx: &mut Context<Self>,
10152    ) {
10153        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10154            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10155                message: None,
10156                state: BreakpointState::Enabled,
10157                condition: None,
10158                hit_condition: None,
10159            });
10160
10161            self.add_edit_breakpoint_block(
10162                anchor,
10163                &breakpoint,
10164                BreakpointPromptEditAction::Log,
10165                window,
10166                cx,
10167            );
10168        }
10169    }
10170
10171    fn breakpoints_at_cursors(
10172        &self,
10173        window: &mut Window,
10174        cx: &mut Context<Self>,
10175    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10176        let snapshot = self.snapshot(window, cx);
10177        let cursors = self
10178            .selections
10179            .disjoint_anchors()
10180            .into_iter()
10181            .map(|selection| {
10182                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10183
10184                let breakpoint_position = self
10185                    .breakpoint_at_row(cursor_position.row, window, cx)
10186                    .map(|bp| bp.0)
10187                    .unwrap_or_else(|| {
10188                        snapshot
10189                            .display_snapshot
10190                            .buffer_snapshot
10191                            .anchor_after(Point::new(cursor_position.row, 0))
10192                    });
10193
10194                let breakpoint = self
10195                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10196                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10197
10198                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10199            })
10200            // 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.
10201            .collect::<HashMap<Anchor, _>>();
10202
10203        cursors.into_iter().collect()
10204    }
10205
10206    pub fn enable_breakpoint(
10207        &mut self,
10208        _: &crate::actions::EnableBreakpoint,
10209        window: &mut Window,
10210        cx: &mut Context<Self>,
10211    ) {
10212        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10213            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10214                continue;
10215            };
10216            self.edit_breakpoint_at_anchor(
10217                anchor,
10218                breakpoint,
10219                BreakpointEditAction::InvertState,
10220                cx,
10221            );
10222        }
10223    }
10224
10225    pub fn disable_breakpoint(
10226        &mut self,
10227        _: &crate::actions::DisableBreakpoint,
10228        window: &mut Window,
10229        cx: &mut Context<Self>,
10230    ) {
10231        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10232            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10233                continue;
10234            };
10235            self.edit_breakpoint_at_anchor(
10236                anchor,
10237                breakpoint,
10238                BreakpointEditAction::InvertState,
10239                cx,
10240            );
10241        }
10242    }
10243
10244    pub fn toggle_breakpoint(
10245        &mut self,
10246        _: &crate::actions::ToggleBreakpoint,
10247        window: &mut Window,
10248        cx: &mut Context<Self>,
10249    ) {
10250        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10251            if let Some(breakpoint) = breakpoint {
10252                self.edit_breakpoint_at_anchor(
10253                    anchor,
10254                    breakpoint,
10255                    BreakpointEditAction::Toggle,
10256                    cx,
10257                );
10258            } else {
10259                self.edit_breakpoint_at_anchor(
10260                    anchor,
10261                    Breakpoint::new_standard(),
10262                    BreakpointEditAction::Toggle,
10263                    cx,
10264                );
10265            }
10266        }
10267    }
10268
10269    pub fn edit_breakpoint_at_anchor(
10270        &mut self,
10271        breakpoint_position: Anchor,
10272        breakpoint: Breakpoint,
10273        edit_action: BreakpointEditAction,
10274        cx: &mut Context<Self>,
10275    ) {
10276        let Some(breakpoint_store) = &self.breakpoint_store else {
10277            return;
10278        };
10279
10280        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10281            if breakpoint_position == Anchor::min() {
10282                self.buffer()
10283                    .read(cx)
10284                    .excerpt_buffer_ids()
10285                    .into_iter()
10286                    .next()
10287            } else {
10288                None
10289            }
10290        }) else {
10291            return;
10292        };
10293
10294        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10295            return;
10296        };
10297
10298        breakpoint_store.update(cx, |breakpoint_store, cx| {
10299            breakpoint_store.toggle_breakpoint(
10300                buffer,
10301                BreakpointWithPosition {
10302                    position: breakpoint_position.text_anchor,
10303                    bp: breakpoint,
10304                },
10305                edit_action,
10306                cx,
10307            );
10308        });
10309
10310        cx.notify();
10311    }
10312
10313    #[cfg(any(test, feature = "test-support"))]
10314    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10315        self.breakpoint_store.clone()
10316    }
10317
10318    pub fn prepare_restore_change(
10319        &self,
10320        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10321        hunk: &MultiBufferDiffHunk,
10322        cx: &mut App,
10323    ) -> Option<()> {
10324        if hunk.is_created_file() {
10325            return None;
10326        }
10327        let buffer = self.buffer.read(cx);
10328        let diff = buffer.diff_for(hunk.buffer_id)?;
10329        let buffer = buffer.buffer(hunk.buffer_id)?;
10330        let buffer = buffer.read(cx);
10331        let original_text = diff
10332            .read(cx)
10333            .base_text()
10334            .as_rope()
10335            .slice(hunk.diff_base_byte_range.clone());
10336        let buffer_snapshot = buffer.snapshot();
10337        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10338        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10339            probe
10340                .0
10341                .start
10342                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10343                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10344        }) {
10345            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10346            Some(())
10347        } else {
10348            None
10349        }
10350    }
10351
10352    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10353        self.manipulate_lines(window, cx, |lines| lines.reverse())
10354    }
10355
10356    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10357        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10358    }
10359
10360    fn manipulate_lines<Fn>(
10361        &mut self,
10362        window: &mut Window,
10363        cx: &mut Context<Self>,
10364        mut callback: Fn,
10365    ) where
10366        Fn: FnMut(&mut Vec<&str>),
10367    {
10368        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10369
10370        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10371        let buffer = self.buffer.read(cx).snapshot(cx);
10372
10373        let mut edits = Vec::new();
10374
10375        let selections = self.selections.all::<Point>(cx);
10376        let mut selections = selections.iter().peekable();
10377        let mut contiguous_row_selections = Vec::new();
10378        let mut new_selections = Vec::new();
10379        let mut added_lines = 0;
10380        let mut removed_lines = 0;
10381
10382        while let Some(selection) = selections.next() {
10383            let (start_row, end_row) = consume_contiguous_rows(
10384                &mut contiguous_row_selections,
10385                selection,
10386                &display_map,
10387                &mut selections,
10388            );
10389
10390            let start_point = Point::new(start_row.0, 0);
10391            let end_point = Point::new(
10392                end_row.previous_row().0,
10393                buffer.line_len(end_row.previous_row()),
10394            );
10395            let text = buffer
10396                .text_for_range(start_point..end_point)
10397                .collect::<String>();
10398
10399            let mut lines = text.split('\n').collect_vec();
10400
10401            let lines_before = lines.len();
10402            callback(&mut lines);
10403            let lines_after = lines.len();
10404
10405            edits.push((start_point..end_point, lines.join("\n")));
10406
10407            // Selections must change based on added and removed line count
10408            let start_row =
10409                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10410            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10411            new_selections.push(Selection {
10412                id: selection.id,
10413                start: start_row,
10414                end: end_row,
10415                goal: SelectionGoal::None,
10416                reversed: selection.reversed,
10417            });
10418
10419            if lines_after > lines_before {
10420                added_lines += lines_after - lines_before;
10421            } else if lines_before > lines_after {
10422                removed_lines += lines_before - lines_after;
10423            }
10424        }
10425
10426        self.transact(window, cx, |this, window, cx| {
10427            let buffer = this.buffer.update(cx, |buffer, cx| {
10428                buffer.edit(edits, None, cx);
10429                buffer.snapshot(cx)
10430            });
10431
10432            // Recalculate offsets on newly edited buffer
10433            let new_selections = new_selections
10434                .iter()
10435                .map(|s| {
10436                    let start_point = Point::new(s.start.0, 0);
10437                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10438                    Selection {
10439                        id: s.id,
10440                        start: buffer.point_to_offset(start_point),
10441                        end: buffer.point_to_offset(end_point),
10442                        goal: s.goal,
10443                        reversed: s.reversed,
10444                    }
10445                })
10446                .collect();
10447
10448            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10449                s.select(new_selections);
10450            });
10451
10452            this.request_autoscroll(Autoscroll::fit(), cx);
10453        });
10454    }
10455
10456    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10457        self.manipulate_text(window, cx, |text| {
10458            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10459            if has_upper_case_characters {
10460                text.to_lowercase()
10461            } else {
10462                text.to_uppercase()
10463            }
10464        })
10465    }
10466
10467    pub fn convert_to_upper_case(
10468        &mut self,
10469        _: &ConvertToUpperCase,
10470        window: &mut Window,
10471        cx: &mut Context<Self>,
10472    ) {
10473        self.manipulate_text(window, cx, |text| text.to_uppercase())
10474    }
10475
10476    pub fn convert_to_lower_case(
10477        &mut self,
10478        _: &ConvertToLowerCase,
10479        window: &mut Window,
10480        cx: &mut Context<Self>,
10481    ) {
10482        self.manipulate_text(window, cx, |text| text.to_lowercase())
10483    }
10484
10485    pub fn convert_to_title_case(
10486        &mut self,
10487        _: &ConvertToTitleCase,
10488        window: &mut Window,
10489        cx: &mut Context<Self>,
10490    ) {
10491        self.manipulate_text(window, cx, |text| {
10492            text.split('\n')
10493                .map(|line| line.to_case(Case::Title))
10494                .join("\n")
10495        })
10496    }
10497
10498    pub fn convert_to_snake_case(
10499        &mut self,
10500        _: &ConvertToSnakeCase,
10501        window: &mut Window,
10502        cx: &mut Context<Self>,
10503    ) {
10504        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10505    }
10506
10507    pub fn convert_to_kebab_case(
10508        &mut self,
10509        _: &ConvertToKebabCase,
10510        window: &mut Window,
10511        cx: &mut Context<Self>,
10512    ) {
10513        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10514    }
10515
10516    pub fn convert_to_upper_camel_case(
10517        &mut self,
10518        _: &ConvertToUpperCamelCase,
10519        window: &mut Window,
10520        cx: &mut Context<Self>,
10521    ) {
10522        self.manipulate_text(window, cx, |text| {
10523            text.split('\n')
10524                .map(|line| line.to_case(Case::UpperCamel))
10525                .join("\n")
10526        })
10527    }
10528
10529    pub fn convert_to_lower_camel_case(
10530        &mut self,
10531        _: &ConvertToLowerCamelCase,
10532        window: &mut Window,
10533        cx: &mut Context<Self>,
10534    ) {
10535        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10536    }
10537
10538    pub fn convert_to_opposite_case(
10539        &mut self,
10540        _: &ConvertToOppositeCase,
10541        window: &mut Window,
10542        cx: &mut Context<Self>,
10543    ) {
10544        self.manipulate_text(window, cx, |text| {
10545            text.chars()
10546                .fold(String::with_capacity(text.len()), |mut t, c| {
10547                    if c.is_uppercase() {
10548                        t.extend(c.to_lowercase());
10549                    } else {
10550                        t.extend(c.to_uppercase());
10551                    }
10552                    t
10553                })
10554        })
10555    }
10556
10557    pub fn convert_to_rot13(
10558        &mut self,
10559        _: &ConvertToRot13,
10560        window: &mut Window,
10561        cx: &mut Context<Self>,
10562    ) {
10563        self.manipulate_text(window, cx, |text| {
10564            text.chars()
10565                .map(|c| match c {
10566                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10567                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10568                    _ => c,
10569                })
10570                .collect()
10571        })
10572    }
10573
10574    pub fn convert_to_rot47(
10575        &mut self,
10576        _: &ConvertToRot47,
10577        window: &mut Window,
10578        cx: &mut Context<Self>,
10579    ) {
10580        self.manipulate_text(window, cx, |text| {
10581            text.chars()
10582                .map(|c| {
10583                    let code_point = c as u32;
10584                    if code_point >= 33 && code_point <= 126 {
10585                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10586                    }
10587                    c
10588                })
10589                .collect()
10590        })
10591    }
10592
10593    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10594    where
10595        Fn: FnMut(&str) -> String,
10596    {
10597        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10598        let buffer = self.buffer.read(cx).snapshot(cx);
10599
10600        let mut new_selections = Vec::new();
10601        let mut edits = Vec::new();
10602        let mut selection_adjustment = 0i32;
10603
10604        for selection in self.selections.all::<usize>(cx) {
10605            let selection_is_empty = selection.is_empty();
10606
10607            let (start, end) = if selection_is_empty {
10608                let word_range = movement::surrounding_word(
10609                    &display_map,
10610                    selection.start.to_display_point(&display_map),
10611                );
10612                let start = word_range.start.to_offset(&display_map, Bias::Left);
10613                let end = word_range.end.to_offset(&display_map, Bias::Left);
10614                (start, end)
10615            } else {
10616                (selection.start, selection.end)
10617            };
10618
10619            let text = buffer.text_for_range(start..end).collect::<String>();
10620            let old_length = text.len() as i32;
10621            let text = callback(&text);
10622
10623            new_selections.push(Selection {
10624                start: (start as i32 - selection_adjustment) as usize,
10625                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10626                goal: SelectionGoal::None,
10627                ..selection
10628            });
10629
10630            selection_adjustment += old_length - text.len() as i32;
10631
10632            edits.push((start..end, text));
10633        }
10634
10635        self.transact(window, cx, |this, window, cx| {
10636            this.buffer.update(cx, |buffer, cx| {
10637                buffer.edit(edits, None, cx);
10638            });
10639
10640            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10641                s.select(new_selections);
10642            });
10643
10644            this.request_autoscroll(Autoscroll::fit(), cx);
10645        });
10646    }
10647
10648    pub fn move_selection_on_drop(
10649        &mut self,
10650        selection: &Selection<Anchor>,
10651        target: DisplayPoint,
10652        is_cut: bool,
10653        window: &mut Window,
10654        cx: &mut Context<Self>,
10655    ) {
10656        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10657        let buffer = &display_map.buffer_snapshot;
10658        let mut edits = Vec::new();
10659        let insert_point = display_map
10660            .clip_point(target, Bias::Left)
10661            .to_point(&display_map);
10662        let text = buffer
10663            .text_for_range(selection.start..selection.end)
10664            .collect::<String>();
10665        if is_cut {
10666            edits.push(((selection.start..selection.end), String::new()));
10667        }
10668        let insert_anchor = buffer.anchor_before(insert_point);
10669        edits.push(((insert_anchor..insert_anchor), text));
10670        let last_edit_start = insert_anchor.bias_left(buffer);
10671        let last_edit_end = insert_anchor.bias_right(buffer);
10672        self.transact(window, cx, |this, window, cx| {
10673            this.buffer.update(cx, |buffer, cx| {
10674                buffer.edit(edits, None, cx);
10675            });
10676            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10677                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10678            });
10679        });
10680    }
10681
10682    pub fn clear_selection_drag_state(&mut self) {
10683        self.selection_drag_state = SelectionDragState::None;
10684    }
10685
10686    pub fn duplicate(
10687        &mut self,
10688        upwards: bool,
10689        whole_lines: bool,
10690        window: &mut Window,
10691        cx: &mut Context<Self>,
10692    ) {
10693        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10694
10695        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10696        let buffer = &display_map.buffer_snapshot;
10697        let selections = self.selections.all::<Point>(cx);
10698
10699        let mut edits = Vec::new();
10700        let mut selections_iter = selections.iter().peekable();
10701        while let Some(selection) = selections_iter.next() {
10702            let mut rows = selection.spanned_rows(false, &display_map);
10703            // duplicate line-wise
10704            if whole_lines || selection.start == selection.end {
10705                // Avoid duplicating the same lines twice.
10706                while let Some(next_selection) = selections_iter.peek() {
10707                    let next_rows = next_selection.spanned_rows(false, &display_map);
10708                    if next_rows.start < rows.end {
10709                        rows.end = next_rows.end;
10710                        selections_iter.next().unwrap();
10711                    } else {
10712                        break;
10713                    }
10714                }
10715
10716                // Copy the text from the selected row region and splice it either at the start
10717                // or end of the region.
10718                let start = Point::new(rows.start.0, 0);
10719                let end = Point::new(
10720                    rows.end.previous_row().0,
10721                    buffer.line_len(rows.end.previous_row()),
10722                );
10723                let text = buffer
10724                    .text_for_range(start..end)
10725                    .chain(Some("\n"))
10726                    .collect::<String>();
10727                let insert_location = if upwards {
10728                    Point::new(rows.end.0, 0)
10729                } else {
10730                    start
10731                };
10732                edits.push((insert_location..insert_location, text));
10733            } else {
10734                // duplicate character-wise
10735                let start = selection.start;
10736                let end = selection.end;
10737                let text = buffer.text_for_range(start..end).collect::<String>();
10738                edits.push((selection.end..selection.end, text));
10739            }
10740        }
10741
10742        self.transact(window, cx, |this, _, cx| {
10743            this.buffer.update(cx, |buffer, cx| {
10744                buffer.edit(edits, None, cx);
10745            });
10746
10747            this.request_autoscroll(Autoscroll::fit(), cx);
10748        });
10749    }
10750
10751    pub fn duplicate_line_up(
10752        &mut self,
10753        _: &DuplicateLineUp,
10754        window: &mut Window,
10755        cx: &mut Context<Self>,
10756    ) {
10757        self.duplicate(true, true, window, cx);
10758    }
10759
10760    pub fn duplicate_line_down(
10761        &mut self,
10762        _: &DuplicateLineDown,
10763        window: &mut Window,
10764        cx: &mut Context<Self>,
10765    ) {
10766        self.duplicate(false, true, window, cx);
10767    }
10768
10769    pub fn duplicate_selection(
10770        &mut self,
10771        _: &DuplicateSelection,
10772        window: &mut Window,
10773        cx: &mut Context<Self>,
10774    ) {
10775        self.duplicate(false, false, window, cx);
10776    }
10777
10778    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10779        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10780
10781        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10782        let buffer = self.buffer.read(cx).snapshot(cx);
10783
10784        let mut edits = Vec::new();
10785        let mut unfold_ranges = Vec::new();
10786        let mut refold_creases = Vec::new();
10787
10788        let selections = self.selections.all::<Point>(cx);
10789        let mut selections = selections.iter().peekable();
10790        let mut contiguous_row_selections = Vec::new();
10791        let mut new_selections = Vec::new();
10792
10793        while let Some(selection) = selections.next() {
10794            // Find all the selections that span a contiguous row range
10795            let (start_row, end_row) = consume_contiguous_rows(
10796                &mut contiguous_row_selections,
10797                selection,
10798                &display_map,
10799                &mut selections,
10800            );
10801
10802            // Move the text spanned by the row range to be before the line preceding the row range
10803            if start_row.0 > 0 {
10804                let range_to_move = Point::new(
10805                    start_row.previous_row().0,
10806                    buffer.line_len(start_row.previous_row()),
10807                )
10808                    ..Point::new(
10809                        end_row.previous_row().0,
10810                        buffer.line_len(end_row.previous_row()),
10811                    );
10812                let insertion_point = display_map
10813                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10814                    .0;
10815
10816                // Don't move lines across excerpts
10817                if buffer
10818                    .excerpt_containing(insertion_point..range_to_move.end)
10819                    .is_some()
10820                {
10821                    let text = buffer
10822                        .text_for_range(range_to_move.clone())
10823                        .flat_map(|s| s.chars())
10824                        .skip(1)
10825                        .chain(['\n'])
10826                        .collect::<String>();
10827
10828                    edits.push((
10829                        buffer.anchor_after(range_to_move.start)
10830                            ..buffer.anchor_before(range_to_move.end),
10831                        String::new(),
10832                    ));
10833                    let insertion_anchor = buffer.anchor_after(insertion_point);
10834                    edits.push((insertion_anchor..insertion_anchor, text));
10835
10836                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10837
10838                    // Move selections up
10839                    new_selections.extend(contiguous_row_selections.drain(..).map(
10840                        |mut selection| {
10841                            selection.start.row -= row_delta;
10842                            selection.end.row -= row_delta;
10843                            selection
10844                        },
10845                    ));
10846
10847                    // Move folds up
10848                    unfold_ranges.push(range_to_move.clone());
10849                    for fold in display_map.folds_in_range(
10850                        buffer.anchor_before(range_to_move.start)
10851                            ..buffer.anchor_after(range_to_move.end),
10852                    ) {
10853                        let mut start = fold.range.start.to_point(&buffer);
10854                        let mut end = fold.range.end.to_point(&buffer);
10855                        start.row -= row_delta;
10856                        end.row -= row_delta;
10857                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10858                    }
10859                }
10860            }
10861
10862            // If we didn't move line(s), preserve the existing selections
10863            new_selections.append(&mut contiguous_row_selections);
10864        }
10865
10866        self.transact(window, cx, |this, window, cx| {
10867            this.unfold_ranges(&unfold_ranges, true, true, cx);
10868            this.buffer.update(cx, |buffer, cx| {
10869                for (range, text) in edits {
10870                    buffer.edit([(range, text)], None, cx);
10871                }
10872            });
10873            this.fold_creases(refold_creases, true, window, cx);
10874            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10875                s.select(new_selections);
10876            })
10877        });
10878    }
10879
10880    pub fn move_line_down(
10881        &mut self,
10882        _: &MoveLineDown,
10883        window: &mut Window,
10884        cx: &mut Context<Self>,
10885    ) {
10886        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10887
10888        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10889        let buffer = self.buffer.read(cx).snapshot(cx);
10890
10891        let mut edits = Vec::new();
10892        let mut unfold_ranges = Vec::new();
10893        let mut refold_creases = Vec::new();
10894
10895        let selections = self.selections.all::<Point>(cx);
10896        let mut selections = selections.iter().peekable();
10897        let mut contiguous_row_selections = Vec::new();
10898        let mut new_selections = Vec::new();
10899
10900        while let Some(selection) = selections.next() {
10901            // Find all the selections that span a contiguous row range
10902            let (start_row, end_row) = consume_contiguous_rows(
10903                &mut contiguous_row_selections,
10904                selection,
10905                &display_map,
10906                &mut selections,
10907            );
10908
10909            // Move the text spanned by the row range to be after the last line of the row range
10910            if end_row.0 <= buffer.max_point().row {
10911                let range_to_move =
10912                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10913                let insertion_point = display_map
10914                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10915                    .0;
10916
10917                // Don't move lines across excerpt boundaries
10918                if buffer
10919                    .excerpt_containing(range_to_move.start..insertion_point)
10920                    .is_some()
10921                {
10922                    let mut text = String::from("\n");
10923                    text.extend(buffer.text_for_range(range_to_move.clone()));
10924                    text.pop(); // Drop trailing newline
10925                    edits.push((
10926                        buffer.anchor_after(range_to_move.start)
10927                            ..buffer.anchor_before(range_to_move.end),
10928                        String::new(),
10929                    ));
10930                    let insertion_anchor = buffer.anchor_after(insertion_point);
10931                    edits.push((insertion_anchor..insertion_anchor, text));
10932
10933                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10934
10935                    // Move selections down
10936                    new_selections.extend(contiguous_row_selections.drain(..).map(
10937                        |mut selection| {
10938                            selection.start.row += row_delta;
10939                            selection.end.row += row_delta;
10940                            selection
10941                        },
10942                    ));
10943
10944                    // Move folds down
10945                    unfold_ranges.push(range_to_move.clone());
10946                    for fold in display_map.folds_in_range(
10947                        buffer.anchor_before(range_to_move.start)
10948                            ..buffer.anchor_after(range_to_move.end),
10949                    ) {
10950                        let mut start = fold.range.start.to_point(&buffer);
10951                        let mut end = fold.range.end.to_point(&buffer);
10952                        start.row += row_delta;
10953                        end.row += row_delta;
10954                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10955                    }
10956                }
10957            }
10958
10959            // If we didn't move line(s), preserve the existing selections
10960            new_selections.append(&mut contiguous_row_selections);
10961        }
10962
10963        self.transact(window, cx, |this, window, cx| {
10964            this.unfold_ranges(&unfold_ranges, true, true, cx);
10965            this.buffer.update(cx, |buffer, cx| {
10966                for (range, text) in edits {
10967                    buffer.edit([(range, text)], None, cx);
10968                }
10969            });
10970            this.fold_creases(refold_creases, true, window, cx);
10971            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10972                s.select(new_selections)
10973            });
10974        });
10975    }
10976
10977    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10978        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10979        let text_layout_details = &self.text_layout_details(window);
10980        self.transact(window, cx, |this, window, cx| {
10981            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10982                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10983                s.move_with(|display_map, selection| {
10984                    if !selection.is_empty() {
10985                        return;
10986                    }
10987
10988                    let mut head = selection.head();
10989                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10990                    if head.column() == display_map.line_len(head.row()) {
10991                        transpose_offset = display_map
10992                            .buffer_snapshot
10993                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10994                    }
10995
10996                    if transpose_offset == 0 {
10997                        return;
10998                    }
10999
11000                    *head.column_mut() += 1;
11001                    head = display_map.clip_point(head, Bias::Right);
11002                    let goal = SelectionGoal::HorizontalPosition(
11003                        display_map
11004                            .x_for_display_point(head, text_layout_details)
11005                            .into(),
11006                    );
11007                    selection.collapse_to(head, goal);
11008
11009                    let transpose_start = display_map
11010                        .buffer_snapshot
11011                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11012                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11013                        let transpose_end = display_map
11014                            .buffer_snapshot
11015                            .clip_offset(transpose_offset + 1, Bias::Right);
11016                        if let Some(ch) =
11017                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11018                        {
11019                            edits.push((transpose_start..transpose_offset, String::new()));
11020                            edits.push((transpose_end..transpose_end, ch.to_string()));
11021                        }
11022                    }
11023                });
11024                edits
11025            });
11026            this.buffer
11027                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11028            let selections = this.selections.all::<usize>(cx);
11029            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11030                s.select(selections);
11031            });
11032        });
11033    }
11034
11035    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11036        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11037        self.rewrap_impl(RewrapOptions::default(), cx)
11038    }
11039
11040    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11041        let buffer = self.buffer.read(cx).snapshot(cx);
11042        let selections = self.selections.all::<Point>(cx);
11043
11044        // Shrink and split selections to respect paragraph boundaries.
11045        let ranges = selections.into_iter().flat_map(|selection| {
11046            let language_settings = buffer.language_settings_at(selection.head(), cx);
11047            let language_scope = buffer.language_scope_at(selection.head());
11048
11049            let Some(start_row) = (selection.start.row..=selection.end.row)
11050                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11051            else {
11052                return vec![];
11053            };
11054            let Some(end_row) = (selection.start.row..=selection.end.row)
11055                .rev()
11056                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11057            else {
11058                return vec![];
11059            };
11060
11061            let mut row = start_row;
11062            let mut ranges = Vec::new();
11063            while let Some(blank_row) =
11064                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11065            {
11066                let next_paragraph_start = (blank_row + 1..=end_row)
11067                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11068                    .unwrap();
11069                ranges.push((
11070                    language_settings.clone(),
11071                    language_scope.clone(),
11072                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11073                ));
11074                row = next_paragraph_start;
11075            }
11076            ranges.push((
11077                language_settings.clone(),
11078                language_scope.clone(),
11079                Point::new(row, 0)..Point::new(end_row, 0),
11080            ));
11081
11082            ranges
11083        });
11084
11085        let mut edits = Vec::new();
11086        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11087
11088        for (language_settings, language_scope, range) in ranges {
11089            let mut start_row = range.start.row;
11090            let mut end_row = range.end.row;
11091
11092            // Skip selections that overlap with a range that has already been rewrapped.
11093            let selection_range = start_row..end_row;
11094            if rewrapped_row_ranges
11095                .iter()
11096                .any(|range| range.overlaps(&selection_range))
11097            {
11098                continue;
11099            }
11100
11101            let tab_size = language_settings.tab_size;
11102
11103            // Since not all lines in the selection may be at the same indent
11104            // level, choose the indent size that is the most common between all
11105            // of the lines.
11106            //
11107            // If there is a tie, we use the deepest indent.
11108            let (indent_size, indent_end) = {
11109                let mut indent_size_occurrences = HashMap::default();
11110                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11111
11112                for row in start_row..=end_row {
11113                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11114                    rows_by_indent_size.entry(indent).or_default().push(row);
11115                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11116                }
11117
11118                let indent_size = indent_size_occurrences
11119                    .into_iter()
11120                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11121                    .map(|(indent, _)| indent)
11122                    .unwrap_or_default();
11123                let row = rows_by_indent_size[&indent_size][0];
11124                let indent_end = Point::new(row, indent_size.len);
11125
11126                (indent_size, indent_end)
11127            };
11128
11129            let mut line_prefix = indent_size.chars().collect::<String>();
11130
11131            let mut inside_comment = false;
11132            if let Some(comment_prefix) = language_scope.and_then(|language| {
11133                language
11134                    .line_comment_prefixes()
11135                    .iter()
11136                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11137                    .cloned()
11138            }) {
11139                line_prefix.push_str(&comment_prefix);
11140                inside_comment = true;
11141            }
11142
11143            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11144                RewrapBehavior::InComments => inside_comment,
11145                RewrapBehavior::InSelections => !range.is_empty(),
11146                RewrapBehavior::Anywhere => true,
11147            };
11148
11149            let should_rewrap = options.override_language_settings
11150                || allow_rewrap_based_on_language
11151                || self.hard_wrap.is_some();
11152            if !should_rewrap {
11153                continue;
11154            }
11155
11156            if range.is_empty() {
11157                'expand_upwards: while start_row > 0 {
11158                    let prev_row = start_row - 1;
11159                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11160                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11161                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11162                    {
11163                        start_row = prev_row;
11164                    } else {
11165                        break 'expand_upwards;
11166                    }
11167                }
11168
11169                'expand_downwards: while end_row < buffer.max_point().row {
11170                    let next_row = end_row + 1;
11171                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11172                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11173                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11174                    {
11175                        end_row = next_row;
11176                    } else {
11177                        break 'expand_downwards;
11178                    }
11179                }
11180            }
11181
11182            let start = Point::new(start_row, 0);
11183            let start_offset = start.to_offset(&buffer);
11184            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11185            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11186            let Some(lines_without_prefixes) = selection_text
11187                .lines()
11188                .map(|line| {
11189                    line.strip_prefix(&line_prefix)
11190                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11191                        .with_context(|| {
11192                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11193                        })
11194                })
11195                .collect::<Result<Vec<_>, _>>()
11196                .log_err()
11197            else {
11198                continue;
11199            };
11200
11201            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11202                buffer
11203                    .language_settings_at(Point::new(start_row, 0), cx)
11204                    .preferred_line_length as usize
11205            });
11206            let wrapped_text = wrap_with_prefix(
11207                line_prefix,
11208                lines_without_prefixes.join("\n"),
11209                wrap_column,
11210                tab_size,
11211                options.preserve_existing_whitespace,
11212            );
11213
11214            // TODO: should always use char-based diff while still supporting cursor behavior that
11215            // matches vim.
11216            let mut diff_options = DiffOptions::default();
11217            if options.override_language_settings {
11218                diff_options.max_word_diff_len = 0;
11219                diff_options.max_word_diff_line_count = 0;
11220            } else {
11221                diff_options.max_word_diff_len = usize::MAX;
11222                diff_options.max_word_diff_line_count = usize::MAX;
11223            }
11224
11225            for (old_range, new_text) in
11226                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11227            {
11228                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11229                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11230                edits.push((edit_start..edit_end, new_text));
11231            }
11232
11233            rewrapped_row_ranges.push(start_row..=end_row);
11234        }
11235
11236        self.buffer
11237            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11238    }
11239
11240    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11241        let mut text = String::new();
11242        let buffer = self.buffer.read(cx).snapshot(cx);
11243        let mut selections = self.selections.all::<Point>(cx);
11244        let mut clipboard_selections = Vec::with_capacity(selections.len());
11245        {
11246            let max_point = buffer.max_point();
11247            let mut is_first = true;
11248            for selection in &mut selections {
11249                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11250                if is_entire_line {
11251                    selection.start = Point::new(selection.start.row, 0);
11252                    if !selection.is_empty() && selection.end.column == 0 {
11253                        selection.end = cmp::min(max_point, selection.end);
11254                    } else {
11255                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11256                    }
11257                    selection.goal = SelectionGoal::None;
11258                }
11259                if is_first {
11260                    is_first = false;
11261                } else {
11262                    text += "\n";
11263                }
11264                let mut len = 0;
11265                for chunk in buffer.text_for_range(selection.start..selection.end) {
11266                    text.push_str(chunk);
11267                    len += chunk.len();
11268                }
11269                clipboard_selections.push(ClipboardSelection {
11270                    len,
11271                    is_entire_line,
11272                    first_line_indent: buffer
11273                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11274                        .len,
11275                });
11276            }
11277        }
11278
11279        self.transact(window, cx, |this, window, cx| {
11280            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11281                s.select(selections);
11282            });
11283            this.insert("", window, cx);
11284        });
11285        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11286    }
11287
11288    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11289        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11290        let item = self.cut_common(window, cx);
11291        cx.write_to_clipboard(item);
11292    }
11293
11294    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11295        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11296        self.change_selections(None, window, cx, |s| {
11297            s.move_with(|snapshot, sel| {
11298                if sel.is_empty() {
11299                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11300                }
11301            });
11302        });
11303        let item = self.cut_common(window, cx);
11304        cx.set_global(KillRing(item))
11305    }
11306
11307    pub fn kill_ring_yank(
11308        &mut self,
11309        _: &KillRingYank,
11310        window: &mut Window,
11311        cx: &mut Context<Self>,
11312    ) {
11313        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11314        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11315            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11316                (kill_ring.text().to_string(), kill_ring.metadata_json())
11317            } else {
11318                return;
11319            }
11320        } else {
11321            return;
11322        };
11323        self.do_paste(&text, metadata, false, window, cx);
11324    }
11325
11326    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11327        self.do_copy(true, cx);
11328    }
11329
11330    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11331        self.do_copy(false, cx);
11332    }
11333
11334    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11335        let selections = self.selections.all::<Point>(cx);
11336        let buffer = self.buffer.read(cx).read(cx);
11337        let mut text = String::new();
11338
11339        let mut clipboard_selections = Vec::with_capacity(selections.len());
11340        {
11341            let max_point = buffer.max_point();
11342            let mut is_first = true;
11343            for selection in &selections {
11344                let mut start = selection.start;
11345                let mut end = selection.end;
11346                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11347                if is_entire_line {
11348                    start = Point::new(start.row, 0);
11349                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11350                }
11351
11352                let mut trimmed_selections = Vec::new();
11353                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11354                    let row = MultiBufferRow(start.row);
11355                    let first_indent = buffer.indent_size_for_line(row);
11356                    if first_indent.len == 0 || start.column > first_indent.len {
11357                        trimmed_selections.push(start..end);
11358                    } else {
11359                        trimmed_selections.push(
11360                            Point::new(row.0, first_indent.len)
11361                                ..Point::new(row.0, buffer.line_len(row)),
11362                        );
11363                        for row in start.row + 1..=end.row {
11364                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11365                            if row == end.row {
11366                                line_len = end.column;
11367                            }
11368                            if line_len == 0 {
11369                                trimmed_selections
11370                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11371                                continue;
11372                            }
11373                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11374                            if row_indent_size.len >= first_indent.len {
11375                                trimmed_selections.push(
11376                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11377                                );
11378                            } else {
11379                                trimmed_selections.clear();
11380                                trimmed_selections.push(start..end);
11381                                break;
11382                            }
11383                        }
11384                    }
11385                } else {
11386                    trimmed_selections.push(start..end);
11387                }
11388
11389                for trimmed_range in trimmed_selections {
11390                    if is_first {
11391                        is_first = false;
11392                    } else {
11393                        text += "\n";
11394                    }
11395                    let mut len = 0;
11396                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11397                        text.push_str(chunk);
11398                        len += chunk.len();
11399                    }
11400                    clipboard_selections.push(ClipboardSelection {
11401                        len,
11402                        is_entire_line,
11403                        first_line_indent: buffer
11404                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11405                            .len,
11406                    });
11407                }
11408            }
11409        }
11410
11411        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11412            text,
11413            clipboard_selections,
11414        ));
11415    }
11416
11417    pub fn do_paste(
11418        &mut self,
11419        text: &String,
11420        clipboard_selections: Option<Vec<ClipboardSelection>>,
11421        handle_entire_lines: bool,
11422        window: &mut Window,
11423        cx: &mut Context<Self>,
11424    ) {
11425        if self.read_only(cx) {
11426            return;
11427        }
11428
11429        let clipboard_text = Cow::Borrowed(text);
11430
11431        self.transact(window, cx, |this, window, cx| {
11432            if let Some(mut clipboard_selections) = clipboard_selections {
11433                let old_selections = this.selections.all::<usize>(cx);
11434                let all_selections_were_entire_line =
11435                    clipboard_selections.iter().all(|s| s.is_entire_line);
11436                let first_selection_indent_column =
11437                    clipboard_selections.first().map(|s| s.first_line_indent);
11438                if clipboard_selections.len() != old_selections.len() {
11439                    clipboard_selections.drain(..);
11440                }
11441                let cursor_offset = this.selections.last::<usize>(cx).head();
11442                let mut auto_indent_on_paste = true;
11443
11444                this.buffer.update(cx, |buffer, cx| {
11445                    let snapshot = buffer.read(cx);
11446                    auto_indent_on_paste = snapshot
11447                        .language_settings_at(cursor_offset, cx)
11448                        .auto_indent_on_paste;
11449
11450                    let mut start_offset = 0;
11451                    let mut edits = Vec::new();
11452                    let mut original_indent_columns = Vec::new();
11453                    for (ix, selection) in old_selections.iter().enumerate() {
11454                        let to_insert;
11455                        let entire_line;
11456                        let original_indent_column;
11457                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11458                            let end_offset = start_offset + clipboard_selection.len;
11459                            to_insert = &clipboard_text[start_offset..end_offset];
11460                            entire_line = clipboard_selection.is_entire_line;
11461                            start_offset = end_offset + 1;
11462                            original_indent_column = Some(clipboard_selection.first_line_indent);
11463                        } else {
11464                            to_insert = clipboard_text.as_str();
11465                            entire_line = all_selections_were_entire_line;
11466                            original_indent_column = first_selection_indent_column
11467                        }
11468
11469                        // If the corresponding selection was empty when this slice of the
11470                        // clipboard text was written, then the entire line containing the
11471                        // selection was copied. If this selection is also currently empty,
11472                        // then paste the line before the current line of the buffer.
11473                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11474                            let column = selection.start.to_point(&snapshot).column as usize;
11475                            let line_start = selection.start - column;
11476                            line_start..line_start
11477                        } else {
11478                            selection.range()
11479                        };
11480
11481                        edits.push((range, to_insert));
11482                        original_indent_columns.push(original_indent_column);
11483                    }
11484                    drop(snapshot);
11485
11486                    buffer.edit(
11487                        edits,
11488                        if auto_indent_on_paste {
11489                            Some(AutoindentMode::Block {
11490                                original_indent_columns,
11491                            })
11492                        } else {
11493                            None
11494                        },
11495                        cx,
11496                    );
11497                });
11498
11499                let selections = this.selections.all::<usize>(cx);
11500                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11501                    s.select(selections)
11502                });
11503            } else {
11504                this.insert(&clipboard_text, window, cx);
11505            }
11506        });
11507    }
11508
11509    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11510        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11511        if let Some(item) = cx.read_from_clipboard() {
11512            let entries = item.entries();
11513
11514            match entries.first() {
11515                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11516                // of all the pasted entries.
11517                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11518                    .do_paste(
11519                        clipboard_string.text(),
11520                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11521                        true,
11522                        window,
11523                        cx,
11524                    ),
11525                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11526            }
11527        }
11528    }
11529
11530    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11531        if self.read_only(cx) {
11532            return;
11533        }
11534
11535        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11536
11537        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11538            if let Some((selections, _)) =
11539                self.selection_history.transaction(transaction_id).cloned()
11540            {
11541                self.change_selections(None, window, cx, |s| {
11542                    s.select_anchors(selections.to_vec());
11543                });
11544            } else {
11545                log::error!(
11546                    "No entry in selection_history found for undo. \
11547                     This may correspond to a bug where undo does not update the selection. \
11548                     If this is occurring, please add details to \
11549                     https://github.com/zed-industries/zed/issues/22692"
11550                );
11551            }
11552            self.request_autoscroll(Autoscroll::fit(), cx);
11553            self.unmark_text(window, cx);
11554            self.refresh_inline_completion(true, false, window, cx);
11555            cx.emit(EditorEvent::Edited { transaction_id });
11556            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11557        }
11558    }
11559
11560    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11561        if self.read_only(cx) {
11562            return;
11563        }
11564
11565        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11566
11567        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11568            if let Some((_, Some(selections))) =
11569                self.selection_history.transaction(transaction_id).cloned()
11570            {
11571                self.change_selections(None, window, cx, |s| {
11572                    s.select_anchors(selections.to_vec());
11573                });
11574            } else {
11575                log::error!(
11576                    "No entry in selection_history found for redo. \
11577                     This may correspond to a bug where undo does not update the selection. \
11578                     If this is occurring, please add details to \
11579                     https://github.com/zed-industries/zed/issues/22692"
11580                );
11581            }
11582            self.request_autoscroll(Autoscroll::fit(), cx);
11583            self.unmark_text(window, cx);
11584            self.refresh_inline_completion(true, false, window, cx);
11585            cx.emit(EditorEvent::Edited { transaction_id });
11586        }
11587    }
11588
11589    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11590        self.buffer
11591            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11592    }
11593
11594    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11595        self.buffer
11596            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11597    }
11598
11599    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11600        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11601        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11602            s.move_with(|map, selection| {
11603                let cursor = if selection.is_empty() {
11604                    movement::left(map, selection.start)
11605                } else {
11606                    selection.start
11607                };
11608                selection.collapse_to(cursor, SelectionGoal::None);
11609            });
11610        })
11611    }
11612
11613    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11614        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11615        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11616            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11617        })
11618    }
11619
11620    pub fn move_right(&mut self, _: &MoveRight, 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_with(|map, selection| {
11624                let cursor = if selection.is_empty() {
11625                    movement::right(map, selection.end)
11626                } else {
11627                    selection.end
11628                };
11629                selection.collapse_to(cursor, SelectionGoal::None)
11630            });
11631        })
11632    }
11633
11634    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11635        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11636        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11637            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11638        })
11639    }
11640
11641    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11642        if self.take_rename(true, window, cx).is_some() {
11643            return;
11644        }
11645
11646        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11647            cx.propagate();
11648            return;
11649        }
11650
11651        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11652
11653        let text_layout_details = &self.text_layout_details(window);
11654        let selection_count = self.selections.count();
11655        let first_selection = self.selections.first_anchor();
11656
11657        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11658            s.move_with(|map, selection| {
11659                if !selection.is_empty() {
11660                    selection.goal = SelectionGoal::None;
11661                }
11662                let (cursor, goal) = movement::up(
11663                    map,
11664                    selection.start,
11665                    selection.goal,
11666                    false,
11667                    text_layout_details,
11668                );
11669                selection.collapse_to(cursor, goal);
11670            });
11671        });
11672
11673        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11674        {
11675            cx.propagate();
11676        }
11677    }
11678
11679    pub fn move_up_by_lines(
11680        &mut self,
11681        action: &MoveUpByLines,
11682        window: &mut Window,
11683        cx: &mut Context<Self>,
11684    ) {
11685        if self.take_rename(true, window, cx).is_some() {
11686            return;
11687        }
11688
11689        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11690            cx.propagate();
11691            return;
11692        }
11693
11694        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11695
11696        let text_layout_details = &self.text_layout_details(window);
11697
11698        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11699            s.move_with(|map, selection| {
11700                if !selection.is_empty() {
11701                    selection.goal = SelectionGoal::None;
11702                }
11703                let (cursor, goal) = movement::up_by_rows(
11704                    map,
11705                    selection.start,
11706                    action.lines,
11707                    selection.goal,
11708                    false,
11709                    text_layout_details,
11710                );
11711                selection.collapse_to(cursor, goal);
11712            });
11713        })
11714    }
11715
11716    pub fn move_down_by_lines(
11717        &mut self,
11718        action: &MoveDownByLines,
11719        window: &mut Window,
11720        cx: &mut Context<Self>,
11721    ) {
11722        if self.take_rename(true, window, cx).is_some() {
11723            return;
11724        }
11725
11726        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11727            cx.propagate();
11728            return;
11729        }
11730
11731        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11732
11733        let text_layout_details = &self.text_layout_details(window);
11734
11735        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11736            s.move_with(|map, selection| {
11737                if !selection.is_empty() {
11738                    selection.goal = SelectionGoal::None;
11739                }
11740                let (cursor, goal) = movement::down_by_rows(
11741                    map,
11742                    selection.start,
11743                    action.lines,
11744                    selection.goal,
11745                    false,
11746                    text_layout_details,
11747                );
11748                selection.collapse_to(cursor, goal);
11749            });
11750        })
11751    }
11752
11753    pub fn select_down_by_lines(
11754        &mut self,
11755        action: &SelectDownByLines,
11756        window: &mut Window,
11757        cx: &mut Context<Self>,
11758    ) {
11759        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11760        let text_layout_details = &self.text_layout_details(window);
11761        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11762            s.move_heads_with(|map, head, goal| {
11763                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11764            })
11765        })
11766    }
11767
11768    pub fn select_up_by_lines(
11769        &mut self,
11770        action: &SelectUpByLines,
11771        window: &mut Window,
11772        cx: &mut Context<Self>,
11773    ) {
11774        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11775        let text_layout_details = &self.text_layout_details(window);
11776        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11777            s.move_heads_with(|map, head, goal| {
11778                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11779            })
11780        })
11781    }
11782
11783    pub fn select_page_up(
11784        &mut self,
11785        _: &SelectPageUp,
11786        window: &mut Window,
11787        cx: &mut Context<Self>,
11788    ) {
11789        let Some(row_count) = self.visible_row_count() else {
11790            return;
11791        };
11792
11793        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11794
11795        let text_layout_details = &self.text_layout_details(window);
11796
11797        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11798            s.move_heads_with(|map, head, goal| {
11799                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11800            })
11801        })
11802    }
11803
11804    pub fn move_page_up(
11805        &mut self,
11806        action: &MovePageUp,
11807        window: &mut Window,
11808        cx: &mut Context<Self>,
11809    ) {
11810        if self.take_rename(true, window, cx).is_some() {
11811            return;
11812        }
11813
11814        if self
11815            .context_menu
11816            .borrow_mut()
11817            .as_mut()
11818            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11819            .unwrap_or(false)
11820        {
11821            return;
11822        }
11823
11824        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11825            cx.propagate();
11826            return;
11827        }
11828
11829        let Some(row_count) = self.visible_row_count() else {
11830            return;
11831        };
11832
11833        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11834
11835        let autoscroll = if action.center_cursor {
11836            Autoscroll::center()
11837        } else {
11838            Autoscroll::fit()
11839        };
11840
11841        let text_layout_details = &self.text_layout_details(window);
11842
11843        self.change_selections(Some(autoscroll), window, cx, |s| {
11844            s.move_with(|map, selection| {
11845                if !selection.is_empty() {
11846                    selection.goal = SelectionGoal::None;
11847                }
11848                let (cursor, goal) = movement::up_by_rows(
11849                    map,
11850                    selection.end,
11851                    row_count,
11852                    selection.goal,
11853                    false,
11854                    text_layout_details,
11855                );
11856                selection.collapse_to(cursor, goal);
11857            });
11858        });
11859    }
11860
11861    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11862        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11863        let text_layout_details = &self.text_layout_details(window);
11864        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11865            s.move_heads_with(|map, head, goal| {
11866                movement::up(map, head, goal, false, text_layout_details)
11867            })
11868        })
11869    }
11870
11871    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11872        self.take_rename(true, window, cx);
11873
11874        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11875            cx.propagate();
11876            return;
11877        }
11878
11879        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11880
11881        let text_layout_details = &self.text_layout_details(window);
11882        let selection_count = self.selections.count();
11883        let first_selection = self.selections.first_anchor();
11884
11885        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11886            s.move_with(|map, selection| {
11887                if !selection.is_empty() {
11888                    selection.goal = SelectionGoal::None;
11889                }
11890                let (cursor, goal) = movement::down(
11891                    map,
11892                    selection.end,
11893                    selection.goal,
11894                    false,
11895                    text_layout_details,
11896                );
11897                selection.collapse_to(cursor, goal);
11898            });
11899        });
11900
11901        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11902        {
11903            cx.propagate();
11904        }
11905    }
11906
11907    pub fn select_page_down(
11908        &mut self,
11909        _: &SelectPageDown,
11910        window: &mut Window,
11911        cx: &mut Context<Self>,
11912    ) {
11913        let Some(row_count) = self.visible_row_count() else {
11914            return;
11915        };
11916
11917        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11918
11919        let text_layout_details = &self.text_layout_details(window);
11920
11921        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11922            s.move_heads_with(|map, head, goal| {
11923                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11924            })
11925        })
11926    }
11927
11928    pub fn move_page_down(
11929        &mut self,
11930        action: &MovePageDown,
11931        window: &mut Window,
11932        cx: &mut Context<Self>,
11933    ) {
11934        if self.take_rename(true, window, cx).is_some() {
11935            return;
11936        }
11937
11938        if self
11939            .context_menu
11940            .borrow_mut()
11941            .as_mut()
11942            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11943            .unwrap_or(false)
11944        {
11945            return;
11946        }
11947
11948        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11949            cx.propagate();
11950            return;
11951        }
11952
11953        let Some(row_count) = self.visible_row_count() else {
11954            return;
11955        };
11956
11957        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11958
11959        let autoscroll = if action.center_cursor {
11960            Autoscroll::center()
11961        } else {
11962            Autoscroll::fit()
11963        };
11964
11965        let text_layout_details = &self.text_layout_details(window);
11966        self.change_selections(Some(autoscroll), window, cx, |s| {
11967            s.move_with(|map, selection| {
11968                if !selection.is_empty() {
11969                    selection.goal = SelectionGoal::None;
11970                }
11971                let (cursor, goal) = movement::down_by_rows(
11972                    map,
11973                    selection.end,
11974                    row_count,
11975                    selection.goal,
11976                    false,
11977                    text_layout_details,
11978                );
11979                selection.collapse_to(cursor, goal);
11980            });
11981        });
11982    }
11983
11984    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11985        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11986        let text_layout_details = &self.text_layout_details(window);
11987        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11988            s.move_heads_with(|map, head, goal| {
11989                movement::down(map, head, goal, false, text_layout_details)
11990            })
11991        });
11992    }
11993
11994    pub fn context_menu_first(
11995        &mut self,
11996        _: &ContextMenuFirst,
11997        window: &mut Window,
11998        cx: &mut Context<Self>,
11999    ) {
12000        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12001            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12002        }
12003    }
12004
12005    pub fn context_menu_prev(
12006        &mut self,
12007        _: &ContextMenuPrevious,
12008        window: &mut Window,
12009        cx: &mut Context<Self>,
12010    ) {
12011        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12012            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12013        }
12014    }
12015
12016    pub fn context_menu_next(
12017        &mut self,
12018        _: &ContextMenuNext,
12019        window: &mut Window,
12020        cx: &mut Context<Self>,
12021    ) {
12022        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12023            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12024        }
12025    }
12026
12027    pub fn context_menu_last(
12028        &mut self,
12029        _: &ContextMenuLast,
12030        window: &mut Window,
12031        cx: &mut Context<Self>,
12032    ) {
12033        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12034            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12035        }
12036    }
12037
12038    pub fn move_to_previous_word_start(
12039        &mut self,
12040        _: &MoveToPreviousWordStart,
12041        window: &mut Window,
12042        cx: &mut Context<Self>,
12043    ) {
12044        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12045        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12046            s.move_cursors_with(|map, head, _| {
12047                (
12048                    movement::previous_word_start(map, head),
12049                    SelectionGoal::None,
12050                )
12051            });
12052        })
12053    }
12054
12055    pub fn move_to_previous_subword_start(
12056        &mut self,
12057        _: &MoveToPreviousSubwordStart,
12058        window: &mut Window,
12059        cx: &mut Context<Self>,
12060    ) {
12061        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12062        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12063            s.move_cursors_with(|map, head, _| {
12064                (
12065                    movement::previous_subword_start(map, head),
12066                    SelectionGoal::None,
12067                )
12068            });
12069        })
12070    }
12071
12072    pub fn select_to_previous_word_start(
12073        &mut self,
12074        _: &SelectToPreviousWordStart,
12075        window: &mut Window,
12076        cx: &mut Context<Self>,
12077    ) {
12078        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12079        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12080            s.move_heads_with(|map, head, _| {
12081                (
12082                    movement::previous_word_start(map, head),
12083                    SelectionGoal::None,
12084                )
12085            });
12086        })
12087    }
12088
12089    pub fn select_to_previous_subword_start(
12090        &mut self,
12091        _: &SelectToPreviousSubwordStart,
12092        window: &mut Window,
12093        cx: &mut Context<Self>,
12094    ) {
12095        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12096        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12097            s.move_heads_with(|map, head, _| {
12098                (
12099                    movement::previous_subword_start(map, head),
12100                    SelectionGoal::None,
12101                )
12102            });
12103        })
12104    }
12105
12106    pub fn delete_to_previous_word_start(
12107        &mut self,
12108        action: &DeleteToPreviousWordStart,
12109        window: &mut Window,
12110        cx: &mut Context<Self>,
12111    ) {
12112        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12113        self.transact(window, cx, |this, window, cx| {
12114            this.select_autoclose_pair(window, cx);
12115            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12116                s.move_with(|map, selection| {
12117                    if selection.is_empty() {
12118                        let cursor = if action.ignore_newlines {
12119                            movement::previous_word_start(map, selection.head())
12120                        } else {
12121                            movement::previous_word_start_or_newline(map, selection.head())
12122                        };
12123                        selection.set_head(cursor, SelectionGoal::None);
12124                    }
12125                });
12126            });
12127            this.insert("", window, cx);
12128        });
12129    }
12130
12131    pub fn delete_to_previous_subword_start(
12132        &mut self,
12133        _: &DeleteToPreviousSubwordStart,
12134        window: &mut Window,
12135        cx: &mut Context<Self>,
12136    ) {
12137        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12138        self.transact(window, cx, |this, window, cx| {
12139            this.select_autoclose_pair(window, cx);
12140            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12141                s.move_with(|map, selection| {
12142                    if selection.is_empty() {
12143                        let cursor = movement::previous_subword_start(map, selection.head());
12144                        selection.set_head(cursor, SelectionGoal::None);
12145                    }
12146                });
12147            });
12148            this.insert("", window, cx);
12149        });
12150    }
12151
12152    pub fn move_to_next_word_end(
12153        &mut self,
12154        _: &MoveToNextWordEnd,
12155        window: &mut Window,
12156        cx: &mut Context<Self>,
12157    ) {
12158        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12159        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12160            s.move_cursors_with(|map, head, _| {
12161                (movement::next_word_end(map, head), SelectionGoal::None)
12162            });
12163        })
12164    }
12165
12166    pub fn move_to_next_subword_end(
12167        &mut self,
12168        _: &MoveToNextSubwordEnd,
12169        window: &mut Window,
12170        cx: &mut Context<Self>,
12171    ) {
12172        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12173        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12174            s.move_cursors_with(|map, head, _| {
12175                (movement::next_subword_end(map, head), SelectionGoal::None)
12176            });
12177        })
12178    }
12179
12180    pub fn select_to_next_word_end(
12181        &mut self,
12182        _: &SelectToNextWordEnd,
12183        window: &mut Window,
12184        cx: &mut Context<Self>,
12185    ) {
12186        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12187        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12188            s.move_heads_with(|map, head, _| {
12189                (movement::next_word_end(map, head), SelectionGoal::None)
12190            });
12191        })
12192    }
12193
12194    pub fn select_to_next_subword_end(
12195        &mut self,
12196        _: &SelectToNextSubwordEnd,
12197        window: &mut Window,
12198        cx: &mut Context<Self>,
12199    ) {
12200        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12201        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12202            s.move_heads_with(|map, head, _| {
12203                (movement::next_subword_end(map, head), SelectionGoal::None)
12204            });
12205        })
12206    }
12207
12208    pub fn delete_to_next_word_end(
12209        &mut self,
12210        action: &DeleteToNextWordEnd,
12211        window: &mut Window,
12212        cx: &mut Context<Self>,
12213    ) {
12214        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12215        self.transact(window, cx, |this, window, cx| {
12216            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12217                s.move_with(|map, selection| {
12218                    if selection.is_empty() {
12219                        let cursor = if action.ignore_newlines {
12220                            movement::next_word_end(map, selection.head())
12221                        } else {
12222                            movement::next_word_end_or_newline(map, selection.head())
12223                        };
12224                        selection.set_head(cursor, SelectionGoal::None);
12225                    }
12226                });
12227            });
12228            this.insert("", window, cx);
12229        });
12230    }
12231
12232    pub fn delete_to_next_subword_end(
12233        &mut self,
12234        _: &DeleteToNextSubwordEnd,
12235        window: &mut Window,
12236        cx: &mut Context<Self>,
12237    ) {
12238        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12239        self.transact(window, cx, |this, window, cx| {
12240            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12241                s.move_with(|map, selection| {
12242                    if selection.is_empty() {
12243                        let cursor = movement::next_subword_end(map, selection.head());
12244                        selection.set_head(cursor, SelectionGoal::None);
12245                    }
12246                });
12247            });
12248            this.insert("", window, cx);
12249        });
12250    }
12251
12252    pub fn move_to_beginning_of_line(
12253        &mut self,
12254        action: &MoveToBeginningOfLine,
12255        window: &mut Window,
12256        cx: &mut Context<Self>,
12257    ) {
12258        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12259        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12260            s.move_cursors_with(|map, head, _| {
12261                (
12262                    movement::indented_line_beginning(
12263                        map,
12264                        head,
12265                        action.stop_at_soft_wraps,
12266                        action.stop_at_indent,
12267                    ),
12268                    SelectionGoal::None,
12269                )
12270            });
12271        })
12272    }
12273
12274    pub fn select_to_beginning_of_line(
12275        &mut self,
12276        action: &SelectToBeginningOfLine,
12277        window: &mut Window,
12278        cx: &mut Context<Self>,
12279    ) {
12280        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12281        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12282            s.move_heads_with(|map, head, _| {
12283                (
12284                    movement::indented_line_beginning(
12285                        map,
12286                        head,
12287                        action.stop_at_soft_wraps,
12288                        action.stop_at_indent,
12289                    ),
12290                    SelectionGoal::None,
12291                )
12292            });
12293        });
12294    }
12295
12296    pub fn delete_to_beginning_of_line(
12297        &mut self,
12298        action: &DeleteToBeginningOfLine,
12299        window: &mut Window,
12300        cx: &mut Context<Self>,
12301    ) {
12302        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12303        self.transact(window, cx, |this, window, cx| {
12304            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12305                s.move_with(|_, selection| {
12306                    selection.reversed = true;
12307                });
12308            });
12309
12310            this.select_to_beginning_of_line(
12311                &SelectToBeginningOfLine {
12312                    stop_at_soft_wraps: false,
12313                    stop_at_indent: action.stop_at_indent,
12314                },
12315                window,
12316                cx,
12317            );
12318            this.backspace(&Backspace, window, cx);
12319        });
12320    }
12321
12322    pub fn move_to_end_of_line(
12323        &mut self,
12324        action: &MoveToEndOfLine,
12325        window: &mut Window,
12326        cx: &mut Context<Self>,
12327    ) {
12328        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12329        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12330            s.move_cursors_with(|map, head, _| {
12331                (
12332                    movement::line_end(map, head, action.stop_at_soft_wraps),
12333                    SelectionGoal::None,
12334                )
12335            });
12336        })
12337    }
12338
12339    pub fn select_to_end_of_line(
12340        &mut self,
12341        action: &SelectToEndOfLine,
12342        window: &mut Window,
12343        cx: &mut Context<Self>,
12344    ) {
12345        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12346        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12347            s.move_heads_with(|map, head, _| {
12348                (
12349                    movement::line_end(map, head, action.stop_at_soft_wraps),
12350                    SelectionGoal::None,
12351                )
12352            });
12353        })
12354    }
12355
12356    pub fn delete_to_end_of_line(
12357        &mut self,
12358        _: &DeleteToEndOfLine,
12359        window: &mut Window,
12360        cx: &mut Context<Self>,
12361    ) {
12362        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12363        self.transact(window, cx, |this, window, cx| {
12364            this.select_to_end_of_line(
12365                &SelectToEndOfLine {
12366                    stop_at_soft_wraps: false,
12367                },
12368                window,
12369                cx,
12370            );
12371            this.delete(&Delete, window, cx);
12372        });
12373    }
12374
12375    pub fn cut_to_end_of_line(
12376        &mut self,
12377        _: &CutToEndOfLine,
12378        window: &mut Window,
12379        cx: &mut Context<Self>,
12380    ) {
12381        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12382        self.transact(window, cx, |this, window, cx| {
12383            this.select_to_end_of_line(
12384                &SelectToEndOfLine {
12385                    stop_at_soft_wraps: false,
12386                },
12387                window,
12388                cx,
12389            );
12390            this.cut(&Cut, window, cx);
12391        });
12392    }
12393
12394    pub fn move_to_start_of_paragraph(
12395        &mut self,
12396        _: &MoveToStartOfParagraph,
12397        window: &mut Window,
12398        cx: &mut Context<Self>,
12399    ) {
12400        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12401            cx.propagate();
12402            return;
12403        }
12404        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12405        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12406            s.move_with(|map, selection| {
12407                selection.collapse_to(
12408                    movement::start_of_paragraph(map, selection.head(), 1),
12409                    SelectionGoal::None,
12410                )
12411            });
12412        })
12413    }
12414
12415    pub fn move_to_end_of_paragraph(
12416        &mut self,
12417        _: &MoveToEndOfParagraph,
12418        window: &mut Window,
12419        cx: &mut Context<Self>,
12420    ) {
12421        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12422            cx.propagate();
12423            return;
12424        }
12425        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12426        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12427            s.move_with(|map, selection| {
12428                selection.collapse_to(
12429                    movement::end_of_paragraph(map, selection.head(), 1),
12430                    SelectionGoal::None,
12431                )
12432            });
12433        })
12434    }
12435
12436    pub fn select_to_start_of_paragraph(
12437        &mut self,
12438        _: &SelectToStartOfParagraph,
12439        window: &mut Window,
12440        cx: &mut Context<Self>,
12441    ) {
12442        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12443            cx.propagate();
12444            return;
12445        }
12446        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12447        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12448            s.move_heads_with(|map, head, _| {
12449                (
12450                    movement::start_of_paragraph(map, head, 1),
12451                    SelectionGoal::None,
12452                )
12453            });
12454        })
12455    }
12456
12457    pub fn select_to_end_of_paragraph(
12458        &mut self,
12459        _: &SelectToEndOfParagraph,
12460        window: &mut Window,
12461        cx: &mut Context<Self>,
12462    ) {
12463        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12464            cx.propagate();
12465            return;
12466        }
12467        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12468        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12469            s.move_heads_with(|map, head, _| {
12470                (
12471                    movement::end_of_paragraph(map, head, 1),
12472                    SelectionGoal::None,
12473                )
12474            });
12475        })
12476    }
12477
12478    pub fn move_to_start_of_excerpt(
12479        &mut self,
12480        _: &MoveToStartOfExcerpt,
12481        window: &mut Window,
12482        cx: &mut Context<Self>,
12483    ) {
12484        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12485            cx.propagate();
12486            return;
12487        }
12488        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12489        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12490            s.move_with(|map, selection| {
12491                selection.collapse_to(
12492                    movement::start_of_excerpt(
12493                        map,
12494                        selection.head(),
12495                        workspace::searchable::Direction::Prev,
12496                    ),
12497                    SelectionGoal::None,
12498                )
12499            });
12500        })
12501    }
12502
12503    pub fn move_to_start_of_next_excerpt(
12504        &mut self,
12505        _: &MoveToStartOfNextExcerpt,
12506        window: &mut Window,
12507        cx: &mut Context<Self>,
12508    ) {
12509        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12510            cx.propagate();
12511            return;
12512        }
12513
12514        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12515            s.move_with(|map, selection| {
12516                selection.collapse_to(
12517                    movement::start_of_excerpt(
12518                        map,
12519                        selection.head(),
12520                        workspace::searchable::Direction::Next,
12521                    ),
12522                    SelectionGoal::None,
12523                )
12524            });
12525        })
12526    }
12527
12528    pub fn move_to_end_of_excerpt(
12529        &mut self,
12530        _: &MoveToEndOfExcerpt,
12531        window: &mut Window,
12532        cx: &mut Context<Self>,
12533    ) {
12534        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12535            cx.propagate();
12536            return;
12537        }
12538        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12539        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12540            s.move_with(|map, selection| {
12541                selection.collapse_to(
12542                    movement::end_of_excerpt(
12543                        map,
12544                        selection.head(),
12545                        workspace::searchable::Direction::Next,
12546                    ),
12547                    SelectionGoal::None,
12548                )
12549            });
12550        })
12551    }
12552
12553    pub fn move_to_end_of_previous_excerpt(
12554        &mut self,
12555        _: &MoveToEndOfPreviousExcerpt,
12556        window: &mut Window,
12557        cx: &mut Context<Self>,
12558    ) {
12559        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12560            cx.propagate();
12561            return;
12562        }
12563        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12564        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12565            s.move_with(|map, selection| {
12566                selection.collapse_to(
12567                    movement::end_of_excerpt(
12568                        map,
12569                        selection.head(),
12570                        workspace::searchable::Direction::Prev,
12571                    ),
12572                    SelectionGoal::None,
12573                )
12574            });
12575        })
12576    }
12577
12578    pub fn select_to_start_of_excerpt(
12579        &mut self,
12580        _: &SelectToStartOfExcerpt,
12581        window: &mut Window,
12582        cx: &mut Context<Self>,
12583    ) {
12584        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12585            cx.propagate();
12586            return;
12587        }
12588        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12589        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12590            s.move_heads_with(|map, head, _| {
12591                (
12592                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12593                    SelectionGoal::None,
12594                )
12595            });
12596        })
12597    }
12598
12599    pub fn select_to_start_of_next_excerpt(
12600        &mut self,
12601        _: &SelectToStartOfNextExcerpt,
12602        window: &mut Window,
12603        cx: &mut Context<Self>,
12604    ) {
12605        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12606            cx.propagate();
12607            return;
12608        }
12609        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12610        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12611            s.move_heads_with(|map, head, _| {
12612                (
12613                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12614                    SelectionGoal::None,
12615                )
12616            });
12617        })
12618    }
12619
12620    pub fn select_to_end_of_excerpt(
12621        &mut self,
12622        _: &SelectToEndOfExcerpt,
12623        window: &mut Window,
12624        cx: &mut Context<Self>,
12625    ) {
12626        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12627            cx.propagate();
12628            return;
12629        }
12630        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12631        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12632            s.move_heads_with(|map, head, _| {
12633                (
12634                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12635                    SelectionGoal::None,
12636                )
12637            });
12638        })
12639    }
12640
12641    pub fn select_to_end_of_previous_excerpt(
12642        &mut self,
12643        _: &SelectToEndOfPreviousExcerpt,
12644        window: &mut Window,
12645        cx: &mut Context<Self>,
12646    ) {
12647        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12648            cx.propagate();
12649            return;
12650        }
12651        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12652        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12653            s.move_heads_with(|map, head, _| {
12654                (
12655                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12656                    SelectionGoal::None,
12657                )
12658            });
12659        })
12660    }
12661
12662    pub fn move_to_beginning(
12663        &mut self,
12664        _: &MoveToBeginning,
12665        window: &mut Window,
12666        cx: &mut Context<Self>,
12667    ) {
12668        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12669            cx.propagate();
12670            return;
12671        }
12672        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12673        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12674            s.select_ranges(vec![0..0]);
12675        });
12676    }
12677
12678    pub fn select_to_beginning(
12679        &mut self,
12680        _: &SelectToBeginning,
12681        window: &mut Window,
12682        cx: &mut Context<Self>,
12683    ) {
12684        let mut selection = self.selections.last::<Point>(cx);
12685        selection.set_head(Point::zero(), SelectionGoal::None);
12686        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12687        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12688            s.select(vec![selection]);
12689        });
12690    }
12691
12692    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12693        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12694            cx.propagate();
12695            return;
12696        }
12697        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12698        let cursor = self.buffer.read(cx).read(cx).len();
12699        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12700            s.select_ranges(vec![cursor..cursor])
12701        });
12702    }
12703
12704    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12705        self.nav_history = nav_history;
12706    }
12707
12708    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12709        self.nav_history.as_ref()
12710    }
12711
12712    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12713        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12714    }
12715
12716    fn push_to_nav_history(
12717        &mut self,
12718        cursor_anchor: Anchor,
12719        new_position: Option<Point>,
12720        is_deactivate: bool,
12721        cx: &mut Context<Self>,
12722    ) {
12723        if let Some(nav_history) = self.nav_history.as_mut() {
12724            let buffer = self.buffer.read(cx).read(cx);
12725            let cursor_position = cursor_anchor.to_point(&buffer);
12726            let scroll_state = self.scroll_manager.anchor();
12727            let scroll_top_row = scroll_state.top_row(&buffer);
12728            drop(buffer);
12729
12730            if let Some(new_position) = new_position {
12731                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12732                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12733                    return;
12734                }
12735            }
12736
12737            nav_history.push(
12738                Some(NavigationData {
12739                    cursor_anchor,
12740                    cursor_position,
12741                    scroll_anchor: scroll_state,
12742                    scroll_top_row,
12743                }),
12744                cx,
12745            );
12746            cx.emit(EditorEvent::PushedToNavHistory {
12747                anchor: cursor_anchor,
12748                is_deactivate,
12749            })
12750        }
12751    }
12752
12753    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12754        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12755        let buffer = self.buffer.read(cx).snapshot(cx);
12756        let mut selection = self.selections.first::<usize>(cx);
12757        selection.set_head(buffer.len(), SelectionGoal::None);
12758        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12759            s.select(vec![selection]);
12760        });
12761    }
12762
12763    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12764        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12765        let end = self.buffer.read(cx).read(cx).len();
12766        self.change_selections(None, window, cx, |s| {
12767            s.select_ranges(vec![0..end]);
12768        });
12769    }
12770
12771    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12772        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12773        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12774        let mut selections = self.selections.all::<Point>(cx);
12775        let max_point = display_map.buffer_snapshot.max_point();
12776        for selection in &mut selections {
12777            let rows = selection.spanned_rows(true, &display_map);
12778            selection.start = Point::new(rows.start.0, 0);
12779            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12780            selection.reversed = false;
12781        }
12782        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12783            s.select(selections);
12784        });
12785    }
12786
12787    pub fn split_selection_into_lines(
12788        &mut self,
12789        _: &SplitSelectionIntoLines,
12790        window: &mut Window,
12791        cx: &mut Context<Self>,
12792    ) {
12793        let selections = self
12794            .selections
12795            .all::<Point>(cx)
12796            .into_iter()
12797            .map(|selection| selection.start..selection.end)
12798            .collect::<Vec<_>>();
12799        self.unfold_ranges(&selections, true, true, cx);
12800
12801        let mut new_selection_ranges = Vec::new();
12802        {
12803            let buffer = self.buffer.read(cx).read(cx);
12804            for selection in selections {
12805                for row in selection.start.row..selection.end.row {
12806                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12807                    new_selection_ranges.push(cursor..cursor);
12808                }
12809
12810                let is_multiline_selection = selection.start.row != selection.end.row;
12811                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12812                // so this action feels more ergonomic when paired with other selection operations
12813                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12814                if !should_skip_last {
12815                    new_selection_ranges.push(selection.end..selection.end);
12816                }
12817            }
12818        }
12819        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12820            s.select_ranges(new_selection_ranges);
12821        });
12822    }
12823
12824    pub fn add_selection_above(
12825        &mut self,
12826        _: &AddSelectionAbove,
12827        window: &mut Window,
12828        cx: &mut Context<Self>,
12829    ) {
12830        self.add_selection(true, window, cx);
12831    }
12832
12833    pub fn add_selection_below(
12834        &mut self,
12835        _: &AddSelectionBelow,
12836        window: &mut Window,
12837        cx: &mut Context<Self>,
12838    ) {
12839        self.add_selection(false, window, cx);
12840    }
12841
12842    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12843        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12844
12845        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12846        let all_selections = self.selections.all::<Point>(cx);
12847        let text_layout_details = self.text_layout_details(window);
12848
12849        let (mut columnar_selections, new_selections_to_columnarize) = {
12850            if let Some(state) = self.add_selections_state.as_ref() {
12851                let columnar_selection_ids: HashSet<_> = state
12852                    .groups
12853                    .iter()
12854                    .flat_map(|group| group.stack.iter())
12855                    .copied()
12856                    .collect();
12857
12858                all_selections
12859                    .into_iter()
12860                    .partition(|s| columnar_selection_ids.contains(&s.id))
12861            } else {
12862                (Vec::new(), all_selections)
12863            }
12864        };
12865
12866        let mut state = self
12867            .add_selections_state
12868            .take()
12869            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12870
12871        for selection in new_selections_to_columnarize {
12872            let range = selection.display_range(&display_map).sorted();
12873            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12874            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12875            let positions = start_x.min(end_x)..start_x.max(end_x);
12876            let mut stack = Vec::new();
12877            for row in range.start.row().0..=range.end.row().0 {
12878                if let Some(selection) = self.selections.build_columnar_selection(
12879                    &display_map,
12880                    DisplayRow(row),
12881                    &positions,
12882                    selection.reversed,
12883                    &text_layout_details,
12884                ) {
12885                    stack.push(selection.id);
12886                    columnar_selections.push(selection);
12887                }
12888            }
12889            if !stack.is_empty() {
12890                if above {
12891                    stack.reverse();
12892                }
12893                state.groups.push(AddSelectionsGroup { above, stack });
12894            }
12895        }
12896
12897        let mut final_selections = Vec::new();
12898        let end_row = if above {
12899            DisplayRow(0)
12900        } else {
12901            display_map.max_point().row()
12902        };
12903
12904        let mut last_added_item_per_group = HashMap::default();
12905        for group in state.groups.iter_mut() {
12906            if let Some(last_id) = group.stack.last() {
12907                last_added_item_per_group.insert(*last_id, group);
12908            }
12909        }
12910
12911        for selection in columnar_selections {
12912            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
12913                if above == group.above {
12914                    let range = selection.display_range(&display_map).sorted();
12915                    debug_assert_eq!(range.start.row(), range.end.row());
12916                    let mut row = range.start.row();
12917                    let positions =
12918                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12919                            px(start)..px(end)
12920                        } else {
12921                            let start_x =
12922                                display_map.x_for_display_point(range.start, &text_layout_details);
12923                            let end_x =
12924                                display_map.x_for_display_point(range.end, &text_layout_details);
12925                            start_x.min(end_x)..start_x.max(end_x)
12926                        };
12927
12928                    let mut maybe_new_selection = None;
12929                    while row != end_row {
12930                        if above {
12931                            row.0 -= 1;
12932                        } else {
12933                            row.0 += 1;
12934                        }
12935                        if let Some(new_selection) = self.selections.build_columnar_selection(
12936                            &display_map,
12937                            row,
12938                            &positions,
12939                            selection.reversed,
12940                            &text_layout_details,
12941                        ) {
12942                            maybe_new_selection = Some(new_selection);
12943                            break;
12944                        }
12945                    }
12946
12947                    if let Some(new_selection) = maybe_new_selection {
12948                        group.stack.push(new_selection.id);
12949                        if above {
12950                            final_selections.push(new_selection);
12951                            final_selections.push(selection);
12952                        } else {
12953                            final_selections.push(selection);
12954                            final_selections.push(new_selection);
12955                        }
12956                    } else {
12957                        final_selections.push(selection);
12958                    }
12959                } else {
12960                    group.stack.pop();
12961                }
12962            } else {
12963                final_selections.push(selection);
12964            }
12965        }
12966
12967        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12968            s.select(final_selections);
12969        });
12970
12971        let final_selection_ids: HashSet<_> = self
12972            .selections
12973            .all::<Point>(cx)
12974            .iter()
12975            .map(|s| s.id)
12976            .collect();
12977        state.groups.retain_mut(|group| {
12978            // selections might get merged above so we remove invalid items from stacks
12979            group.stack.retain(|id| final_selection_ids.contains(id));
12980
12981            // single selection in stack can be treated as initial state
12982            group.stack.len() > 1
12983        });
12984
12985        if !state.groups.is_empty() {
12986            self.add_selections_state = Some(state);
12987        }
12988    }
12989
12990    fn select_match_ranges(
12991        &mut self,
12992        range: Range<usize>,
12993        reversed: bool,
12994        replace_newest: bool,
12995        auto_scroll: Option<Autoscroll>,
12996        window: &mut Window,
12997        cx: &mut Context<Editor>,
12998    ) {
12999        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13000        self.change_selections(auto_scroll, window, cx, |s| {
13001            if replace_newest {
13002                s.delete(s.newest_anchor().id);
13003            }
13004            if reversed {
13005                s.insert_range(range.end..range.start);
13006            } else {
13007                s.insert_range(range);
13008            }
13009        });
13010    }
13011
13012    pub fn select_next_match_internal(
13013        &mut self,
13014        display_map: &DisplaySnapshot,
13015        replace_newest: bool,
13016        autoscroll: Option<Autoscroll>,
13017        window: &mut Window,
13018        cx: &mut Context<Self>,
13019    ) -> Result<()> {
13020        let buffer = &display_map.buffer_snapshot;
13021        let mut selections = self.selections.all::<usize>(cx);
13022        if let Some(mut select_next_state) = self.select_next_state.take() {
13023            let query = &select_next_state.query;
13024            if !select_next_state.done {
13025                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13026                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13027                let mut next_selected_range = None;
13028
13029                let bytes_after_last_selection =
13030                    buffer.bytes_in_range(last_selection.end..buffer.len());
13031                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13032                let query_matches = query
13033                    .stream_find_iter(bytes_after_last_selection)
13034                    .map(|result| (last_selection.end, result))
13035                    .chain(
13036                        query
13037                            .stream_find_iter(bytes_before_first_selection)
13038                            .map(|result| (0, result)),
13039                    );
13040
13041                for (start_offset, query_match) in query_matches {
13042                    let query_match = query_match.unwrap(); // can only fail due to I/O
13043                    let offset_range =
13044                        start_offset + query_match.start()..start_offset + query_match.end();
13045                    let display_range = offset_range.start.to_display_point(display_map)
13046                        ..offset_range.end.to_display_point(display_map);
13047
13048                    if !select_next_state.wordwise
13049                        || (!movement::is_inside_word(display_map, display_range.start)
13050                            && !movement::is_inside_word(display_map, display_range.end))
13051                    {
13052                        // TODO: This is n^2, because we might check all the selections
13053                        if !selections
13054                            .iter()
13055                            .any(|selection| selection.range().overlaps(&offset_range))
13056                        {
13057                            next_selected_range = Some(offset_range);
13058                            break;
13059                        }
13060                    }
13061                }
13062
13063                if let Some(next_selected_range) = next_selected_range {
13064                    self.select_match_ranges(
13065                        next_selected_range,
13066                        last_selection.reversed,
13067                        replace_newest,
13068                        autoscroll,
13069                        window,
13070                        cx,
13071                    );
13072                } else {
13073                    select_next_state.done = true;
13074                }
13075            }
13076
13077            self.select_next_state = Some(select_next_state);
13078        } else {
13079            let mut only_carets = true;
13080            let mut same_text_selected = true;
13081            let mut selected_text = None;
13082
13083            let mut selections_iter = selections.iter().peekable();
13084            while let Some(selection) = selections_iter.next() {
13085                if selection.start != selection.end {
13086                    only_carets = false;
13087                }
13088
13089                if same_text_selected {
13090                    if selected_text.is_none() {
13091                        selected_text =
13092                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13093                    }
13094
13095                    if let Some(next_selection) = selections_iter.peek() {
13096                        if next_selection.range().len() == selection.range().len() {
13097                            let next_selected_text = buffer
13098                                .text_for_range(next_selection.range())
13099                                .collect::<String>();
13100                            if Some(next_selected_text) != selected_text {
13101                                same_text_selected = false;
13102                                selected_text = None;
13103                            }
13104                        } else {
13105                            same_text_selected = false;
13106                            selected_text = None;
13107                        }
13108                    }
13109                }
13110            }
13111
13112            if only_carets {
13113                for selection in &mut selections {
13114                    let word_range = movement::surrounding_word(
13115                        display_map,
13116                        selection.start.to_display_point(display_map),
13117                    );
13118                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13119                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13120                    selection.goal = SelectionGoal::None;
13121                    selection.reversed = false;
13122                    self.select_match_ranges(
13123                        selection.start..selection.end,
13124                        selection.reversed,
13125                        replace_newest,
13126                        autoscroll,
13127                        window,
13128                        cx,
13129                    );
13130                }
13131
13132                if selections.len() == 1 {
13133                    let selection = selections
13134                        .last()
13135                        .expect("ensured that there's only one selection");
13136                    let query = buffer
13137                        .text_for_range(selection.start..selection.end)
13138                        .collect::<String>();
13139                    let is_empty = query.is_empty();
13140                    let select_state = SelectNextState {
13141                        query: AhoCorasick::new(&[query])?,
13142                        wordwise: true,
13143                        done: is_empty,
13144                    };
13145                    self.select_next_state = Some(select_state);
13146                } else {
13147                    self.select_next_state = None;
13148                }
13149            } else if let Some(selected_text) = selected_text {
13150                self.select_next_state = Some(SelectNextState {
13151                    query: AhoCorasick::new(&[selected_text])?,
13152                    wordwise: false,
13153                    done: false,
13154                });
13155                self.select_next_match_internal(
13156                    display_map,
13157                    replace_newest,
13158                    autoscroll,
13159                    window,
13160                    cx,
13161                )?;
13162            }
13163        }
13164        Ok(())
13165    }
13166
13167    pub fn select_all_matches(
13168        &mut self,
13169        _action: &SelectAllMatches,
13170        window: &mut Window,
13171        cx: &mut Context<Self>,
13172    ) -> Result<()> {
13173        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13174
13175        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13176
13177        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13178        let Some(select_next_state) = self.select_next_state.as_mut() else {
13179            return Ok(());
13180        };
13181        if select_next_state.done {
13182            return Ok(());
13183        }
13184
13185        let mut new_selections = Vec::new();
13186
13187        let reversed = self.selections.oldest::<usize>(cx).reversed;
13188        let buffer = &display_map.buffer_snapshot;
13189        let query_matches = select_next_state
13190            .query
13191            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13192
13193        for query_match in query_matches.into_iter() {
13194            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13195            let offset_range = if reversed {
13196                query_match.end()..query_match.start()
13197            } else {
13198                query_match.start()..query_match.end()
13199            };
13200            let display_range = offset_range.start.to_display_point(&display_map)
13201                ..offset_range.end.to_display_point(&display_map);
13202
13203            if !select_next_state.wordwise
13204                || (!movement::is_inside_word(&display_map, display_range.start)
13205                    && !movement::is_inside_word(&display_map, display_range.end))
13206            {
13207                new_selections.push(offset_range.start..offset_range.end);
13208            }
13209        }
13210
13211        select_next_state.done = true;
13212        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13213        self.change_selections(None, window, cx, |selections| {
13214            selections.select_ranges(new_selections)
13215        });
13216
13217        Ok(())
13218    }
13219
13220    pub fn select_next(
13221        &mut self,
13222        action: &SelectNext,
13223        window: &mut Window,
13224        cx: &mut Context<Self>,
13225    ) -> Result<()> {
13226        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13227        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13228        self.select_next_match_internal(
13229            &display_map,
13230            action.replace_newest,
13231            Some(Autoscroll::newest()),
13232            window,
13233            cx,
13234        )?;
13235        Ok(())
13236    }
13237
13238    pub fn select_previous(
13239        &mut self,
13240        action: &SelectPrevious,
13241        window: &mut Window,
13242        cx: &mut Context<Self>,
13243    ) -> Result<()> {
13244        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13245        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13246        let buffer = &display_map.buffer_snapshot;
13247        let mut selections = self.selections.all::<usize>(cx);
13248        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13249            let query = &select_prev_state.query;
13250            if !select_prev_state.done {
13251                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13252                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13253                let mut next_selected_range = None;
13254                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13255                let bytes_before_last_selection =
13256                    buffer.reversed_bytes_in_range(0..last_selection.start);
13257                let bytes_after_first_selection =
13258                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13259                let query_matches = query
13260                    .stream_find_iter(bytes_before_last_selection)
13261                    .map(|result| (last_selection.start, result))
13262                    .chain(
13263                        query
13264                            .stream_find_iter(bytes_after_first_selection)
13265                            .map(|result| (buffer.len(), result)),
13266                    );
13267                for (end_offset, query_match) in query_matches {
13268                    let query_match = query_match.unwrap(); // can only fail due to I/O
13269                    let offset_range =
13270                        end_offset - query_match.end()..end_offset - query_match.start();
13271                    let display_range = offset_range.start.to_display_point(&display_map)
13272                        ..offset_range.end.to_display_point(&display_map);
13273
13274                    if !select_prev_state.wordwise
13275                        || (!movement::is_inside_word(&display_map, display_range.start)
13276                            && !movement::is_inside_word(&display_map, display_range.end))
13277                    {
13278                        next_selected_range = Some(offset_range);
13279                        break;
13280                    }
13281                }
13282
13283                if let Some(next_selected_range) = next_selected_range {
13284                    self.select_match_ranges(
13285                        next_selected_range,
13286                        last_selection.reversed,
13287                        action.replace_newest,
13288                        Some(Autoscroll::newest()),
13289                        window,
13290                        cx,
13291                    );
13292                } else {
13293                    select_prev_state.done = true;
13294                }
13295            }
13296
13297            self.select_prev_state = Some(select_prev_state);
13298        } else {
13299            let mut only_carets = true;
13300            let mut same_text_selected = true;
13301            let mut selected_text = None;
13302
13303            let mut selections_iter = selections.iter().peekable();
13304            while let Some(selection) = selections_iter.next() {
13305                if selection.start != selection.end {
13306                    only_carets = false;
13307                }
13308
13309                if same_text_selected {
13310                    if selected_text.is_none() {
13311                        selected_text =
13312                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13313                    }
13314
13315                    if let Some(next_selection) = selections_iter.peek() {
13316                        if next_selection.range().len() == selection.range().len() {
13317                            let next_selected_text = buffer
13318                                .text_for_range(next_selection.range())
13319                                .collect::<String>();
13320                            if Some(next_selected_text) != selected_text {
13321                                same_text_selected = false;
13322                                selected_text = None;
13323                            }
13324                        } else {
13325                            same_text_selected = false;
13326                            selected_text = None;
13327                        }
13328                    }
13329                }
13330            }
13331
13332            if only_carets {
13333                for selection in &mut selections {
13334                    let word_range = movement::surrounding_word(
13335                        &display_map,
13336                        selection.start.to_display_point(&display_map),
13337                    );
13338                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13339                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13340                    selection.goal = SelectionGoal::None;
13341                    selection.reversed = false;
13342                    self.select_match_ranges(
13343                        selection.start..selection.end,
13344                        selection.reversed,
13345                        action.replace_newest,
13346                        Some(Autoscroll::newest()),
13347                        window,
13348                        cx,
13349                    );
13350                }
13351                if selections.len() == 1 {
13352                    let selection = selections
13353                        .last()
13354                        .expect("ensured that there's only one selection");
13355                    let query = buffer
13356                        .text_for_range(selection.start..selection.end)
13357                        .collect::<String>();
13358                    let is_empty = query.is_empty();
13359                    let select_state = SelectNextState {
13360                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13361                        wordwise: true,
13362                        done: is_empty,
13363                    };
13364                    self.select_prev_state = Some(select_state);
13365                } else {
13366                    self.select_prev_state = None;
13367                }
13368            } else if let Some(selected_text) = selected_text {
13369                self.select_prev_state = Some(SelectNextState {
13370                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13371                    wordwise: false,
13372                    done: false,
13373                });
13374                self.select_previous(action, window, cx)?;
13375            }
13376        }
13377        Ok(())
13378    }
13379
13380    pub fn find_next_match(
13381        &mut self,
13382        _: &FindNextMatch,
13383        window: &mut Window,
13384        cx: &mut Context<Self>,
13385    ) -> Result<()> {
13386        let selections = self.selections.disjoint_anchors();
13387        match selections.first() {
13388            Some(first) if selections.len() >= 2 => {
13389                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13390                    s.select_ranges([first.range()]);
13391                });
13392            }
13393            _ => self.select_next(
13394                &SelectNext {
13395                    replace_newest: true,
13396                },
13397                window,
13398                cx,
13399            )?,
13400        }
13401        Ok(())
13402    }
13403
13404    pub fn find_previous_match(
13405        &mut self,
13406        _: &FindPreviousMatch,
13407        window: &mut Window,
13408        cx: &mut Context<Self>,
13409    ) -> Result<()> {
13410        let selections = self.selections.disjoint_anchors();
13411        match selections.last() {
13412            Some(last) if selections.len() >= 2 => {
13413                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13414                    s.select_ranges([last.range()]);
13415                });
13416            }
13417            _ => self.select_previous(
13418                &SelectPrevious {
13419                    replace_newest: true,
13420                },
13421                window,
13422                cx,
13423            )?,
13424        }
13425        Ok(())
13426    }
13427
13428    pub fn toggle_comments(
13429        &mut self,
13430        action: &ToggleComments,
13431        window: &mut Window,
13432        cx: &mut Context<Self>,
13433    ) {
13434        if self.read_only(cx) {
13435            return;
13436        }
13437        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13438        let text_layout_details = &self.text_layout_details(window);
13439        self.transact(window, cx, |this, window, cx| {
13440            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13441            let mut edits = Vec::new();
13442            let mut selection_edit_ranges = Vec::new();
13443            let mut last_toggled_row = None;
13444            let snapshot = this.buffer.read(cx).read(cx);
13445            let empty_str: Arc<str> = Arc::default();
13446            let mut suffixes_inserted = Vec::new();
13447            let ignore_indent = action.ignore_indent;
13448
13449            fn comment_prefix_range(
13450                snapshot: &MultiBufferSnapshot,
13451                row: MultiBufferRow,
13452                comment_prefix: &str,
13453                comment_prefix_whitespace: &str,
13454                ignore_indent: bool,
13455            ) -> Range<Point> {
13456                let indent_size = if ignore_indent {
13457                    0
13458                } else {
13459                    snapshot.indent_size_for_line(row).len
13460                };
13461
13462                let start = Point::new(row.0, indent_size);
13463
13464                let mut line_bytes = snapshot
13465                    .bytes_in_range(start..snapshot.max_point())
13466                    .flatten()
13467                    .copied();
13468
13469                // If this line currently begins with the line comment prefix, then record
13470                // the range containing the prefix.
13471                if line_bytes
13472                    .by_ref()
13473                    .take(comment_prefix.len())
13474                    .eq(comment_prefix.bytes())
13475                {
13476                    // Include any whitespace that matches the comment prefix.
13477                    let matching_whitespace_len = line_bytes
13478                        .zip(comment_prefix_whitespace.bytes())
13479                        .take_while(|(a, b)| a == b)
13480                        .count() as u32;
13481                    let end = Point::new(
13482                        start.row,
13483                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13484                    );
13485                    start..end
13486                } else {
13487                    start..start
13488                }
13489            }
13490
13491            fn comment_suffix_range(
13492                snapshot: &MultiBufferSnapshot,
13493                row: MultiBufferRow,
13494                comment_suffix: &str,
13495                comment_suffix_has_leading_space: bool,
13496            ) -> Range<Point> {
13497                let end = Point::new(row.0, snapshot.line_len(row));
13498                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13499
13500                let mut line_end_bytes = snapshot
13501                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13502                    .flatten()
13503                    .copied();
13504
13505                let leading_space_len = if suffix_start_column > 0
13506                    && line_end_bytes.next() == Some(b' ')
13507                    && comment_suffix_has_leading_space
13508                {
13509                    1
13510                } else {
13511                    0
13512                };
13513
13514                // If this line currently begins with the line comment prefix, then record
13515                // the range containing the prefix.
13516                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13517                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13518                    start..end
13519                } else {
13520                    end..end
13521                }
13522            }
13523
13524            // TODO: Handle selections that cross excerpts
13525            for selection in &mut selections {
13526                let start_column = snapshot
13527                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13528                    .len;
13529                let language = if let Some(language) =
13530                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13531                {
13532                    language
13533                } else {
13534                    continue;
13535                };
13536
13537                selection_edit_ranges.clear();
13538
13539                // If multiple selections contain a given row, avoid processing that
13540                // row more than once.
13541                let mut start_row = MultiBufferRow(selection.start.row);
13542                if last_toggled_row == Some(start_row) {
13543                    start_row = start_row.next_row();
13544                }
13545                let end_row =
13546                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13547                        MultiBufferRow(selection.end.row - 1)
13548                    } else {
13549                        MultiBufferRow(selection.end.row)
13550                    };
13551                last_toggled_row = Some(end_row);
13552
13553                if start_row > end_row {
13554                    continue;
13555                }
13556
13557                // If the language has line comments, toggle those.
13558                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13559
13560                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13561                if ignore_indent {
13562                    full_comment_prefixes = full_comment_prefixes
13563                        .into_iter()
13564                        .map(|s| Arc::from(s.trim_end()))
13565                        .collect();
13566                }
13567
13568                if !full_comment_prefixes.is_empty() {
13569                    let first_prefix = full_comment_prefixes
13570                        .first()
13571                        .expect("prefixes is non-empty");
13572                    let prefix_trimmed_lengths = full_comment_prefixes
13573                        .iter()
13574                        .map(|p| p.trim_end_matches(' ').len())
13575                        .collect::<SmallVec<[usize; 4]>>();
13576
13577                    let mut all_selection_lines_are_comments = true;
13578
13579                    for row in start_row.0..=end_row.0 {
13580                        let row = MultiBufferRow(row);
13581                        if start_row < end_row && snapshot.is_line_blank(row) {
13582                            continue;
13583                        }
13584
13585                        let prefix_range = full_comment_prefixes
13586                            .iter()
13587                            .zip(prefix_trimmed_lengths.iter().copied())
13588                            .map(|(prefix, trimmed_prefix_len)| {
13589                                comment_prefix_range(
13590                                    snapshot.deref(),
13591                                    row,
13592                                    &prefix[..trimmed_prefix_len],
13593                                    &prefix[trimmed_prefix_len..],
13594                                    ignore_indent,
13595                                )
13596                            })
13597                            .max_by_key(|range| range.end.column - range.start.column)
13598                            .expect("prefixes is non-empty");
13599
13600                        if prefix_range.is_empty() {
13601                            all_selection_lines_are_comments = false;
13602                        }
13603
13604                        selection_edit_ranges.push(prefix_range);
13605                    }
13606
13607                    if all_selection_lines_are_comments {
13608                        edits.extend(
13609                            selection_edit_ranges
13610                                .iter()
13611                                .cloned()
13612                                .map(|range| (range, empty_str.clone())),
13613                        );
13614                    } else {
13615                        let min_column = selection_edit_ranges
13616                            .iter()
13617                            .map(|range| range.start.column)
13618                            .min()
13619                            .unwrap_or(0);
13620                        edits.extend(selection_edit_ranges.iter().map(|range| {
13621                            let position = Point::new(range.start.row, min_column);
13622                            (position..position, first_prefix.clone())
13623                        }));
13624                    }
13625                } else if let Some((full_comment_prefix, comment_suffix)) =
13626                    language.block_comment_delimiters()
13627                {
13628                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13629                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13630                    let prefix_range = comment_prefix_range(
13631                        snapshot.deref(),
13632                        start_row,
13633                        comment_prefix,
13634                        comment_prefix_whitespace,
13635                        ignore_indent,
13636                    );
13637                    let suffix_range = comment_suffix_range(
13638                        snapshot.deref(),
13639                        end_row,
13640                        comment_suffix.trim_start_matches(' '),
13641                        comment_suffix.starts_with(' '),
13642                    );
13643
13644                    if prefix_range.is_empty() || suffix_range.is_empty() {
13645                        edits.push((
13646                            prefix_range.start..prefix_range.start,
13647                            full_comment_prefix.clone(),
13648                        ));
13649                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13650                        suffixes_inserted.push((end_row, comment_suffix.len()));
13651                    } else {
13652                        edits.push((prefix_range, empty_str.clone()));
13653                        edits.push((suffix_range, empty_str.clone()));
13654                    }
13655                } else {
13656                    continue;
13657                }
13658            }
13659
13660            drop(snapshot);
13661            this.buffer.update(cx, |buffer, cx| {
13662                buffer.edit(edits, None, cx);
13663            });
13664
13665            // Adjust selections so that they end before any comment suffixes that
13666            // were inserted.
13667            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13668            let mut selections = this.selections.all::<Point>(cx);
13669            let snapshot = this.buffer.read(cx).read(cx);
13670            for selection in &mut selections {
13671                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13672                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13673                        Ordering::Less => {
13674                            suffixes_inserted.next();
13675                            continue;
13676                        }
13677                        Ordering::Greater => break,
13678                        Ordering::Equal => {
13679                            if selection.end.column == snapshot.line_len(row) {
13680                                if selection.is_empty() {
13681                                    selection.start.column -= suffix_len as u32;
13682                                }
13683                                selection.end.column -= suffix_len as u32;
13684                            }
13685                            break;
13686                        }
13687                    }
13688                }
13689            }
13690
13691            drop(snapshot);
13692            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13693                s.select(selections)
13694            });
13695
13696            let selections = this.selections.all::<Point>(cx);
13697            let selections_on_single_row = selections.windows(2).all(|selections| {
13698                selections[0].start.row == selections[1].start.row
13699                    && selections[0].end.row == selections[1].end.row
13700                    && selections[0].start.row == selections[0].end.row
13701            });
13702            let selections_selecting = selections
13703                .iter()
13704                .any(|selection| selection.start != selection.end);
13705            let advance_downwards = action.advance_downwards
13706                && selections_on_single_row
13707                && !selections_selecting
13708                && !matches!(this.mode, EditorMode::SingleLine { .. });
13709
13710            if advance_downwards {
13711                let snapshot = this.buffer.read(cx).snapshot(cx);
13712
13713                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13714                    s.move_cursors_with(|display_snapshot, display_point, _| {
13715                        let mut point = display_point.to_point(display_snapshot);
13716                        point.row += 1;
13717                        point = snapshot.clip_point(point, Bias::Left);
13718                        let display_point = point.to_display_point(display_snapshot);
13719                        let goal = SelectionGoal::HorizontalPosition(
13720                            display_snapshot
13721                                .x_for_display_point(display_point, text_layout_details)
13722                                .into(),
13723                        );
13724                        (display_point, goal)
13725                    })
13726                });
13727            }
13728        });
13729    }
13730
13731    pub fn select_enclosing_symbol(
13732        &mut self,
13733        _: &SelectEnclosingSymbol,
13734        window: &mut Window,
13735        cx: &mut Context<Self>,
13736    ) {
13737        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13738
13739        let buffer = self.buffer.read(cx).snapshot(cx);
13740        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13741
13742        fn update_selection(
13743            selection: &Selection<usize>,
13744            buffer_snap: &MultiBufferSnapshot,
13745        ) -> Option<Selection<usize>> {
13746            let cursor = selection.head();
13747            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13748            for symbol in symbols.iter().rev() {
13749                let start = symbol.range.start.to_offset(buffer_snap);
13750                let end = symbol.range.end.to_offset(buffer_snap);
13751                let new_range = start..end;
13752                if start < selection.start || end > selection.end {
13753                    return Some(Selection {
13754                        id: selection.id,
13755                        start: new_range.start,
13756                        end: new_range.end,
13757                        goal: SelectionGoal::None,
13758                        reversed: selection.reversed,
13759                    });
13760                }
13761            }
13762            None
13763        }
13764
13765        let mut selected_larger_symbol = false;
13766        let new_selections = old_selections
13767            .iter()
13768            .map(|selection| match update_selection(selection, &buffer) {
13769                Some(new_selection) => {
13770                    if new_selection.range() != selection.range() {
13771                        selected_larger_symbol = true;
13772                    }
13773                    new_selection
13774                }
13775                None => selection.clone(),
13776            })
13777            .collect::<Vec<_>>();
13778
13779        if selected_larger_symbol {
13780            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13781                s.select(new_selections);
13782            });
13783        }
13784    }
13785
13786    pub fn select_larger_syntax_node(
13787        &mut self,
13788        _: &SelectLargerSyntaxNode,
13789        window: &mut Window,
13790        cx: &mut Context<Self>,
13791    ) {
13792        let Some(visible_row_count) = self.visible_row_count() else {
13793            return;
13794        };
13795        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13796        if old_selections.is_empty() {
13797            return;
13798        }
13799
13800        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13801
13802        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13803        let buffer = self.buffer.read(cx).snapshot(cx);
13804
13805        let mut selected_larger_node = false;
13806        let mut new_selections = old_selections
13807            .iter()
13808            .map(|selection| {
13809                let old_range = selection.start..selection.end;
13810
13811                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13812                    // manually select word at selection
13813                    if ["string_content", "inline"].contains(&node.kind()) {
13814                        let word_range = {
13815                            let display_point = buffer
13816                                .offset_to_point(old_range.start)
13817                                .to_display_point(&display_map);
13818                            let Range { start, end } =
13819                                movement::surrounding_word(&display_map, display_point);
13820                            start.to_point(&display_map).to_offset(&buffer)
13821                                ..end.to_point(&display_map).to_offset(&buffer)
13822                        };
13823                        // ignore if word is already selected
13824                        if !word_range.is_empty() && old_range != word_range {
13825                            let last_word_range = {
13826                                let display_point = buffer
13827                                    .offset_to_point(old_range.end)
13828                                    .to_display_point(&display_map);
13829                                let Range { start, end } =
13830                                    movement::surrounding_word(&display_map, display_point);
13831                                start.to_point(&display_map).to_offset(&buffer)
13832                                    ..end.to_point(&display_map).to_offset(&buffer)
13833                            };
13834                            // only select word if start and end point belongs to same word
13835                            if word_range == last_word_range {
13836                                selected_larger_node = true;
13837                                return Selection {
13838                                    id: selection.id,
13839                                    start: word_range.start,
13840                                    end: word_range.end,
13841                                    goal: SelectionGoal::None,
13842                                    reversed: selection.reversed,
13843                                };
13844                            }
13845                        }
13846                    }
13847                }
13848
13849                let mut new_range = old_range.clone();
13850                while let Some((_node, containing_range)) =
13851                    buffer.syntax_ancestor(new_range.clone())
13852                {
13853                    new_range = match containing_range {
13854                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13855                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13856                    };
13857                    if !display_map.intersects_fold(new_range.start)
13858                        && !display_map.intersects_fold(new_range.end)
13859                    {
13860                        break;
13861                    }
13862                }
13863
13864                selected_larger_node |= new_range != old_range;
13865                Selection {
13866                    id: selection.id,
13867                    start: new_range.start,
13868                    end: new_range.end,
13869                    goal: SelectionGoal::None,
13870                    reversed: selection.reversed,
13871                }
13872            })
13873            .collect::<Vec<_>>();
13874
13875        if !selected_larger_node {
13876            return; // don't put this call in the history
13877        }
13878
13879        // scroll based on transformation done to the last selection created by the user
13880        let (last_old, last_new) = old_selections
13881            .last()
13882            .zip(new_selections.last().cloned())
13883            .expect("old_selections isn't empty");
13884
13885        // revert selection
13886        let is_selection_reversed = {
13887            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13888            new_selections.last_mut().expect("checked above").reversed =
13889                should_newest_selection_be_reversed;
13890            should_newest_selection_be_reversed
13891        };
13892
13893        if selected_larger_node {
13894            self.select_syntax_node_history.disable_clearing = true;
13895            self.change_selections(None, window, cx, |s| {
13896                s.select(new_selections.clone());
13897            });
13898            self.select_syntax_node_history.disable_clearing = false;
13899        }
13900
13901        let start_row = last_new.start.to_display_point(&display_map).row().0;
13902        let end_row = last_new.end.to_display_point(&display_map).row().0;
13903        let selection_height = end_row - start_row + 1;
13904        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13905
13906        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13907        let scroll_behavior = if fits_on_the_screen {
13908            self.request_autoscroll(Autoscroll::fit(), cx);
13909            SelectSyntaxNodeScrollBehavior::FitSelection
13910        } else if is_selection_reversed {
13911            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13912            SelectSyntaxNodeScrollBehavior::CursorTop
13913        } else {
13914            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13915            SelectSyntaxNodeScrollBehavior::CursorBottom
13916        };
13917
13918        self.select_syntax_node_history.push((
13919            old_selections,
13920            scroll_behavior,
13921            is_selection_reversed,
13922        ));
13923    }
13924
13925    pub fn select_smaller_syntax_node(
13926        &mut self,
13927        _: &SelectSmallerSyntaxNode,
13928        window: &mut Window,
13929        cx: &mut Context<Self>,
13930    ) {
13931        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13932
13933        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13934            self.select_syntax_node_history.pop()
13935        {
13936            if let Some(selection) = selections.last_mut() {
13937                selection.reversed = is_selection_reversed;
13938            }
13939
13940            self.select_syntax_node_history.disable_clearing = true;
13941            self.change_selections(None, window, cx, |s| {
13942                s.select(selections.to_vec());
13943            });
13944            self.select_syntax_node_history.disable_clearing = false;
13945
13946            match scroll_behavior {
13947                SelectSyntaxNodeScrollBehavior::CursorTop => {
13948                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13949                }
13950                SelectSyntaxNodeScrollBehavior::FitSelection => {
13951                    self.request_autoscroll(Autoscroll::fit(), cx);
13952                }
13953                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13954                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13955                }
13956            }
13957        }
13958    }
13959
13960    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13961        if !EditorSettings::get_global(cx).gutter.runnables {
13962            self.clear_tasks();
13963            return Task::ready(());
13964        }
13965        let project = self.project.as_ref().map(Entity::downgrade);
13966        let task_sources = self.lsp_task_sources(cx);
13967        let multi_buffer = self.buffer.downgrade();
13968        cx.spawn_in(window, async move |editor, cx| {
13969            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13970            let Some(project) = project.and_then(|p| p.upgrade()) else {
13971                return;
13972            };
13973            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13974                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13975            }) else {
13976                return;
13977            };
13978
13979            let hide_runnables = project
13980                .update(cx, |project, cx| {
13981                    // Do not display any test indicators in non-dev server remote projects.
13982                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13983                })
13984                .unwrap_or(true);
13985            if hide_runnables {
13986                return;
13987            }
13988            let new_rows =
13989                cx.background_spawn({
13990                    let snapshot = display_snapshot.clone();
13991                    async move {
13992                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13993                    }
13994                })
13995                    .await;
13996            let Ok(lsp_tasks) =
13997                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13998            else {
13999                return;
14000            };
14001            let lsp_tasks = lsp_tasks.await;
14002
14003            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14004                lsp_tasks
14005                    .into_iter()
14006                    .flat_map(|(kind, tasks)| {
14007                        tasks.into_iter().filter_map(move |(location, task)| {
14008                            Some((kind.clone(), location?, task))
14009                        })
14010                    })
14011                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14012                        let buffer = location.target.buffer;
14013                        let buffer_snapshot = buffer.read(cx).snapshot();
14014                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14015                            |(excerpt_id, snapshot, _)| {
14016                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14017                                    display_snapshot
14018                                        .buffer_snapshot
14019                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14020                                } else {
14021                                    None
14022                                }
14023                            },
14024                        );
14025                        if let Some(offset) = offset {
14026                            let task_buffer_range =
14027                                location.target.range.to_point(&buffer_snapshot);
14028                            let context_buffer_range =
14029                                task_buffer_range.to_offset(&buffer_snapshot);
14030                            let context_range = BufferOffset(context_buffer_range.start)
14031                                ..BufferOffset(context_buffer_range.end);
14032
14033                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14034                                .or_insert_with(|| RunnableTasks {
14035                                    templates: Vec::new(),
14036                                    offset,
14037                                    column: task_buffer_range.start.column,
14038                                    extra_variables: HashMap::default(),
14039                                    context_range,
14040                                })
14041                                .templates
14042                                .push((kind, task.original_task().clone()));
14043                        }
14044
14045                        acc
14046                    })
14047            }) else {
14048                return;
14049            };
14050
14051            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14052                buffer.language_settings(cx).tasks.prefer_lsp
14053            }) else {
14054                return;
14055            };
14056
14057            let rows = Self::runnable_rows(
14058                project,
14059                display_snapshot,
14060                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14061                new_rows,
14062                cx.clone(),
14063            )
14064            .await;
14065            editor
14066                .update(cx, |editor, _| {
14067                    editor.clear_tasks();
14068                    for (key, mut value) in rows {
14069                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14070                            value.templates.extend(lsp_tasks.templates);
14071                        }
14072
14073                        editor.insert_tasks(key, value);
14074                    }
14075                    for (key, value) in lsp_tasks_by_rows {
14076                        editor.insert_tasks(key, value);
14077                    }
14078                })
14079                .ok();
14080        })
14081    }
14082    fn fetch_runnable_ranges(
14083        snapshot: &DisplaySnapshot,
14084        range: Range<Anchor>,
14085    ) -> Vec<language::RunnableRange> {
14086        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14087    }
14088
14089    fn runnable_rows(
14090        project: Entity<Project>,
14091        snapshot: DisplaySnapshot,
14092        prefer_lsp: bool,
14093        runnable_ranges: Vec<RunnableRange>,
14094        cx: AsyncWindowContext,
14095    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14096        cx.spawn(async move |cx| {
14097            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14098            for mut runnable in runnable_ranges {
14099                let Some(tasks) = cx
14100                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14101                    .ok()
14102                else {
14103                    continue;
14104                };
14105                let mut tasks = tasks.await;
14106
14107                if prefer_lsp {
14108                    tasks.retain(|(task_kind, _)| {
14109                        !matches!(task_kind, TaskSourceKind::Language { .. })
14110                    });
14111                }
14112                if tasks.is_empty() {
14113                    continue;
14114                }
14115
14116                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14117                let Some(row) = snapshot
14118                    .buffer_snapshot
14119                    .buffer_line_for_row(MultiBufferRow(point.row))
14120                    .map(|(_, range)| range.start.row)
14121                else {
14122                    continue;
14123                };
14124
14125                let context_range =
14126                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14127                runnable_rows.push((
14128                    (runnable.buffer_id, row),
14129                    RunnableTasks {
14130                        templates: tasks,
14131                        offset: snapshot
14132                            .buffer_snapshot
14133                            .anchor_before(runnable.run_range.start),
14134                        context_range,
14135                        column: point.column,
14136                        extra_variables: runnable.extra_captures,
14137                    },
14138                ));
14139            }
14140            runnable_rows
14141        })
14142    }
14143
14144    fn templates_with_tags(
14145        project: &Entity<Project>,
14146        runnable: &mut Runnable,
14147        cx: &mut App,
14148    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14149        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14150            let (worktree_id, file) = project
14151                .buffer_for_id(runnable.buffer, cx)
14152                .and_then(|buffer| buffer.read(cx).file())
14153                .map(|file| (file.worktree_id(cx), file.clone()))
14154                .unzip();
14155
14156            (
14157                project.task_store().read(cx).task_inventory().cloned(),
14158                worktree_id,
14159                file,
14160            )
14161        });
14162
14163        let tags = mem::take(&mut runnable.tags);
14164        let language = runnable.language.clone();
14165        cx.spawn(async move |cx| {
14166            let mut templates_with_tags = Vec::new();
14167            if let Some(inventory) = inventory {
14168                for RunnableTag(tag) in tags {
14169                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14170                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14171                    }) else {
14172                        return templates_with_tags;
14173                    };
14174                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14175                        move |(_, template)| {
14176                            template.tags.iter().any(|source_tag| source_tag == &tag)
14177                        },
14178                    ));
14179                }
14180            }
14181            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14182
14183            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14184                // Strongest source wins; if we have worktree tag binding, prefer that to
14185                // global and language bindings;
14186                // if we have a global binding, prefer that to language binding.
14187                let first_mismatch = templates_with_tags
14188                    .iter()
14189                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14190                if let Some(index) = first_mismatch {
14191                    templates_with_tags.truncate(index);
14192                }
14193            }
14194
14195            templates_with_tags
14196        })
14197    }
14198
14199    pub fn move_to_enclosing_bracket(
14200        &mut self,
14201        _: &MoveToEnclosingBracket,
14202        window: &mut Window,
14203        cx: &mut Context<Self>,
14204    ) {
14205        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14206        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14207            s.move_offsets_with(|snapshot, selection| {
14208                let Some(enclosing_bracket_ranges) =
14209                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14210                else {
14211                    return;
14212                };
14213
14214                let mut best_length = usize::MAX;
14215                let mut best_inside = false;
14216                let mut best_in_bracket_range = false;
14217                let mut best_destination = None;
14218                for (open, close) in enclosing_bracket_ranges {
14219                    let close = close.to_inclusive();
14220                    let length = close.end() - open.start;
14221                    let inside = selection.start >= open.end && selection.end <= *close.start();
14222                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14223                        || close.contains(&selection.head());
14224
14225                    // If best is next to a bracket and current isn't, skip
14226                    if !in_bracket_range && best_in_bracket_range {
14227                        continue;
14228                    }
14229
14230                    // Prefer smaller lengths unless best is inside and current isn't
14231                    if length > best_length && (best_inside || !inside) {
14232                        continue;
14233                    }
14234
14235                    best_length = length;
14236                    best_inside = inside;
14237                    best_in_bracket_range = in_bracket_range;
14238                    best_destination = Some(
14239                        if close.contains(&selection.start) && close.contains(&selection.end) {
14240                            if inside { open.end } else { open.start }
14241                        } else if inside {
14242                            *close.start()
14243                        } else {
14244                            *close.end()
14245                        },
14246                    );
14247                }
14248
14249                if let Some(destination) = best_destination {
14250                    selection.collapse_to(destination, SelectionGoal::None);
14251                }
14252            })
14253        });
14254    }
14255
14256    pub fn undo_selection(
14257        &mut self,
14258        _: &UndoSelection,
14259        window: &mut Window,
14260        cx: &mut Context<Self>,
14261    ) {
14262        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14263        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14264            self.selection_history.mode = SelectionHistoryMode::Undoing;
14265            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14266                this.end_selection(window, cx);
14267                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14268                    s.select_anchors(entry.selections.to_vec())
14269                });
14270            });
14271            self.selection_history.mode = SelectionHistoryMode::Normal;
14272
14273            self.select_next_state = entry.select_next_state;
14274            self.select_prev_state = entry.select_prev_state;
14275            self.add_selections_state = entry.add_selections_state;
14276        }
14277    }
14278
14279    pub fn redo_selection(
14280        &mut self,
14281        _: &RedoSelection,
14282        window: &mut Window,
14283        cx: &mut Context<Self>,
14284    ) {
14285        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14286        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14287            self.selection_history.mode = SelectionHistoryMode::Redoing;
14288            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14289                this.end_selection(window, cx);
14290                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14291                    s.select_anchors(entry.selections.to_vec())
14292                });
14293            });
14294            self.selection_history.mode = SelectionHistoryMode::Normal;
14295
14296            self.select_next_state = entry.select_next_state;
14297            self.select_prev_state = entry.select_prev_state;
14298            self.add_selections_state = entry.add_selections_state;
14299        }
14300    }
14301
14302    pub fn expand_excerpts(
14303        &mut self,
14304        action: &ExpandExcerpts,
14305        _: &mut Window,
14306        cx: &mut Context<Self>,
14307    ) {
14308        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14309    }
14310
14311    pub fn expand_excerpts_down(
14312        &mut self,
14313        action: &ExpandExcerptsDown,
14314        _: &mut Window,
14315        cx: &mut Context<Self>,
14316    ) {
14317        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14318    }
14319
14320    pub fn expand_excerpts_up(
14321        &mut self,
14322        action: &ExpandExcerptsUp,
14323        _: &mut Window,
14324        cx: &mut Context<Self>,
14325    ) {
14326        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14327    }
14328
14329    pub fn expand_excerpts_for_direction(
14330        &mut self,
14331        lines: u32,
14332        direction: ExpandExcerptDirection,
14333
14334        cx: &mut Context<Self>,
14335    ) {
14336        let selections = self.selections.disjoint_anchors();
14337
14338        let lines = if lines == 0 {
14339            EditorSettings::get_global(cx).expand_excerpt_lines
14340        } else {
14341            lines
14342        };
14343
14344        self.buffer.update(cx, |buffer, cx| {
14345            let snapshot = buffer.snapshot(cx);
14346            let mut excerpt_ids = selections
14347                .iter()
14348                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14349                .collect::<Vec<_>>();
14350            excerpt_ids.sort();
14351            excerpt_ids.dedup();
14352            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14353        })
14354    }
14355
14356    pub fn expand_excerpt(
14357        &mut self,
14358        excerpt: ExcerptId,
14359        direction: ExpandExcerptDirection,
14360        window: &mut Window,
14361        cx: &mut Context<Self>,
14362    ) {
14363        let current_scroll_position = self.scroll_position(cx);
14364        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14365        let mut should_scroll_up = false;
14366
14367        if direction == ExpandExcerptDirection::Down {
14368            let multi_buffer = self.buffer.read(cx);
14369            let snapshot = multi_buffer.snapshot(cx);
14370            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14371                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14372                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14373                        let buffer_snapshot = buffer.read(cx).snapshot();
14374                        let excerpt_end_row =
14375                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14376                        let last_row = buffer_snapshot.max_point().row;
14377                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14378                        should_scroll_up = lines_below >= lines_to_expand;
14379                    }
14380                }
14381            }
14382        }
14383
14384        self.buffer.update(cx, |buffer, cx| {
14385            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14386        });
14387
14388        if should_scroll_up {
14389            let new_scroll_position =
14390                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14391            self.set_scroll_position(new_scroll_position, window, cx);
14392        }
14393    }
14394
14395    pub fn go_to_singleton_buffer_point(
14396        &mut self,
14397        point: Point,
14398        window: &mut Window,
14399        cx: &mut Context<Self>,
14400    ) {
14401        self.go_to_singleton_buffer_range(point..point, window, cx);
14402    }
14403
14404    pub fn go_to_singleton_buffer_range(
14405        &mut self,
14406        range: Range<Point>,
14407        window: &mut Window,
14408        cx: &mut Context<Self>,
14409    ) {
14410        let multibuffer = self.buffer().read(cx);
14411        let Some(buffer) = multibuffer.as_singleton() else {
14412            return;
14413        };
14414        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14415            return;
14416        };
14417        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14418            return;
14419        };
14420        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14421            s.select_anchor_ranges([start..end])
14422        });
14423    }
14424
14425    pub fn go_to_diagnostic(
14426        &mut self,
14427        _: &GoToDiagnostic,
14428        window: &mut Window,
14429        cx: &mut Context<Self>,
14430    ) {
14431        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14432        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14433    }
14434
14435    pub fn go_to_prev_diagnostic(
14436        &mut self,
14437        _: &GoToPreviousDiagnostic,
14438        window: &mut Window,
14439        cx: &mut Context<Self>,
14440    ) {
14441        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14442        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14443    }
14444
14445    pub fn go_to_diagnostic_impl(
14446        &mut self,
14447        direction: Direction,
14448        window: &mut Window,
14449        cx: &mut Context<Self>,
14450    ) {
14451        let buffer = self.buffer.read(cx).snapshot(cx);
14452        let selection = self.selections.newest::<usize>(cx);
14453
14454        let mut active_group_id = None;
14455        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14456            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14457                active_group_id = Some(active_group.group_id);
14458            }
14459        }
14460
14461        fn filtered(
14462            snapshot: EditorSnapshot,
14463            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14464        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14465            diagnostics
14466                .filter(|entry| entry.range.start != entry.range.end)
14467                .filter(|entry| !entry.diagnostic.is_unnecessary)
14468                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14469        }
14470
14471        let snapshot = self.snapshot(window, cx);
14472        let before = filtered(
14473            snapshot.clone(),
14474            buffer
14475                .diagnostics_in_range(0..selection.start)
14476                .filter(|entry| entry.range.start <= selection.start),
14477        );
14478        let after = filtered(
14479            snapshot,
14480            buffer
14481                .diagnostics_in_range(selection.start..buffer.len())
14482                .filter(|entry| entry.range.start >= selection.start),
14483        );
14484
14485        let mut found: Option<DiagnosticEntry<usize>> = None;
14486        if direction == Direction::Prev {
14487            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14488            {
14489                for diagnostic in prev_diagnostics.into_iter().rev() {
14490                    if diagnostic.range.start != selection.start
14491                        || active_group_id
14492                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14493                    {
14494                        found = Some(diagnostic);
14495                        break 'outer;
14496                    }
14497                }
14498            }
14499        } else {
14500            for diagnostic in after.chain(before) {
14501                if diagnostic.range.start != selection.start
14502                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14503                {
14504                    found = Some(diagnostic);
14505                    break;
14506                }
14507            }
14508        }
14509        let Some(next_diagnostic) = found else {
14510            return;
14511        };
14512
14513        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14514            return;
14515        };
14516        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14517            s.select_ranges(vec![
14518                next_diagnostic.range.start..next_diagnostic.range.start,
14519            ])
14520        });
14521        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14522        self.refresh_inline_completion(false, true, window, cx);
14523    }
14524
14525    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14526        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14527        let snapshot = self.snapshot(window, cx);
14528        let selection = self.selections.newest::<Point>(cx);
14529        self.go_to_hunk_before_or_after_position(
14530            &snapshot,
14531            selection.head(),
14532            Direction::Next,
14533            window,
14534            cx,
14535        );
14536    }
14537
14538    pub fn go_to_hunk_before_or_after_position(
14539        &mut self,
14540        snapshot: &EditorSnapshot,
14541        position: Point,
14542        direction: Direction,
14543        window: &mut Window,
14544        cx: &mut Context<Editor>,
14545    ) {
14546        let row = if direction == Direction::Next {
14547            self.hunk_after_position(snapshot, position)
14548                .map(|hunk| hunk.row_range.start)
14549        } else {
14550            self.hunk_before_position(snapshot, position)
14551        };
14552
14553        if let Some(row) = row {
14554            let destination = Point::new(row.0, 0);
14555            let autoscroll = Autoscroll::center();
14556
14557            self.unfold_ranges(&[destination..destination], false, false, cx);
14558            self.change_selections(Some(autoscroll), window, cx, |s| {
14559                s.select_ranges([destination..destination]);
14560            });
14561        }
14562    }
14563
14564    fn hunk_after_position(
14565        &mut self,
14566        snapshot: &EditorSnapshot,
14567        position: Point,
14568    ) -> Option<MultiBufferDiffHunk> {
14569        snapshot
14570            .buffer_snapshot
14571            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14572            .find(|hunk| hunk.row_range.start.0 > position.row)
14573            .or_else(|| {
14574                snapshot
14575                    .buffer_snapshot
14576                    .diff_hunks_in_range(Point::zero()..position)
14577                    .find(|hunk| hunk.row_range.end.0 < position.row)
14578            })
14579    }
14580
14581    fn go_to_prev_hunk(
14582        &mut self,
14583        _: &GoToPreviousHunk,
14584        window: &mut Window,
14585        cx: &mut Context<Self>,
14586    ) {
14587        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14588        let snapshot = self.snapshot(window, cx);
14589        let selection = self.selections.newest::<Point>(cx);
14590        self.go_to_hunk_before_or_after_position(
14591            &snapshot,
14592            selection.head(),
14593            Direction::Prev,
14594            window,
14595            cx,
14596        );
14597    }
14598
14599    fn hunk_before_position(
14600        &mut self,
14601        snapshot: &EditorSnapshot,
14602        position: Point,
14603    ) -> Option<MultiBufferRow> {
14604        snapshot
14605            .buffer_snapshot
14606            .diff_hunk_before(position)
14607            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14608    }
14609
14610    fn go_to_next_change(
14611        &mut self,
14612        _: &GoToNextChange,
14613        window: &mut Window,
14614        cx: &mut Context<Self>,
14615    ) {
14616        if let Some(selections) = self
14617            .change_list
14618            .next_change(1, Direction::Next)
14619            .map(|s| s.to_vec())
14620        {
14621            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14622                let map = s.display_map();
14623                s.select_display_ranges(selections.iter().map(|a| {
14624                    let point = a.to_display_point(&map);
14625                    point..point
14626                }))
14627            })
14628        }
14629    }
14630
14631    fn go_to_previous_change(
14632        &mut self,
14633        _: &GoToPreviousChange,
14634        window: &mut Window,
14635        cx: &mut Context<Self>,
14636    ) {
14637        if let Some(selections) = self
14638            .change_list
14639            .next_change(1, Direction::Prev)
14640            .map(|s| s.to_vec())
14641        {
14642            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14643                let map = s.display_map();
14644                s.select_display_ranges(selections.iter().map(|a| {
14645                    let point = a.to_display_point(&map);
14646                    point..point
14647                }))
14648            })
14649        }
14650    }
14651
14652    fn go_to_line<T: 'static>(
14653        &mut self,
14654        position: Anchor,
14655        highlight_color: Option<Hsla>,
14656        window: &mut Window,
14657        cx: &mut Context<Self>,
14658    ) {
14659        let snapshot = self.snapshot(window, cx).display_snapshot;
14660        let position = position.to_point(&snapshot.buffer_snapshot);
14661        let start = snapshot
14662            .buffer_snapshot
14663            .clip_point(Point::new(position.row, 0), Bias::Left);
14664        let end = start + Point::new(1, 0);
14665        let start = snapshot.buffer_snapshot.anchor_before(start);
14666        let end = snapshot.buffer_snapshot.anchor_before(end);
14667
14668        self.highlight_rows::<T>(
14669            start..end,
14670            highlight_color
14671                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14672            Default::default(),
14673            cx,
14674        );
14675
14676        if self.buffer.read(cx).is_singleton() {
14677            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14678        }
14679    }
14680
14681    pub fn go_to_definition(
14682        &mut self,
14683        _: &GoToDefinition,
14684        window: &mut Window,
14685        cx: &mut Context<Self>,
14686    ) -> Task<Result<Navigated>> {
14687        let definition =
14688            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14689        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14690        cx.spawn_in(window, async move |editor, cx| {
14691            if definition.await? == Navigated::Yes {
14692                return Ok(Navigated::Yes);
14693            }
14694            match fallback_strategy {
14695                GoToDefinitionFallback::None => Ok(Navigated::No),
14696                GoToDefinitionFallback::FindAllReferences => {
14697                    match editor.update_in(cx, |editor, window, cx| {
14698                        editor.find_all_references(&FindAllReferences, window, cx)
14699                    })? {
14700                        Some(references) => references.await,
14701                        None => Ok(Navigated::No),
14702                    }
14703                }
14704            }
14705        })
14706    }
14707
14708    pub fn go_to_declaration(
14709        &mut self,
14710        _: &GoToDeclaration,
14711        window: &mut Window,
14712        cx: &mut Context<Self>,
14713    ) -> Task<Result<Navigated>> {
14714        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14715    }
14716
14717    pub fn go_to_declaration_split(
14718        &mut self,
14719        _: &GoToDeclaration,
14720        window: &mut Window,
14721        cx: &mut Context<Self>,
14722    ) -> Task<Result<Navigated>> {
14723        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14724    }
14725
14726    pub fn go_to_implementation(
14727        &mut self,
14728        _: &GoToImplementation,
14729        window: &mut Window,
14730        cx: &mut Context<Self>,
14731    ) -> Task<Result<Navigated>> {
14732        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14733    }
14734
14735    pub fn go_to_implementation_split(
14736        &mut self,
14737        _: &GoToImplementationSplit,
14738        window: &mut Window,
14739        cx: &mut Context<Self>,
14740    ) -> Task<Result<Navigated>> {
14741        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14742    }
14743
14744    pub fn go_to_type_definition(
14745        &mut self,
14746        _: &GoToTypeDefinition,
14747        window: &mut Window,
14748        cx: &mut Context<Self>,
14749    ) -> Task<Result<Navigated>> {
14750        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14751    }
14752
14753    pub fn go_to_definition_split(
14754        &mut self,
14755        _: &GoToDefinitionSplit,
14756        window: &mut Window,
14757        cx: &mut Context<Self>,
14758    ) -> Task<Result<Navigated>> {
14759        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14760    }
14761
14762    pub fn go_to_type_definition_split(
14763        &mut self,
14764        _: &GoToTypeDefinitionSplit,
14765        window: &mut Window,
14766        cx: &mut Context<Self>,
14767    ) -> Task<Result<Navigated>> {
14768        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14769    }
14770
14771    fn go_to_definition_of_kind(
14772        &mut self,
14773        kind: GotoDefinitionKind,
14774        split: bool,
14775        window: &mut Window,
14776        cx: &mut Context<Self>,
14777    ) -> Task<Result<Navigated>> {
14778        let Some(provider) = self.semantics_provider.clone() else {
14779            return Task::ready(Ok(Navigated::No));
14780        };
14781        let head = self.selections.newest::<usize>(cx).head();
14782        let buffer = self.buffer.read(cx);
14783        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14784            text_anchor
14785        } else {
14786            return Task::ready(Ok(Navigated::No));
14787        };
14788
14789        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14790            return Task::ready(Ok(Navigated::No));
14791        };
14792
14793        cx.spawn_in(window, async move |editor, cx| {
14794            let definitions = definitions.await?;
14795            let navigated = editor
14796                .update_in(cx, |editor, window, cx| {
14797                    editor.navigate_to_hover_links(
14798                        Some(kind),
14799                        definitions
14800                            .into_iter()
14801                            .filter(|location| {
14802                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14803                            })
14804                            .map(HoverLink::Text)
14805                            .collect::<Vec<_>>(),
14806                        split,
14807                        window,
14808                        cx,
14809                    )
14810                })?
14811                .await?;
14812            anyhow::Ok(navigated)
14813        })
14814    }
14815
14816    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14817        let selection = self.selections.newest_anchor();
14818        let head = selection.head();
14819        let tail = selection.tail();
14820
14821        let Some((buffer, start_position)) =
14822            self.buffer.read(cx).text_anchor_for_position(head, cx)
14823        else {
14824            return;
14825        };
14826
14827        let end_position = if head != tail {
14828            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14829                return;
14830            };
14831            Some(pos)
14832        } else {
14833            None
14834        };
14835
14836        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14837            let url = if let Some(end_pos) = end_position {
14838                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14839            } else {
14840                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14841            };
14842
14843            if let Some(url) = url {
14844                editor.update(cx, |_, cx| {
14845                    cx.open_url(&url);
14846                })
14847            } else {
14848                Ok(())
14849            }
14850        });
14851
14852        url_finder.detach();
14853    }
14854
14855    pub fn open_selected_filename(
14856        &mut self,
14857        _: &OpenSelectedFilename,
14858        window: &mut Window,
14859        cx: &mut Context<Self>,
14860    ) {
14861        let Some(workspace) = self.workspace() else {
14862            return;
14863        };
14864
14865        let position = self.selections.newest_anchor().head();
14866
14867        let Some((buffer, buffer_position)) =
14868            self.buffer.read(cx).text_anchor_for_position(position, cx)
14869        else {
14870            return;
14871        };
14872
14873        let project = self.project.clone();
14874
14875        cx.spawn_in(window, async move |_, cx| {
14876            let result = find_file(&buffer, project, buffer_position, cx).await;
14877
14878            if let Some((_, path)) = result {
14879                workspace
14880                    .update_in(cx, |workspace, window, cx| {
14881                        workspace.open_resolved_path(path, window, cx)
14882                    })?
14883                    .await?;
14884            }
14885            anyhow::Ok(())
14886        })
14887        .detach();
14888    }
14889
14890    pub(crate) fn navigate_to_hover_links(
14891        &mut self,
14892        kind: Option<GotoDefinitionKind>,
14893        mut definitions: Vec<HoverLink>,
14894        split: bool,
14895        window: &mut Window,
14896        cx: &mut Context<Editor>,
14897    ) -> Task<Result<Navigated>> {
14898        // If there is one definition, just open it directly
14899        if definitions.len() == 1 {
14900            let definition = definitions.pop().unwrap();
14901
14902            enum TargetTaskResult {
14903                Location(Option<Location>),
14904                AlreadyNavigated,
14905            }
14906
14907            let target_task = match definition {
14908                HoverLink::Text(link) => {
14909                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14910                }
14911                HoverLink::InlayHint(lsp_location, server_id) => {
14912                    let computation =
14913                        self.compute_target_location(lsp_location, server_id, window, cx);
14914                    cx.background_spawn(async move {
14915                        let location = computation.await?;
14916                        Ok(TargetTaskResult::Location(location))
14917                    })
14918                }
14919                HoverLink::Url(url) => {
14920                    cx.open_url(&url);
14921                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14922                }
14923                HoverLink::File(path) => {
14924                    if let Some(workspace) = self.workspace() {
14925                        cx.spawn_in(window, async move |_, cx| {
14926                            workspace
14927                                .update_in(cx, |workspace, window, cx| {
14928                                    workspace.open_resolved_path(path, window, cx)
14929                                })?
14930                                .await
14931                                .map(|_| TargetTaskResult::AlreadyNavigated)
14932                        })
14933                    } else {
14934                        Task::ready(Ok(TargetTaskResult::Location(None)))
14935                    }
14936                }
14937            };
14938            cx.spawn_in(window, async move |editor, cx| {
14939                let target = match target_task.await.context("target resolution task")? {
14940                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14941                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14942                    TargetTaskResult::Location(Some(target)) => target,
14943                };
14944
14945                editor.update_in(cx, |editor, window, cx| {
14946                    let Some(workspace) = editor.workspace() else {
14947                        return Navigated::No;
14948                    };
14949                    let pane = workspace.read(cx).active_pane().clone();
14950
14951                    let range = target.range.to_point(target.buffer.read(cx));
14952                    let range = editor.range_for_match(&range);
14953                    let range = collapse_multiline_range(range);
14954
14955                    if !split
14956                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14957                    {
14958                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14959                    } else {
14960                        window.defer(cx, move |window, cx| {
14961                            let target_editor: Entity<Self> =
14962                                workspace.update(cx, |workspace, cx| {
14963                                    let pane = if split {
14964                                        workspace.adjacent_pane(window, cx)
14965                                    } else {
14966                                        workspace.active_pane().clone()
14967                                    };
14968
14969                                    workspace.open_project_item(
14970                                        pane,
14971                                        target.buffer.clone(),
14972                                        true,
14973                                        true,
14974                                        window,
14975                                        cx,
14976                                    )
14977                                });
14978                            target_editor.update(cx, |target_editor, cx| {
14979                                // When selecting a definition in a different buffer, disable the nav history
14980                                // to avoid creating a history entry at the previous cursor location.
14981                                pane.update(cx, |pane, _| pane.disable_history());
14982                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14983                                pane.update(cx, |pane, _| pane.enable_history());
14984                            });
14985                        });
14986                    }
14987                    Navigated::Yes
14988                })
14989            })
14990        } else if !definitions.is_empty() {
14991            cx.spawn_in(window, async move |editor, cx| {
14992                let (title, location_tasks, workspace) = editor
14993                    .update_in(cx, |editor, window, cx| {
14994                        let tab_kind = match kind {
14995                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14996                            _ => "Definitions",
14997                        };
14998                        let title = definitions
14999                            .iter()
15000                            .find_map(|definition| match definition {
15001                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15002                                    let buffer = origin.buffer.read(cx);
15003                                    format!(
15004                                        "{} for {}",
15005                                        tab_kind,
15006                                        buffer
15007                                            .text_for_range(origin.range.clone())
15008                                            .collect::<String>()
15009                                    )
15010                                }),
15011                                HoverLink::InlayHint(_, _) => None,
15012                                HoverLink::Url(_) => None,
15013                                HoverLink::File(_) => None,
15014                            })
15015                            .unwrap_or(tab_kind.to_string());
15016                        let location_tasks = definitions
15017                            .into_iter()
15018                            .map(|definition| match definition {
15019                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15020                                HoverLink::InlayHint(lsp_location, server_id) => editor
15021                                    .compute_target_location(lsp_location, server_id, window, cx),
15022                                HoverLink::Url(_) => Task::ready(Ok(None)),
15023                                HoverLink::File(_) => Task::ready(Ok(None)),
15024                            })
15025                            .collect::<Vec<_>>();
15026                        (title, location_tasks, editor.workspace().clone())
15027                    })
15028                    .context("location tasks preparation")?;
15029
15030                let locations = future::join_all(location_tasks)
15031                    .await
15032                    .into_iter()
15033                    .filter_map(|location| location.transpose())
15034                    .collect::<Result<_>>()
15035                    .context("location tasks")?;
15036
15037                let Some(workspace) = workspace else {
15038                    return Ok(Navigated::No);
15039                };
15040                let opened = workspace
15041                    .update_in(cx, |workspace, window, cx| {
15042                        Self::open_locations_in_multibuffer(
15043                            workspace,
15044                            locations,
15045                            title,
15046                            split,
15047                            MultibufferSelectionMode::First,
15048                            window,
15049                            cx,
15050                        )
15051                    })
15052                    .ok();
15053
15054                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15055            })
15056        } else {
15057            Task::ready(Ok(Navigated::No))
15058        }
15059    }
15060
15061    fn compute_target_location(
15062        &self,
15063        lsp_location: lsp::Location,
15064        server_id: LanguageServerId,
15065        window: &mut Window,
15066        cx: &mut Context<Self>,
15067    ) -> Task<anyhow::Result<Option<Location>>> {
15068        let Some(project) = self.project.clone() else {
15069            return Task::ready(Ok(None));
15070        };
15071
15072        cx.spawn_in(window, async move |editor, cx| {
15073            let location_task = editor.update(cx, |_, cx| {
15074                project.update(cx, |project, cx| {
15075                    let language_server_name = project
15076                        .language_server_statuses(cx)
15077                        .find(|(id, _)| server_id == *id)
15078                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15079                    language_server_name.map(|language_server_name| {
15080                        project.open_local_buffer_via_lsp(
15081                            lsp_location.uri.clone(),
15082                            server_id,
15083                            language_server_name,
15084                            cx,
15085                        )
15086                    })
15087                })
15088            })?;
15089            let location = match location_task {
15090                Some(task) => Some({
15091                    let target_buffer_handle = task.await.context("open local buffer")?;
15092                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15093                        let target_start = target_buffer
15094                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15095                        let target_end = target_buffer
15096                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15097                        target_buffer.anchor_after(target_start)
15098                            ..target_buffer.anchor_before(target_end)
15099                    })?;
15100                    Location {
15101                        buffer: target_buffer_handle,
15102                        range,
15103                    }
15104                }),
15105                None => None,
15106            };
15107            Ok(location)
15108        })
15109    }
15110
15111    pub fn find_all_references(
15112        &mut self,
15113        _: &FindAllReferences,
15114        window: &mut Window,
15115        cx: &mut Context<Self>,
15116    ) -> Option<Task<Result<Navigated>>> {
15117        let selection = self.selections.newest::<usize>(cx);
15118        let multi_buffer = self.buffer.read(cx);
15119        let head = selection.head();
15120
15121        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15122        let head_anchor = multi_buffer_snapshot.anchor_at(
15123            head,
15124            if head < selection.tail() {
15125                Bias::Right
15126            } else {
15127                Bias::Left
15128            },
15129        );
15130
15131        match self
15132            .find_all_references_task_sources
15133            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15134        {
15135            Ok(_) => {
15136                log::info!(
15137                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15138                );
15139                return None;
15140            }
15141            Err(i) => {
15142                self.find_all_references_task_sources.insert(i, head_anchor);
15143            }
15144        }
15145
15146        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15147        let workspace = self.workspace()?;
15148        let project = workspace.read(cx).project().clone();
15149        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15150        Some(cx.spawn_in(window, async move |editor, cx| {
15151            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15152                if let Ok(i) = editor
15153                    .find_all_references_task_sources
15154                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15155                {
15156                    editor.find_all_references_task_sources.remove(i);
15157                }
15158            });
15159
15160            let locations = references.await?;
15161            if locations.is_empty() {
15162                return anyhow::Ok(Navigated::No);
15163            }
15164
15165            workspace.update_in(cx, |workspace, window, cx| {
15166                let title = locations
15167                    .first()
15168                    .as_ref()
15169                    .map(|location| {
15170                        let buffer = location.buffer.read(cx);
15171                        format!(
15172                            "References to `{}`",
15173                            buffer
15174                                .text_for_range(location.range.clone())
15175                                .collect::<String>()
15176                        )
15177                    })
15178                    .unwrap();
15179                Self::open_locations_in_multibuffer(
15180                    workspace,
15181                    locations,
15182                    title,
15183                    false,
15184                    MultibufferSelectionMode::First,
15185                    window,
15186                    cx,
15187                );
15188                Navigated::Yes
15189            })
15190        }))
15191    }
15192
15193    /// Opens a multibuffer with the given project locations in it
15194    pub fn open_locations_in_multibuffer(
15195        workspace: &mut Workspace,
15196        mut locations: Vec<Location>,
15197        title: String,
15198        split: bool,
15199        multibuffer_selection_mode: MultibufferSelectionMode,
15200        window: &mut Window,
15201        cx: &mut Context<Workspace>,
15202    ) {
15203        // If there are multiple definitions, open them in a multibuffer
15204        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15205        let mut locations = locations.into_iter().peekable();
15206        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15207        let capability = workspace.project().read(cx).capability();
15208
15209        let excerpt_buffer = cx.new(|cx| {
15210            let mut multibuffer = MultiBuffer::new(capability);
15211            while let Some(location) = locations.next() {
15212                let buffer = location.buffer.read(cx);
15213                let mut ranges_for_buffer = Vec::new();
15214                let range = location.range.to_point(buffer);
15215                ranges_for_buffer.push(range.clone());
15216
15217                while let Some(next_location) = locations.peek() {
15218                    if next_location.buffer == location.buffer {
15219                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15220                        locations.next();
15221                    } else {
15222                        break;
15223                    }
15224                }
15225
15226                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15227                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15228                    PathKey::for_buffer(&location.buffer, cx),
15229                    location.buffer.clone(),
15230                    ranges_for_buffer,
15231                    DEFAULT_MULTIBUFFER_CONTEXT,
15232                    cx,
15233                );
15234                ranges.extend(new_ranges)
15235            }
15236
15237            multibuffer.with_title(title)
15238        });
15239
15240        let editor = cx.new(|cx| {
15241            Editor::for_multibuffer(
15242                excerpt_buffer,
15243                Some(workspace.project().clone()),
15244                window,
15245                cx,
15246            )
15247        });
15248        editor.update(cx, |editor, cx| {
15249            match multibuffer_selection_mode {
15250                MultibufferSelectionMode::First => {
15251                    if let Some(first_range) = ranges.first() {
15252                        editor.change_selections(None, window, cx, |selections| {
15253                            selections.clear_disjoint();
15254                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15255                        });
15256                    }
15257                    editor.highlight_background::<Self>(
15258                        &ranges,
15259                        |theme| theme.editor_highlighted_line_background,
15260                        cx,
15261                    );
15262                }
15263                MultibufferSelectionMode::All => {
15264                    editor.change_selections(None, window, cx, |selections| {
15265                        selections.clear_disjoint();
15266                        selections.select_anchor_ranges(ranges);
15267                    });
15268                }
15269            }
15270            editor.register_buffers_with_language_servers(cx);
15271        });
15272
15273        let item = Box::new(editor);
15274        let item_id = item.item_id();
15275
15276        if split {
15277            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15278        } else {
15279            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15280                let (preview_item_id, preview_item_idx) =
15281                    workspace.active_pane().read_with(cx, |pane, _| {
15282                        (pane.preview_item_id(), pane.preview_item_idx())
15283                    });
15284
15285                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15286
15287                if let Some(preview_item_id) = preview_item_id {
15288                    workspace.active_pane().update(cx, |pane, cx| {
15289                        pane.remove_item(preview_item_id, false, false, window, cx);
15290                    });
15291                }
15292            } else {
15293                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15294            }
15295        }
15296        workspace.active_pane().update(cx, |pane, cx| {
15297            pane.set_preview_item_id(Some(item_id), cx);
15298        });
15299    }
15300
15301    pub fn rename(
15302        &mut self,
15303        _: &Rename,
15304        window: &mut Window,
15305        cx: &mut Context<Self>,
15306    ) -> Option<Task<Result<()>>> {
15307        use language::ToOffset as _;
15308
15309        let provider = self.semantics_provider.clone()?;
15310        let selection = self.selections.newest_anchor().clone();
15311        let (cursor_buffer, cursor_buffer_position) = self
15312            .buffer
15313            .read(cx)
15314            .text_anchor_for_position(selection.head(), cx)?;
15315        let (tail_buffer, cursor_buffer_position_end) = self
15316            .buffer
15317            .read(cx)
15318            .text_anchor_for_position(selection.tail(), cx)?;
15319        if tail_buffer != cursor_buffer {
15320            return None;
15321        }
15322
15323        let snapshot = cursor_buffer.read(cx).snapshot();
15324        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15325        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15326        let prepare_rename = provider
15327            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15328            .unwrap_or_else(|| Task::ready(Ok(None)));
15329        drop(snapshot);
15330
15331        Some(cx.spawn_in(window, async move |this, cx| {
15332            let rename_range = if let Some(range) = prepare_rename.await? {
15333                Some(range)
15334            } else {
15335                this.update(cx, |this, cx| {
15336                    let buffer = this.buffer.read(cx).snapshot(cx);
15337                    let mut buffer_highlights = this
15338                        .document_highlights_for_position(selection.head(), &buffer)
15339                        .filter(|highlight| {
15340                            highlight.start.excerpt_id == selection.head().excerpt_id
15341                                && highlight.end.excerpt_id == selection.head().excerpt_id
15342                        });
15343                    buffer_highlights
15344                        .next()
15345                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15346                })?
15347            };
15348            if let Some(rename_range) = rename_range {
15349                this.update_in(cx, |this, window, cx| {
15350                    let snapshot = cursor_buffer.read(cx).snapshot();
15351                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15352                    let cursor_offset_in_rename_range =
15353                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15354                    let cursor_offset_in_rename_range_end =
15355                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15356
15357                    this.take_rename(false, window, cx);
15358                    let buffer = this.buffer.read(cx).read(cx);
15359                    let cursor_offset = selection.head().to_offset(&buffer);
15360                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15361                    let rename_end = rename_start + rename_buffer_range.len();
15362                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15363                    let mut old_highlight_id = None;
15364                    let old_name: Arc<str> = buffer
15365                        .chunks(rename_start..rename_end, true)
15366                        .map(|chunk| {
15367                            if old_highlight_id.is_none() {
15368                                old_highlight_id = chunk.syntax_highlight_id;
15369                            }
15370                            chunk.text
15371                        })
15372                        .collect::<String>()
15373                        .into();
15374
15375                    drop(buffer);
15376
15377                    // Position the selection in the rename editor so that it matches the current selection.
15378                    this.show_local_selections = false;
15379                    let rename_editor = cx.new(|cx| {
15380                        let mut editor = Editor::single_line(window, cx);
15381                        editor.buffer.update(cx, |buffer, cx| {
15382                            buffer.edit([(0..0, old_name.clone())], None, cx)
15383                        });
15384                        let rename_selection_range = match cursor_offset_in_rename_range
15385                            .cmp(&cursor_offset_in_rename_range_end)
15386                        {
15387                            Ordering::Equal => {
15388                                editor.select_all(&SelectAll, window, cx);
15389                                return editor;
15390                            }
15391                            Ordering::Less => {
15392                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15393                            }
15394                            Ordering::Greater => {
15395                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15396                            }
15397                        };
15398                        if rename_selection_range.end > old_name.len() {
15399                            editor.select_all(&SelectAll, window, cx);
15400                        } else {
15401                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15402                                s.select_ranges([rename_selection_range]);
15403                            });
15404                        }
15405                        editor
15406                    });
15407                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15408                        if e == &EditorEvent::Focused {
15409                            cx.emit(EditorEvent::FocusedIn)
15410                        }
15411                    })
15412                    .detach();
15413
15414                    let write_highlights =
15415                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15416                    let read_highlights =
15417                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15418                    let ranges = write_highlights
15419                        .iter()
15420                        .flat_map(|(_, ranges)| ranges.iter())
15421                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15422                        .cloned()
15423                        .collect();
15424
15425                    this.highlight_text::<Rename>(
15426                        ranges,
15427                        HighlightStyle {
15428                            fade_out: Some(0.6),
15429                            ..Default::default()
15430                        },
15431                        cx,
15432                    );
15433                    let rename_focus_handle = rename_editor.focus_handle(cx);
15434                    window.focus(&rename_focus_handle);
15435                    let block_id = this.insert_blocks(
15436                        [BlockProperties {
15437                            style: BlockStyle::Flex,
15438                            placement: BlockPlacement::Below(range.start),
15439                            height: Some(1),
15440                            render: Arc::new({
15441                                let rename_editor = rename_editor.clone();
15442                                move |cx: &mut BlockContext| {
15443                                    let mut text_style = cx.editor_style.text.clone();
15444                                    if let Some(highlight_style) = old_highlight_id
15445                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15446                                    {
15447                                        text_style = text_style.highlight(highlight_style);
15448                                    }
15449                                    div()
15450                                        .block_mouse_except_scroll()
15451                                        .pl(cx.anchor_x)
15452                                        .child(EditorElement::new(
15453                                            &rename_editor,
15454                                            EditorStyle {
15455                                                background: cx.theme().system().transparent,
15456                                                local_player: cx.editor_style.local_player,
15457                                                text: text_style,
15458                                                scrollbar_width: cx.editor_style.scrollbar_width,
15459                                                syntax: cx.editor_style.syntax.clone(),
15460                                                status: cx.editor_style.status.clone(),
15461                                                inlay_hints_style: HighlightStyle {
15462                                                    font_weight: Some(FontWeight::BOLD),
15463                                                    ..make_inlay_hints_style(cx.app)
15464                                                },
15465                                                inline_completion_styles: make_suggestion_styles(
15466                                                    cx.app,
15467                                                ),
15468                                                ..EditorStyle::default()
15469                                            },
15470                                        ))
15471                                        .into_any_element()
15472                                }
15473                            }),
15474                            priority: 0,
15475                            render_in_minimap: true,
15476                        }],
15477                        Some(Autoscroll::fit()),
15478                        cx,
15479                    )[0];
15480                    this.pending_rename = Some(RenameState {
15481                        range,
15482                        old_name,
15483                        editor: rename_editor,
15484                        block_id,
15485                    });
15486                })?;
15487            }
15488
15489            Ok(())
15490        }))
15491    }
15492
15493    pub fn confirm_rename(
15494        &mut self,
15495        _: &ConfirmRename,
15496        window: &mut Window,
15497        cx: &mut Context<Self>,
15498    ) -> Option<Task<Result<()>>> {
15499        let rename = self.take_rename(false, window, cx)?;
15500        let workspace = self.workspace()?.downgrade();
15501        let (buffer, start) = self
15502            .buffer
15503            .read(cx)
15504            .text_anchor_for_position(rename.range.start, cx)?;
15505        let (end_buffer, _) = self
15506            .buffer
15507            .read(cx)
15508            .text_anchor_for_position(rename.range.end, cx)?;
15509        if buffer != end_buffer {
15510            return None;
15511        }
15512
15513        let old_name = rename.old_name;
15514        let new_name = rename.editor.read(cx).text(cx);
15515
15516        let rename = self.semantics_provider.as_ref()?.perform_rename(
15517            &buffer,
15518            start,
15519            new_name.clone(),
15520            cx,
15521        )?;
15522
15523        Some(cx.spawn_in(window, async move |editor, cx| {
15524            let project_transaction = rename.await?;
15525            Self::open_project_transaction(
15526                &editor,
15527                workspace,
15528                project_transaction,
15529                format!("Rename: {}{}", old_name, new_name),
15530                cx,
15531            )
15532            .await?;
15533
15534            editor.update(cx, |editor, cx| {
15535                editor.refresh_document_highlights(cx);
15536            })?;
15537            Ok(())
15538        }))
15539    }
15540
15541    fn take_rename(
15542        &mut self,
15543        moving_cursor: bool,
15544        window: &mut Window,
15545        cx: &mut Context<Self>,
15546    ) -> Option<RenameState> {
15547        let rename = self.pending_rename.take()?;
15548        if rename.editor.focus_handle(cx).is_focused(window) {
15549            window.focus(&self.focus_handle);
15550        }
15551
15552        self.remove_blocks(
15553            [rename.block_id].into_iter().collect(),
15554            Some(Autoscroll::fit()),
15555            cx,
15556        );
15557        self.clear_highlights::<Rename>(cx);
15558        self.show_local_selections = true;
15559
15560        if moving_cursor {
15561            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15562                editor.selections.newest::<usize>(cx).head()
15563            });
15564
15565            // Update the selection to match the position of the selection inside
15566            // the rename editor.
15567            let snapshot = self.buffer.read(cx).read(cx);
15568            let rename_range = rename.range.to_offset(&snapshot);
15569            let cursor_in_editor = snapshot
15570                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15571                .min(rename_range.end);
15572            drop(snapshot);
15573
15574            self.change_selections(None, window, cx, |s| {
15575                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15576            });
15577        } else {
15578            self.refresh_document_highlights(cx);
15579        }
15580
15581        Some(rename)
15582    }
15583
15584    pub fn pending_rename(&self) -> Option<&RenameState> {
15585        self.pending_rename.as_ref()
15586    }
15587
15588    fn format(
15589        &mut self,
15590        _: &Format,
15591        window: &mut Window,
15592        cx: &mut Context<Self>,
15593    ) -> Option<Task<Result<()>>> {
15594        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15595
15596        let project = match &self.project {
15597            Some(project) => project.clone(),
15598            None => return None,
15599        };
15600
15601        Some(self.perform_format(
15602            project,
15603            FormatTrigger::Manual,
15604            FormatTarget::Buffers,
15605            window,
15606            cx,
15607        ))
15608    }
15609
15610    fn format_selections(
15611        &mut self,
15612        _: &FormatSelections,
15613        window: &mut Window,
15614        cx: &mut Context<Self>,
15615    ) -> Option<Task<Result<()>>> {
15616        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15617
15618        let project = match &self.project {
15619            Some(project) => project.clone(),
15620            None => return None,
15621        };
15622
15623        let ranges = self
15624            .selections
15625            .all_adjusted(cx)
15626            .into_iter()
15627            .map(|selection| selection.range())
15628            .collect_vec();
15629
15630        Some(self.perform_format(
15631            project,
15632            FormatTrigger::Manual,
15633            FormatTarget::Ranges(ranges),
15634            window,
15635            cx,
15636        ))
15637    }
15638
15639    fn perform_format(
15640        &mut self,
15641        project: Entity<Project>,
15642        trigger: FormatTrigger,
15643        target: FormatTarget,
15644        window: &mut Window,
15645        cx: &mut Context<Self>,
15646    ) -> Task<Result<()>> {
15647        let buffer = self.buffer.clone();
15648        let (buffers, target) = match target {
15649            FormatTarget::Buffers => {
15650                let mut buffers = buffer.read(cx).all_buffers();
15651                if trigger == FormatTrigger::Save {
15652                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15653                }
15654                (buffers, LspFormatTarget::Buffers)
15655            }
15656            FormatTarget::Ranges(selection_ranges) => {
15657                let multi_buffer = buffer.read(cx);
15658                let snapshot = multi_buffer.read(cx);
15659                let mut buffers = HashSet::default();
15660                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15661                    BTreeMap::new();
15662                for selection_range in selection_ranges {
15663                    for (buffer, buffer_range, _) in
15664                        snapshot.range_to_buffer_ranges(selection_range)
15665                    {
15666                        let buffer_id = buffer.remote_id();
15667                        let start = buffer.anchor_before(buffer_range.start);
15668                        let end = buffer.anchor_after(buffer_range.end);
15669                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15670                        buffer_id_to_ranges
15671                            .entry(buffer_id)
15672                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15673                            .or_insert_with(|| vec![start..end]);
15674                    }
15675                }
15676                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15677            }
15678        };
15679
15680        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15681        let selections_prev = transaction_id_prev
15682            .and_then(|transaction_id_prev| {
15683                // default to selections as they were after the last edit, if we have them,
15684                // instead of how they are now.
15685                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15686                // will take you back to where you made the last edit, instead of staying where you scrolled
15687                self.selection_history
15688                    .transaction(transaction_id_prev)
15689                    .map(|t| t.0.clone())
15690            })
15691            .unwrap_or_else(|| {
15692                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15693                self.selections.disjoint_anchors()
15694            });
15695
15696        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15697        let format = project.update(cx, |project, cx| {
15698            project.format(buffers, target, true, trigger, cx)
15699        });
15700
15701        cx.spawn_in(window, async move |editor, cx| {
15702            let transaction = futures::select_biased! {
15703                transaction = format.log_err().fuse() => transaction,
15704                () = timeout => {
15705                    log::warn!("timed out waiting for formatting");
15706                    None
15707                }
15708            };
15709
15710            buffer
15711                .update(cx, |buffer, cx| {
15712                    if let Some(transaction) = transaction {
15713                        if !buffer.is_singleton() {
15714                            buffer.push_transaction(&transaction.0, cx);
15715                        }
15716                    }
15717                    cx.notify();
15718                })
15719                .ok();
15720
15721            if let Some(transaction_id_now) =
15722                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15723            {
15724                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15725                if has_new_transaction {
15726                    _ = editor.update(cx, |editor, _| {
15727                        editor
15728                            .selection_history
15729                            .insert_transaction(transaction_id_now, selections_prev);
15730                    });
15731                }
15732            }
15733
15734            Ok(())
15735        })
15736    }
15737
15738    fn organize_imports(
15739        &mut self,
15740        _: &OrganizeImports,
15741        window: &mut Window,
15742        cx: &mut Context<Self>,
15743    ) -> Option<Task<Result<()>>> {
15744        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15745        let project = match &self.project {
15746            Some(project) => project.clone(),
15747            None => return None,
15748        };
15749        Some(self.perform_code_action_kind(
15750            project,
15751            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15752            window,
15753            cx,
15754        ))
15755    }
15756
15757    fn perform_code_action_kind(
15758        &mut self,
15759        project: Entity<Project>,
15760        kind: CodeActionKind,
15761        window: &mut Window,
15762        cx: &mut Context<Self>,
15763    ) -> Task<Result<()>> {
15764        let buffer = self.buffer.clone();
15765        let buffers = buffer.read(cx).all_buffers();
15766        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15767        let apply_action = project.update(cx, |project, cx| {
15768            project.apply_code_action_kind(buffers, kind, true, cx)
15769        });
15770        cx.spawn_in(window, async move |_, cx| {
15771            let transaction = futures::select_biased! {
15772                () = timeout => {
15773                    log::warn!("timed out waiting for executing code action");
15774                    None
15775                }
15776                transaction = apply_action.log_err().fuse() => transaction,
15777            };
15778            buffer
15779                .update(cx, |buffer, cx| {
15780                    // check if we need this
15781                    if let Some(transaction) = transaction {
15782                        if !buffer.is_singleton() {
15783                            buffer.push_transaction(&transaction.0, cx);
15784                        }
15785                    }
15786                    cx.notify();
15787                })
15788                .ok();
15789            Ok(())
15790        })
15791    }
15792
15793    fn restart_language_server(
15794        &mut self,
15795        _: &RestartLanguageServer,
15796        _: &mut Window,
15797        cx: &mut Context<Self>,
15798    ) {
15799        if let Some(project) = self.project.clone() {
15800            self.buffer.update(cx, |multi_buffer, cx| {
15801                project.update(cx, |project, cx| {
15802                    project.restart_language_servers_for_buffers(
15803                        multi_buffer.all_buffers().into_iter().collect(),
15804                        cx,
15805                    );
15806                });
15807            })
15808        }
15809    }
15810
15811    fn stop_language_server(
15812        &mut self,
15813        _: &StopLanguageServer,
15814        _: &mut Window,
15815        cx: &mut Context<Self>,
15816    ) {
15817        if let Some(project) = self.project.clone() {
15818            self.buffer.update(cx, |multi_buffer, cx| {
15819                project.update(cx, |project, cx| {
15820                    project.stop_language_servers_for_buffers(
15821                        multi_buffer.all_buffers().into_iter().collect(),
15822                        cx,
15823                    );
15824                    cx.emit(project::Event::RefreshInlayHints);
15825                });
15826            });
15827        }
15828    }
15829
15830    fn cancel_language_server_work(
15831        workspace: &mut Workspace,
15832        _: &actions::CancelLanguageServerWork,
15833        _: &mut Window,
15834        cx: &mut Context<Workspace>,
15835    ) {
15836        let project = workspace.project();
15837        let buffers = workspace
15838            .active_item(cx)
15839            .and_then(|item| item.act_as::<Editor>(cx))
15840            .map_or(HashSet::default(), |editor| {
15841                editor.read(cx).buffer.read(cx).all_buffers()
15842            });
15843        project.update(cx, |project, cx| {
15844            project.cancel_language_server_work_for_buffers(buffers, cx);
15845        });
15846    }
15847
15848    fn show_character_palette(
15849        &mut self,
15850        _: &ShowCharacterPalette,
15851        window: &mut Window,
15852        _: &mut Context<Self>,
15853    ) {
15854        window.show_character_palette();
15855    }
15856
15857    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15858        if self.mode.is_minimap() {
15859            return;
15860        }
15861
15862        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15863            let buffer = self.buffer.read(cx).snapshot(cx);
15864            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15865            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15866            let is_valid = buffer
15867                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15868                .any(|entry| {
15869                    entry.diagnostic.is_primary
15870                        && !entry.range.is_empty()
15871                        && entry.range.start == primary_range_start
15872                        && entry.diagnostic.message == active_diagnostics.active_message
15873                });
15874
15875            if !is_valid {
15876                self.dismiss_diagnostics(cx);
15877            }
15878        }
15879    }
15880
15881    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15882        match &self.active_diagnostics {
15883            ActiveDiagnostic::Group(group) => Some(group),
15884            _ => None,
15885        }
15886    }
15887
15888    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15889        self.dismiss_diagnostics(cx);
15890        self.active_diagnostics = ActiveDiagnostic::All;
15891    }
15892
15893    fn activate_diagnostics(
15894        &mut self,
15895        buffer_id: BufferId,
15896        diagnostic: DiagnosticEntry<usize>,
15897        window: &mut Window,
15898        cx: &mut Context<Self>,
15899    ) {
15900        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15901            return;
15902        }
15903        self.dismiss_diagnostics(cx);
15904        let snapshot = self.snapshot(window, cx);
15905        let buffer = self.buffer.read(cx).snapshot(cx);
15906        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15907            return;
15908        };
15909
15910        let diagnostic_group = buffer
15911            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15912            .collect::<Vec<_>>();
15913
15914        let blocks =
15915            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15916
15917        let blocks = self.display_map.update(cx, |display_map, cx| {
15918            display_map.insert_blocks(blocks, cx).into_iter().collect()
15919        });
15920        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15921            active_range: buffer.anchor_before(diagnostic.range.start)
15922                ..buffer.anchor_after(diagnostic.range.end),
15923            active_message: diagnostic.diagnostic.message.clone(),
15924            group_id: diagnostic.diagnostic.group_id,
15925            blocks,
15926        });
15927        cx.notify();
15928    }
15929
15930    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15931        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15932            return;
15933        };
15934
15935        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15936        if let ActiveDiagnostic::Group(group) = prev {
15937            self.display_map.update(cx, |display_map, cx| {
15938                display_map.remove_blocks(group.blocks, cx);
15939            });
15940            cx.notify();
15941        }
15942    }
15943
15944    /// Disable inline diagnostics rendering for this editor.
15945    pub fn disable_inline_diagnostics(&mut self) {
15946        self.inline_diagnostics_enabled = false;
15947        self.inline_diagnostics_update = Task::ready(());
15948        self.inline_diagnostics.clear();
15949    }
15950
15951    pub fn diagnostics_enabled(&self) -> bool {
15952        self.mode.is_full()
15953    }
15954
15955    pub fn inline_diagnostics_enabled(&self) -> bool {
15956        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15957    }
15958
15959    pub fn show_inline_diagnostics(&self) -> bool {
15960        self.show_inline_diagnostics
15961    }
15962
15963    pub fn toggle_inline_diagnostics(
15964        &mut self,
15965        _: &ToggleInlineDiagnostics,
15966        window: &mut Window,
15967        cx: &mut Context<Editor>,
15968    ) {
15969        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15970        self.refresh_inline_diagnostics(false, window, cx);
15971    }
15972
15973    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15974        self.diagnostics_max_severity = severity;
15975        self.display_map.update(cx, |display_map, _| {
15976            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15977        });
15978    }
15979
15980    pub fn toggle_diagnostics(
15981        &mut self,
15982        _: &ToggleDiagnostics,
15983        window: &mut Window,
15984        cx: &mut Context<Editor>,
15985    ) {
15986        if !self.diagnostics_enabled() {
15987            return;
15988        }
15989
15990        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15991            EditorSettings::get_global(cx)
15992                .diagnostics_max_severity
15993                .filter(|severity| severity != &DiagnosticSeverity::Off)
15994                .unwrap_or(DiagnosticSeverity::Hint)
15995        } else {
15996            DiagnosticSeverity::Off
15997        };
15998        self.set_max_diagnostics_severity(new_severity, cx);
15999        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16000            self.active_diagnostics = ActiveDiagnostic::None;
16001            self.inline_diagnostics_update = Task::ready(());
16002            self.inline_diagnostics.clear();
16003        } else {
16004            self.refresh_inline_diagnostics(false, window, cx);
16005        }
16006
16007        cx.notify();
16008    }
16009
16010    pub fn toggle_minimap(
16011        &mut self,
16012        _: &ToggleMinimap,
16013        window: &mut Window,
16014        cx: &mut Context<Editor>,
16015    ) {
16016        if self.supports_minimap(cx) {
16017            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16018        }
16019    }
16020
16021    fn refresh_inline_diagnostics(
16022        &mut self,
16023        debounce: bool,
16024        window: &mut Window,
16025        cx: &mut Context<Self>,
16026    ) {
16027        let max_severity = ProjectSettings::get_global(cx)
16028            .diagnostics
16029            .inline
16030            .max_severity
16031            .unwrap_or(self.diagnostics_max_severity);
16032
16033        if !self.inline_diagnostics_enabled()
16034            || !self.show_inline_diagnostics
16035            || max_severity == DiagnosticSeverity::Off
16036        {
16037            self.inline_diagnostics_update = Task::ready(());
16038            self.inline_diagnostics.clear();
16039            return;
16040        }
16041
16042        let debounce_ms = ProjectSettings::get_global(cx)
16043            .diagnostics
16044            .inline
16045            .update_debounce_ms;
16046        let debounce = if debounce && debounce_ms > 0 {
16047            Some(Duration::from_millis(debounce_ms))
16048        } else {
16049            None
16050        };
16051        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16052            if let Some(debounce) = debounce {
16053                cx.background_executor().timer(debounce).await;
16054            }
16055            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16056                editor
16057                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16058                    .ok()
16059            }) else {
16060                return;
16061            };
16062
16063            let new_inline_diagnostics = cx
16064                .background_spawn(async move {
16065                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16066                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16067                        let message = diagnostic_entry
16068                            .diagnostic
16069                            .message
16070                            .split_once('\n')
16071                            .map(|(line, _)| line)
16072                            .map(SharedString::new)
16073                            .unwrap_or_else(|| {
16074                                SharedString::from(diagnostic_entry.diagnostic.message)
16075                            });
16076                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16077                        let (Ok(i) | Err(i)) = inline_diagnostics
16078                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16079                        inline_diagnostics.insert(
16080                            i,
16081                            (
16082                                start_anchor,
16083                                InlineDiagnostic {
16084                                    message,
16085                                    group_id: diagnostic_entry.diagnostic.group_id,
16086                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16087                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16088                                    severity: diagnostic_entry.diagnostic.severity,
16089                                },
16090                            ),
16091                        );
16092                    }
16093                    inline_diagnostics
16094                })
16095                .await;
16096
16097            editor
16098                .update(cx, |editor, cx| {
16099                    editor.inline_diagnostics = new_inline_diagnostics;
16100                    cx.notify();
16101                })
16102                .ok();
16103        });
16104    }
16105
16106    fn pull_diagnostics(
16107        &mut self,
16108        buffer_id: Option<BufferId>,
16109        window: &Window,
16110        cx: &mut Context<Self>,
16111    ) -> Option<()> {
16112        if !self.mode().is_full() {
16113            return None;
16114        }
16115        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16116            .diagnostics
16117            .lsp_pull_diagnostics;
16118        if !pull_diagnostics_settings.enabled {
16119            return None;
16120        }
16121        let project = self.project.as_ref()?.downgrade();
16122        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16123        let mut buffers = self.buffer.read(cx).all_buffers();
16124        if let Some(buffer_id) = buffer_id {
16125            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16126        }
16127
16128        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16129            cx.background_executor().timer(debounce).await;
16130
16131            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16132                buffers
16133                    .into_iter()
16134                    .flat_map(|buffer| {
16135                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16136                    })
16137                    .collect::<FuturesUnordered<_>>()
16138            }) else {
16139                return;
16140            };
16141
16142            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16143                match pull_task {
16144                    Ok(()) => {
16145                        if editor
16146                            .update_in(cx, |editor, window, cx| {
16147                                editor.update_diagnostics_state(window, cx);
16148                            })
16149                            .is_err()
16150                        {
16151                            return;
16152                        }
16153                    }
16154                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16155                }
16156            }
16157        });
16158
16159        Some(())
16160    }
16161
16162    pub fn set_selections_from_remote(
16163        &mut self,
16164        selections: Vec<Selection<Anchor>>,
16165        pending_selection: Option<Selection<Anchor>>,
16166        window: &mut Window,
16167        cx: &mut Context<Self>,
16168    ) {
16169        let old_cursor_position = self.selections.newest_anchor().head();
16170        self.selections.change_with(cx, |s| {
16171            s.select_anchors(selections);
16172            if let Some(pending_selection) = pending_selection {
16173                s.set_pending(pending_selection, SelectMode::Character);
16174            } else {
16175                s.clear_pending();
16176            }
16177        });
16178        self.selections_did_change(false, &old_cursor_position, true, window, cx);
16179    }
16180
16181    pub fn transact(
16182        &mut self,
16183        window: &mut Window,
16184        cx: &mut Context<Self>,
16185        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16186    ) -> Option<TransactionId> {
16187        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16188            this.start_transaction_at(Instant::now(), window, cx);
16189            update(this, window, cx);
16190            this.end_transaction_at(Instant::now(), cx)
16191        })
16192    }
16193
16194    pub fn start_transaction_at(
16195        &mut self,
16196        now: Instant,
16197        window: &mut Window,
16198        cx: &mut Context<Self>,
16199    ) {
16200        self.end_selection(window, cx);
16201        if let Some(tx_id) = self
16202            .buffer
16203            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16204        {
16205            self.selection_history
16206                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16207            cx.emit(EditorEvent::TransactionBegun {
16208                transaction_id: tx_id,
16209            })
16210        }
16211    }
16212
16213    pub fn end_transaction_at(
16214        &mut self,
16215        now: Instant,
16216        cx: &mut Context<Self>,
16217    ) -> Option<TransactionId> {
16218        if let Some(transaction_id) = self
16219            .buffer
16220            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16221        {
16222            if let Some((_, end_selections)) =
16223                self.selection_history.transaction_mut(transaction_id)
16224            {
16225                *end_selections = Some(self.selections.disjoint_anchors());
16226            } else {
16227                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16228            }
16229
16230            cx.emit(EditorEvent::Edited { transaction_id });
16231            Some(transaction_id)
16232        } else {
16233            None
16234        }
16235    }
16236
16237    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16238        if self.selection_mark_mode {
16239            self.change_selections(None, window, cx, |s| {
16240                s.move_with(|_, sel| {
16241                    sel.collapse_to(sel.head(), SelectionGoal::None);
16242                });
16243            })
16244        }
16245        self.selection_mark_mode = true;
16246        cx.notify();
16247    }
16248
16249    pub fn swap_selection_ends(
16250        &mut self,
16251        _: &actions::SwapSelectionEnds,
16252        window: &mut Window,
16253        cx: &mut Context<Self>,
16254    ) {
16255        self.change_selections(None, window, cx, |s| {
16256            s.move_with(|_, sel| {
16257                if sel.start != sel.end {
16258                    sel.reversed = !sel.reversed
16259                }
16260            });
16261        });
16262        self.request_autoscroll(Autoscroll::newest(), cx);
16263        cx.notify();
16264    }
16265
16266    pub fn toggle_fold(
16267        &mut self,
16268        _: &actions::ToggleFold,
16269        window: &mut Window,
16270        cx: &mut Context<Self>,
16271    ) {
16272        if self.is_singleton(cx) {
16273            let selection = self.selections.newest::<Point>(cx);
16274
16275            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16276            let range = if selection.is_empty() {
16277                let point = selection.head().to_display_point(&display_map);
16278                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16279                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16280                    .to_point(&display_map);
16281                start..end
16282            } else {
16283                selection.range()
16284            };
16285            if display_map.folds_in_range(range).next().is_some() {
16286                self.unfold_lines(&Default::default(), window, cx)
16287            } else {
16288                self.fold(&Default::default(), window, cx)
16289            }
16290        } else {
16291            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16292            let buffer_ids: HashSet<_> = self
16293                .selections
16294                .disjoint_anchor_ranges()
16295                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16296                .collect();
16297
16298            let should_unfold = buffer_ids
16299                .iter()
16300                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16301
16302            for buffer_id in buffer_ids {
16303                if should_unfold {
16304                    self.unfold_buffer(buffer_id, cx);
16305                } else {
16306                    self.fold_buffer(buffer_id, cx);
16307                }
16308            }
16309        }
16310    }
16311
16312    pub fn toggle_fold_recursive(
16313        &mut self,
16314        _: &actions::ToggleFoldRecursive,
16315        window: &mut Window,
16316        cx: &mut Context<Self>,
16317    ) {
16318        let selection = self.selections.newest::<Point>(cx);
16319
16320        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16321        let range = if selection.is_empty() {
16322            let point = selection.head().to_display_point(&display_map);
16323            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16324            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16325                .to_point(&display_map);
16326            start..end
16327        } else {
16328            selection.range()
16329        };
16330        if display_map.folds_in_range(range).next().is_some() {
16331            self.unfold_recursive(&Default::default(), window, cx)
16332        } else {
16333            self.fold_recursive(&Default::default(), window, cx)
16334        }
16335    }
16336
16337    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16338        if self.is_singleton(cx) {
16339            let mut to_fold = Vec::new();
16340            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16341            let selections = self.selections.all_adjusted(cx);
16342
16343            for selection in selections {
16344                let range = selection.range().sorted();
16345                let buffer_start_row = range.start.row;
16346
16347                if range.start.row != range.end.row {
16348                    let mut found = false;
16349                    let mut row = range.start.row;
16350                    while row <= range.end.row {
16351                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16352                        {
16353                            found = true;
16354                            row = crease.range().end.row + 1;
16355                            to_fold.push(crease);
16356                        } else {
16357                            row += 1
16358                        }
16359                    }
16360                    if found {
16361                        continue;
16362                    }
16363                }
16364
16365                for row in (0..=range.start.row).rev() {
16366                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16367                        if crease.range().end.row >= buffer_start_row {
16368                            to_fold.push(crease);
16369                            if row <= range.start.row {
16370                                break;
16371                            }
16372                        }
16373                    }
16374                }
16375            }
16376
16377            self.fold_creases(to_fold, true, window, cx);
16378        } else {
16379            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16380            let buffer_ids = self
16381                .selections
16382                .disjoint_anchor_ranges()
16383                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16384                .collect::<HashSet<_>>();
16385            for buffer_id in buffer_ids {
16386                self.fold_buffer(buffer_id, cx);
16387            }
16388        }
16389    }
16390
16391    fn fold_at_level(
16392        &mut self,
16393        fold_at: &FoldAtLevel,
16394        window: &mut Window,
16395        cx: &mut Context<Self>,
16396    ) {
16397        if !self.buffer.read(cx).is_singleton() {
16398            return;
16399        }
16400
16401        let fold_at_level = fold_at.0;
16402        let snapshot = self.buffer.read(cx).snapshot(cx);
16403        let mut to_fold = Vec::new();
16404        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16405
16406        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16407            while start_row < end_row {
16408                match self
16409                    .snapshot(window, cx)
16410                    .crease_for_buffer_row(MultiBufferRow(start_row))
16411                {
16412                    Some(crease) => {
16413                        let nested_start_row = crease.range().start.row + 1;
16414                        let nested_end_row = crease.range().end.row;
16415
16416                        if current_level < fold_at_level {
16417                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16418                        } else if current_level == fold_at_level {
16419                            to_fold.push(crease);
16420                        }
16421
16422                        start_row = nested_end_row + 1;
16423                    }
16424                    None => start_row += 1,
16425                }
16426            }
16427        }
16428
16429        self.fold_creases(to_fold, true, window, cx);
16430    }
16431
16432    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16433        if self.buffer.read(cx).is_singleton() {
16434            let mut fold_ranges = Vec::new();
16435            let snapshot = self.buffer.read(cx).snapshot(cx);
16436
16437            for row in 0..snapshot.max_row().0 {
16438                if let Some(foldable_range) = self
16439                    .snapshot(window, cx)
16440                    .crease_for_buffer_row(MultiBufferRow(row))
16441                {
16442                    fold_ranges.push(foldable_range);
16443                }
16444            }
16445
16446            self.fold_creases(fold_ranges, true, window, cx);
16447        } else {
16448            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16449                editor
16450                    .update_in(cx, |editor, _, cx| {
16451                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16452                            editor.fold_buffer(buffer_id, cx);
16453                        }
16454                    })
16455                    .ok();
16456            });
16457        }
16458    }
16459
16460    pub fn fold_function_bodies(
16461        &mut self,
16462        _: &actions::FoldFunctionBodies,
16463        window: &mut Window,
16464        cx: &mut Context<Self>,
16465    ) {
16466        let snapshot = self.buffer.read(cx).snapshot(cx);
16467
16468        let ranges = snapshot
16469            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16470            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16471            .collect::<Vec<_>>();
16472
16473        let creases = ranges
16474            .into_iter()
16475            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16476            .collect();
16477
16478        self.fold_creases(creases, true, window, cx);
16479    }
16480
16481    pub fn fold_recursive(
16482        &mut self,
16483        _: &actions::FoldRecursive,
16484        window: &mut Window,
16485        cx: &mut Context<Self>,
16486    ) {
16487        let mut to_fold = Vec::new();
16488        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16489        let selections = self.selections.all_adjusted(cx);
16490
16491        for selection in selections {
16492            let range = selection.range().sorted();
16493            let buffer_start_row = range.start.row;
16494
16495            if range.start.row != range.end.row {
16496                let mut found = false;
16497                for row in range.start.row..=range.end.row {
16498                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16499                        found = true;
16500                        to_fold.push(crease);
16501                    }
16502                }
16503                if found {
16504                    continue;
16505                }
16506            }
16507
16508            for row in (0..=range.start.row).rev() {
16509                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16510                    if crease.range().end.row >= buffer_start_row {
16511                        to_fold.push(crease);
16512                    } else {
16513                        break;
16514                    }
16515                }
16516            }
16517        }
16518
16519        self.fold_creases(to_fold, true, window, cx);
16520    }
16521
16522    pub fn fold_at(
16523        &mut self,
16524        buffer_row: MultiBufferRow,
16525        window: &mut Window,
16526        cx: &mut Context<Self>,
16527    ) {
16528        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16529
16530        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16531            let autoscroll = self
16532                .selections
16533                .all::<Point>(cx)
16534                .iter()
16535                .any(|selection| crease.range().overlaps(&selection.range()));
16536
16537            self.fold_creases(vec![crease], autoscroll, window, cx);
16538        }
16539    }
16540
16541    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16542        if self.is_singleton(cx) {
16543            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16544            let buffer = &display_map.buffer_snapshot;
16545            let selections = self.selections.all::<Point>(cx);
16546            let ranges = selections
16547                .iter()
16548                .map(|s| {
16549                    let range = s.display_range(&display_map).sorted();
16550                    let mut start = range.start.to_point(&display_map);
16551                    let mut end = range.end.to_point(&display_map);
16552                    start.column = 0;
16553                    end.column = buffer.line_len(MultiBufferRow(end.row));
16554                    start..end
16555                })
16556                .collect::<Vec<_>>();
16557
16558            self.unfold_ranges(&ranges, true, true, cx);
16559        } else {
16560            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16561            let buffer_ids = self
16562                .selections
16563                .disjoint_anchor_ranges()
16564                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16565                .collect::<HashSet<_>>();
16566            for buffer_id in buffer_ids {
16567                self.unfold_buffer(buffer_id, cx);
16568            }
16569        }
16570    }
16571
16572    pub fn unfold_recursive(
16573        &mut self,
16574        _: &UnfoldRecursive,
16575        _window: &mut Window,
16576        cx: &mut Context<Self>,
16577    ) {
16578        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16579        let selections = self.selections.all::<Point>(cx);
16580        let ranges = selections
16581            .iter()
16582            .map(|s| {
16583                let mut range = s.display_range(&display_map).sorted();
16584                *range.start.column_mut() = 0;
16585                *range.end.column_mut() = display_map.line_len(range.end.row());
16586                let start = range.start.to_point(&display_map);
16587                let end = range.end.to_point(&display_map);
16588                start..end
16589            })
16590            .collect::<Vec<_>>();
16591
16592        self.unfold_ranges(&ranges, true, true, cx);
16593    }
16594
16595    pub fn unfold_at(
16596        &mut self,
16597        buffer_row: MultiBufferRow,
16598        _window: &mut Window,
16599        cx: &mut Context<Self>,
16600    ) {
16601        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16602
16603        let intersection_range = Point::new(buffer_row.0, 0)
16604            ..Point::new(
16605                buffer_row.0,
16606                display_map.buffer_snapshot.line_len(buffer_row),
16607            );
16608
16609        let autoscroll = self
16610            .selections
16611            .all::<Point>(cx)
16612            .iter()
16613            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16614
16615        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16616    }
16617
16618    pub fn unfold_all(
16619        &mut self,
16620        _: &actions::UnfoldAll,
16621        _window: &mut Window,
16622        cx: &mut Context<Self>,
16623    ) {
16624        if self.buffer.read(cx).is_singleton() {
16625            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16626            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16627        } else {
16628            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16629                editor
16630                    .update(cx, |editor, cx| {
16631                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16632                            editor.unfold_buffer(buffer_id, cx);
16633                        }
16634                    })
16635                    .ok();
16636            });
16637        }
16638    }
16639
16640    pub fn fold_selected_ranges(
16641        &mut self,
16642        _: &FoldSelectedRanges,
16643        window: &mut Window,
16644        cx: &mut Context<Self>,
16645    ) {
16646        let selections = self.selections.all_adjusted(cx);
16647        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16648        let ranges = selections
16649            .into_iter()
16650            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16651            .collect::<Vec<_>>();
16652        self.fold_creases(ranges, true, window, cx);
16653    }
16654
16655    pub fn fold_ranges<T: ToOffset + Clone>(
16656        &mut self,
16657        ranges: Vec<Range<T>>,
16658        auto_scroll: bool,
16659        window: &mut Window,
16660        cx: &mut Context<Self>,
16661    ) {
16662        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16663        let ranges = ranges
16664            .into_iter()
16665            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16666            .collect::<Vec<_>>();
16667        self.fold_creases(ranges, auto_scroll, window, cx);
16668    }
16669
16670    pub fn fold_creases<T: ToOffset + Clone>(
16671        &mut self,
16672        creases: Vec<Crease<T>>,
16673        auto_scroll: bool,
16674        _window: &mut Window,
16675        cx: &mut Context<Self>,
16676    ) {
16677        if creases.is_empty() {
16678            return;
16679        }
16680
16681        let mut buffers_affected = HashSet::default();
16682        let multi_buffer = self.buffer().read(cx);
16683        for crease in &creases {
16684            if let Some((_, buffer, _)) =
16685                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16686            {
16687                buffers_affected.insert(buffer.read(cx).remote_id());
16688            };
16689        }
16690
16691        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16692
16693        if auto_scroll {
16694            self.request_autoscroll(Autoscroll::fit(), cx);
16695        }
16696
16697        cx.notify();
16698
16699        self.scrollbar_marker_state.dirty = true;
16700        self.folds_did_change(cx);
16701    }
16702
16703    /// Removes any folds whose ranges intersect any of the given ranges.
16704    pub fn unfold_ranges<T: ToOffset + Clone>(
16705        &mut self,
16706        ranges: &[Range<T>],
16707        inclusive: bool,
16708        auto_scroll: bool,
16709        cx: &mut Context<Self>,
16710    ) {
16711        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16712            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16713        });
16714        self.folds_did_change(cx);
16715    }
16716
16717    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16718        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16719            return;
16720        }
16721        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16722        self.display_map.update(cx, |display_map, cx| {
16723            display_map.fold_buffers([buffer_id], cx)
16724        });
16725        cx.emit(EditorEvent::BufferFoldToggled {
16726            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16727            folded: true,
16728        });
16729        cx.notify();
16730    }
16731
16732    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16733        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16734            return;
16735        }
16736        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16737        self.display_map.update(cx, |display_map, cx| {
16738            display_map.unfold_buffers([buffer_id], cx);
16739        });
16740        cx.emit(EditorEvent::BufferFoldToggled {
16741            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16742            folded: false,
16743        });
16744        cx.notify();
16745    }
16746
16747    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16748        self.display_map.read(cx).is_buffer_folded(buffer)
16749    }
16750
16751    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16752        self.display_map.read(cx).folded_buffers()
16753    }
16754
16755    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16756        self.display_map.update(cx, |display_map, cx| {
16757            display_map.disable_header_for_buffer(buffer_id, cx);
16758        });
16759        cx.notify();
16760    }
16761
16762    /// Removes any folds with the given ranges.
16763    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16764        &mut self,
16765        ranges: &[Range<T>],
16766        type_id: TypeId,
16767        auto_scroll: bool,
16768        cx: &mut Context<Self>,
16769    ) {
16770        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16771            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16772        });
16773        self.folds_did_change(cx);
16774    }
16775
16776    fn remove_folds_with<T: ToOffset + Clone>(
16777        &mut self,
16778        ranges: &[Range<T>],
16779        auto_scroll: bool,
16780        cx: &mut Context<Self>,
16781        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16782    ) {
16783        if ranges.is_empty() {
16784            return;
16785        }
16786
16787        let mut buffers_affected = HashSet::default();
16788        let multi_buffer = self.buffer().read(cx);
16789        for range in ranges {
16790            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16791                buffers_affected.insert(buffer.read(cx).remote_id());
16792            };
16793        }
16794
16795        self.display_map.update(cx, update);
16796
16797        if auto_scroll {
16798            self.request_autoscroll(Autoscroll::fit(), cx);
16799        }
16800
16801        cx.notify();
16802        self.scrollbar_marker_state.dirty = true;
16803        self.active_indent_guides_state.dirty = true;
16804    }
16805
16806    pub fn update_fold_widths(
16807        &mut self,
16808        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16809        cx: &mut Context<Self>,
16810    ) -> bool {
16811        self.display_map
16812            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16813    }
16814
16815    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16816        self.display_map.read(cx).fold_placeholder.clone()
16817    }
16818
16819    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16820        self.buffer.update(cx, |buffer, cx| {
16821            buffer.set_all_diff_hunks_expanded(cx);
16822        });
16823    }
16824
16825    pub fn expand_all_diff_hunks(
16826        &mut self,
16827        _: &ExpandAllDiffHunks,
16828        _window: &mut Window,
16829        cx: &mut Context<Self>,
16830    ) {
16831        self.buffer.update(cx, |buffer, cx| {
16832            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16833        });
16834    }
16835
16836    pub fn toggle_selected_diff_hunks(
16837        &mut self,
16838        _: &ToggleSelectedDiffHunks,
16839        _window: &mut Window,
16840        cx: &mut Context<Self>,
16841    ) {
16842        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16843        self.toggle_diff_hunks_in_ranges(ranges, cx);
16844    }
16845
16846    pub fn diff_hunks_in_ranges<'a>(
16847        &'a self,
16848        ranges: &'a [Range<Anchor>],
16849        buffer: &'a MultiBufferSnapshot,
16850    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16851        ranges.iter().flat_map(move |range| {
16852            let end_excerpt_id = range.end.excerpt_id;
16853            let range = range.to_point(buffer);
16854            let mut peek_end = range.end;
16855            if range.end.row < buffer.max_row().0 {
16856                peek_end = Point::new(range.end.row + 1, 0);
16857            }
16858            buffer
16859                .diff_hunks_in_range(range.start..peek_end)
16860                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16861        })
16862    }
16863
16864    pub fn has_stageable_diff_hunks_in_ranges(
16865        &self,
16866        ranges: &[Range<Anchor>],
16867        snapshot: &MultiBufferSnapshot,
16868    ) -> bool {
16869        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16870        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16871    }
16872
16873    pub fn toggle_staged_selected_diff_hunks(
16874        &mut self,
16875        _: &::git::ToggleStaged,
16876        _: &mut Window,
16877        cx: &mut Context<Self>,
16878    ) {
16879        let snapshot = self.buffer.read(cx).snapshot(cx);
16880        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16881        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16882        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16883    }
16884
16885    pub fn set_render_diff_hunk_controls(
16886        &mut self,
16887        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16888        cx: &mut Context<Self>,
16889    ) {
16890        self.render_diff_hunk_controls = render_diff_hunk_controls;
16891        cx.notify();
16892    }
16893
16894    pub fn stage_and_next(
16895        &mut self,
16896        _: &::git::StageAndNext,
16897        window: &mut Window,
16898        cx: &mut Context<Self>,
16899    ) {
16900        self.do_stage_or_unstage_and_next(true, window, cx);
16901    }
16902
16903    pub fn unstage_and_next(
16904        &mut self,
16905        _: &::git::UnstageAndNext,
16906        window: &mut Window,
16907        cx: &mut Context<Self>,
16908    ) {
16909        self.do_stage_or_unstage_and_next(false, window, cx);
16910    }
16911
16912    pub fn stage_or_unstage_diff_hunks(
16913        &mut self,
16914        stage: bool,
16915        ranges: Vec<Range<Anchor>>,
16916        cx: &mut Context<Self>,
16917    ) {
16918        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16919        cx.spawn(async move |this, cx| {
16920            task.await?;
16921            this.update(cx, |this, cx| {
16922                let snapshot = this.buffer.read(cx).snapshot(cx);
16923                let chunk_by = this
16924                    .diff_hunks_in_ranges(&ranges, &snapshot)
16925                    .chunk_by(|hunk| hunk.buffer_id);
16926                for (buffer_id, hunks) in &chunk_by {
16927                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16928                }
16929            })
16930        })
16931        .detach_and_log_err(cx);
16932    }
16933
16934    fn save_buffers_for_ranges_if_needed(
16935        &mut self,
16936        ranges: &[Range<Anchor>],
16937        cx: &mut Context<Editor>,
16938    ) -> Task<Result<()>> {
16939        let multibuffer = self.buffer.read(cx);
16940        let snapshot = multibuffer.read(cx);
16941        let buffer_ids: HashSet<_> = ranges
16942            .iter()
16943            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16944            .collect();
16945        drop(snapshot);
16946
16947        let mut buffers = HashSet::default();
16948        for buffer_id in buffer_ids {
16949            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16950                let buffer = buffer_entity.read(cx);
16951                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16952                {
16953                    buffers.insert(buffer_entity);
16954                }
16955            }
16956        }
16957
16958        if let Some(project) = &self.project {
16959            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16960        } else {
16961            Task::ready(Ok(()))
16962        }
16963    }
16964
16965    fn do_stage_or_unstage_and_next(
16966        &mut self,
16967        stage: bool,
16968        window: &mut Window,
16969        cx: &mut Context<Self>,
16970    ) {
16971        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16972
16973        if ranges.iter().any(|range| range.start != range.end) {
16974            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16975            return;
16976        }
16977
16978        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16979        let snapshot = self.snapshot(window, cx);
16980        let position = self.selections.newest::<Point>(cx).head();
16981        let mut row = snapshot
16982            .buffer_snapshot
16983            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16984            .find(|hunk| hunk.row_range.start.0 > position.row)
16985            .map(|hunk| hunk.row_range.start);
16986
16987        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16988        // Outside of the project diff editor, wrap around to the beginning.
16989        if !all_diff_hunks_expanded {
16990            row = row.or_else(|| {
16991                snapshot
16992                    .buffer_snapshot
16993                    .diff_hunks_in_range(Point::zero()..position)
16994                    .find(|hunk| hunk.row_range.end.0 < position.row)
16995                    .map(|hunk| hunk.row_range.start)
16996            });
16997        }
16998
16999        if let Some(row) = row {
17000            let destination = Point::new(row.0, 0);
17001            let autoscroll = Autoscroll::center();
17002
17003            self.unfold_ranges(&[destination..destination], false, false, cx);
17004            self.change_selections(Some(autoscroll), window, cx, |s| {
17005                s.select_ranges([destination..destination]);
17006            });
17007        }
17008    }
17009
17010    fn do_stage_or_unstage(
17011        &self,
17012        stage: bool,
17013        buffer_id: BufferId,
17014        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17015        cx: &mut App,
17016    ) -> Option<()> {
17017        let project = self.project.as_ref()?;
17018        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17019        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17020        let buffer_snapshot = buffer.read(cx).snapshot();
17021        let file_exists = buffer_snapshot
17022            .file()
17023            .is_some_and(|file| file.disk_state().exists());
17024        diff.update(cx, |diff, cx| {
17025            diff.stage_or_unstage_hunks(
17026                stage,
17027                &hunks
17028                    .map(|hunk| buffer_diff::DiffHunk {
17029                        buffer_range: hunk.buffer_range,
17030                        diff_base_byte_range: hunk.diff_base_byte_range,
17031                        secondary_status: hunk.secondary_status,
17032                        range: Point::zero()..Point::zero(), // unused
17033                    })
17034                    .collect::<Vec<_>>(),
17035                &buffer_snapshot,
17036                file_exists,
17037                cx,
17038            )
17039        });
17040        None
17041    }
17042
17043    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17044        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17045        self.buffer
17046            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17047    }
17048
17049    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17050        self.buffer.update(cx, |buffer, cx| {
17051            let ranges = vec![Anchor::min()..Anchor::max()];
17052            if !buffer.all_diff_hunks_expanded()
17053                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17054            {
17055                buffer.collapse_diff_hunks(ranges, cx);
17056                true
17057            } else {
17058                false
17059            }
17060        })
17061    }
17062
17063    fn toggle_diff_hunks_in_ranges(
17064        &mut self,
17065        ranges: Vec<Range<Anchor>>,
17066        cx: &mut Context<Editor>,
17067    ) {
17068        self.buffer.update(cx, |buffer, cx| {
17069            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17070            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17071        })
17072    }
17073
17074    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17075        self.buffer.update(cx, |buffer, cx| {
17076            let snapshot = buffer.snapshot(cx);
17077            let excerpt_id = range.end.excerpt_id;
17078            let point_range = range.to_point(&snapshot);
17079            let expand = !buffer.single_hunk_is_expanded(range, cx);
17080            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17081        })
17082    }
17083
17084    pub(crate) fn apply_all_diff_hunks(
17085        &mut self,
17086        _: &ApplyAllDiffHunks,
17087        window: &mut Window,
17088        cx: &mut Context<Self>,
17089    ) {
17090        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17091
17092        let buffers = self.buffer.read(cx).all_buffers();
17093        for branch_buffer in buffers {
17094            branch_buffer.update(cx, |branch_buffer, cx| {
17095                branch_buffer.merge_into_base(Vec::new(), cx);
17096            });
17097        }
17098
17099        if let Some(project) = self.project.clone() {
17100            self.save(true, project, window, cx).detach_and_log_err(cx);
17101        }
17102    }
17103
17104    pub(crate) fn apply_selected_diff_hunks(
17105        &mut self,
17106        _: &ApplyDiffHunk,
17107        window: &mut Window,
17108        cx: &mut Context<Self>,
17109    ) {
17110        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17111        let snapshot = self.snapshot(window, cx);
17112        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17113        let mut ranges_by_buffer = HashMap::default();
17114        self.transact(window, cx, |editor, _window, cx| {
17115            for hunk in hunks {
17116                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17117                    ranges_by_buffer
17118                        .entry(buffer.clone())
17119                        .or_insert_with(Vec::new)
17120                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17121                }
17122            }
17123
17124            for (buffer, ranges) in ranges_by_buffer {
17125                buffer.update(cx, |buffer, cx| {
17126                    buffer.merge_into_base(ranges, cx);
17127                });
17128            }
17129        });
17130
17131        if let Some(project) = self.project.clone() {
17132            self.save(true, project, window, cx).detach_and_log_err(cx);
17133        }
17134    }
17135
17136    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17137        if hovered != self.gutter_hovered {
17138            self.gutter_hovered = hovered;
17139            cx.notify();
17140        }
17141    }
17142
17143    pub fn insert_blocks(
17144        &mut self,
17145        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17146        autoscroll: Option<Autoscroll>,
17147        cx: &mut Context<Self>,
17148    ) -> Vec<CustomBlockId> {
17149        let blocks = self
17150            .display_map
17151            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17152        if let Some(autoscroll) = autoscroll {
17153            self.request_autoscroll(autoscroll, cx);
17154        }
17155        cx.notify();
17156        blocks
17157    }
17158
17159    pub fn resize_blocks(
17160        &mut self,
17161        heights: HashMap<CustomBlockId, u32>,
17162        autoscroll: Option<Autoscroll>,
17163        cx: &mut Context<Self>,
17164    ) {
17165        self.display_map
17166            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17167        if let Some(autoscroll) = autoscroll {
17168            self.request_autoscroll(autoscroll, cx);
17169        }
17170        cx.notify();
17171    }
17172
17173    pub fn replace_blocks(
17174        &mut self,
17175        renderers: HashMap<CustomBlockId, RenderBlock>,
17176        autoscroll: Option<Autoscroll>,
17177        cx: &mut Context<Self>,
17178    ) {
17179        self.display_map
17180            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17181        if let Some(autoscroll) = autoscroll {
17182            self.request_autoscroll(autoscroll, cx);
17183        }
17184        cx.notify();
17185    }
17186
17187    pub fn remove_blocks(
17188        &mut self,
17189        block_ids: HashSet<CustomBlockId>,
17190        autoscroll: Option<Autoscroll>,
17191        cx: &mut Context<Self>,
17192    ) {
17193        self.display_map.update(cx, |display_map, cx| {
17194            display_map.remove_blocks(block_ids, cx)
17195        });
17196        if let Some(autoscroll) = autoscroll {
17197            self.request_autoscroll(autoscroll, cx);
17198        }
17199        cx.notify();
17200    }
17201
17202    pub fn row_for_block(
17203        &self,
17204        block_id: CustomBlockId,
17205        cx: &mut Context<Self>,
17206    ) -> Option<DisplayRow> {
17207        self.display_map
17208            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17209    }
17210
17211    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17212        self.focused_block = Some(focused_block);
17213    }
17214
17215    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17216        self.focused_block.take()
17217    }
17218
17219    pub fn insert_creases(
17220        &mut self,
17221        creases: impl IntoIterator<Item = Crease<Anchor>>,
17222        cx: &mut Context<Self>,
17223    ) -> Vec<CreaseId> {
17224        self.display_map
17225            .update(cx, |map, cx| map.insert_creases(creases, cx))
17226    }
17227
17228    pub fn remove_creases(
17229        &mut self,
17230        ids: impl IntoIterator<Item = CreaseId>,
17231        cx: &mut Context<Self>,
17232    ) -> Vec<(CreaseId, Range<Anchor>)> {
17233        self.display_map
17234            .update(cx, |map, cx| map.remove_creases(ids, cx))
17235    }
17236
17237    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17238        self.display_map
17239            .update(cx, |map, cx| map.snapshot(cx))
17240            .longest_row()
17241    }
17242
17243    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17244        self.display_map
17245            .update(cx, |map, cx| map.snapshot(cx))
17246            .max_point()
17247    }
17248
17249    pub fn text(&self, cx: &App) -> String {
17250        self.buffer.read(cx).read(cx).text()
17251    }
17252
17253    pub fn is_empty(&self, cx: &App) -> bool {
17254        self.buffer.read(cx).read(cx).is_empty()
17255    }
17256
17257    pub fn text_option(&self, cx: &App) -> Option<String> {
17258        let text = self.text(cx);
17259        let text = text.trim();
17260
17261        if text.is_empty() {
17262            return None;
17263        }
17264
17265        Some(text.to_string())
17266    }
17267
17268    pub fn set_text(
17269        &mut self,
17270        text: impl Into<Arc<str>>,
17271        window: &mut Window,
17272        cx: &mut Context<Self>,
17273    ) {
17274        self.transact(window, cx, |this, _, cx| {
17275            this.buffer
17276                .read(cx)
17277                .as_singleton()
17278                .expect("you can only call set_text on editors for singleton buffers")
17279                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17280        });
17281    }
17282
17283    pub fn display_text(&self, cx: &mut App) -> String {
17284        self.display_map
17285            .update(cx, |map, cx| map.snapshot(cx))
17286            .text()
17287    }
17288
17289    fn create_minimap(
17290        &self,
17291        minimap_settings: MinimapSettings,
17292        window: &mut Window,
17293        cx: &mut Context<Self>,
17294    ) -> Option<Entity<Self>> {
17295        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17296            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17297    }
17298
17299    fn initialize_new_minimap(
17300        &self,
17301        minimap_settings: MinimapSettings,
17302        window: &mut Window,
17303        cx: &mut Context<Self>,
17304    ) -> Entity<Self> {
17305        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17306
17307        let mut minimap = Editor::new_internal(
17308            EditorMode::Minimap {
17309                parent: cx.weak_entity(),
17310            },
17311            self.buffer.clone(),
17312            self.project.clone(),
17313            Some(self.display_map.clone()),
17314            window,
17315            cx,
17316        );
17317        minimap.scroll_manager.clone_state(&self.scroll_manager);
17318        minimap.set_text_style_refinement(TextStyleRefinement {
17319            font_size: Some(MINIMAP_FONT_SIZE),
17320            font_weight: Some(MINIMAP_FONT_WEIGHT),
17321            ..Default::default()
17322        });
17323        minimap.update_minimap_configuration(minimap_settings, cx);
17324        cx.new(|_| minimap)
17325    }
17326
17327    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17328        let current_line_highlight = minimap_settings
17329            .current_line_highlight
17330            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17331        self.set_current_line_highlight(Some(current_line_highlight));
17332    }
17333
17334    pub fn minimap(&self) -> Option<&Entity<Self>> {
17335        self.minimap
17336            .as_ref()
17337            .filter(|_| self.minimap_visibility.visible())
17338    }
17339
17340    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17341        let mut wrap_guides = smallvec![];
17342
17343        if self.show_wrap_guides == Some(false) {
17344            return wrap_guides;
17345        }
17346
17347        let settings = self.buffer.read(cx).language_settings(cx);
17348        if settings.show_wrap_guides {
17349            match self.soft_wrap_mode(cx) {
17350                SoftWrap::Column(soft_wrap) => {
17351                    wrap_guides.push((soft_wrap as usize, true));
17352                }
17353                SoftWrap::Bounded(soft_wrap) => {
17354                    wrap_guides.push((soft_wrap as usize, true));
17355                }
17356                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17357            }
17358            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17359        }
17360
17361        wrap_guides
17362    }
17363
17364    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17365        let settings = self.buffer.read(cx).language_settings(cx);
17366        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17367        match mode {
17368            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17369                SoftWrap::None
17370            }
17371            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17372            language_settings::SoftWrap::PreferredLineLength => {
17373                SoftWrap::Column(settings.preferred_line_length)
17374            }
17375            language_settings::SoftWrap::Bounded => {
17376                SoftWrap::Bounded(settings.preferred_line_length)
17377            }
17378        }
17379    }
17380
17381    pub fn set_soft_wrap_mode(
17382        &mut self,
17383        mode: language_settings::SoftWrap,
17384
17385        cx: &mut Context<Self>,
17386    ) {
17387        self.soft_wrap_mode_override = Some(mode);
17388        cx.notify();
17389    }
17390
17391    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17392        self.hard_wrap = hard_wrap;
17393        cx.notify();
17394    }
17395
17396    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17397        self.text_style_refinement = Some(style);
17398    }
17399
17400    /// called by the Element so we know what style we were most recently rendered with.
17401    pub(crate) fn set_style(
17402        &mut self,
17403        style: EditorStyle,
17404        window: &mut Window,
17405        cx: &mut Context<Self>,
17406    ) {
17407        // We intentionally do not inform the display map about the minimap style
17408        // so that wrapping is not recalculated and stays consistent for the editor
17409        // and its linked minimap.
17410        if !self.mode.is_minimap() {
17411            let rem_size = window.rem_size();
17412            self.display_map.update(cx, |map, cx| {
17413                map.set_font(
17414                    style.text.font(),
17415                    style.text.font_size.to_pixels(rem_size),
17416                    cx,
17417                )
17418            });
17419        }
17420        self.style = Some(style);
17421    }
17422
17423    pub fn style(&self) -> Option<&EditorStyle> {
17424        self.style.as_ref()
17425    }
17426
17427    // Called by the element. This method is not designed to be called outside of the editor
17428    // element's layout code because it does not notify when rewrapping is computed synchronously.
17429    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17430        self.display_map
17431            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17432    }
17433
17434    pub fn set_soft_wrap(&mut self) {
17435        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17436    }
17437
17438    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17439        if self.soft_wrap_mode_override.is_some() {
17440            self.soft_wrap_mode_override.take();
17441        } else {
17442            let soft_wrap = match self.soft_wrap_mode(cx) {
17443                SoftWrap::GitDiff => return,
17444                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17445                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17446                    language_settings::SoftWrap::None
17447                }
17448            };
17449            self.soft_wrap_mode_override = Some(soft_wrap);
17450        }
17451        cx.notify();
17452    }
17453
17454    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17455        let Some(workspace) = self.workspace() else {
17456            return;
17457        };
17458        let fs = workspace.read(cx).app_state().fs.clone();
17459        let current_show = TabBarSettings::get_global(cx).show;
17460        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17461            setting.show = Some(!current_show);
17462        });
17463    }
17464
17465    pub fn toggle_indent_guides(
17466        &mut self,
17467        _: &ToggleIndentGuides,
17468        _: &mut Window,
17469        cx: &mut Context<Self>,
17470    ) {
17471        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17472            self.buffer
17473                .read(cx)
17474                .language_settings(cx)
17475                .indent_guides
17476                .enabled
17477        });
17478        self.show_indent_guides = Some(!currently_enabled);
17479        cx.notify();
17480    }
17481
17482    fn should_show_indent_guides(&self) -> Option<bool> {
17483        self.show_indent_guides
17484    }
17485
17486    pub fn toggle_line_numbers(
17487        &mut self,
17488        _: &ToggleLineNumbers,
17489        _: &mut Window,
17490        cx: &mut Context<Self>,
17491    ) {
17492        let mut editor_settings = EditorSettings::get_global(cx).clone();
17493        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17494        EditorSettings::override_global(editor_settings, cx);
17495    }
17496
17497    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17498        if let Some(show_line_numbers) = self.show_line_numbers {
17499            return show_line_numbers;
17500        }
17501        EditorSettings::get_global(cx).gutter.line_numbers
17502    }
17503
17504    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17505        self.use_relative_line_numbers
17506            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17507    }
17508
17509    pub fn toggle_relative_line_numbers(
17510        &mut self,
17511        _: &ToggleRelativeLineNumbers,
17512        _: &mut Window,
17513        cx: &mut Context<Self>,
17514    ) {
17515        let is_relative = self.should_use_relative_line_numbers(cx);
17516        self.set_relative_line_number(Some(!is_relative), cx)
17517    }
17518
17519    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17520        self.use_relative_line_numbers = is_relative;
17521        cx.notify();
17522    }
17523
17524    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17525        self.show_gutter = show_gutter;
17526        cx.notify();
17527    }
17528
17529    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17530        self.show_scrollbars = ScrollbarAxes {
17531            horizontal: show,
17532            vertical: show,
17533        };
17534        cx.notify();
17535    }
17536
17537    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17538        self.show_scrollbars.vertical = show;
17539        cx.notify();
17540    }
17541
17542    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17543        self.show_scrollbars.horizontal = show;
17544        cx.notify();
17545    }
17546
17547    pub fn set_minimap_visibility(
17548        &mut self,
17549        minimap_visibility: MinimapVisibility,
17550        window: &mut Window,
17551        cx: &mut Context<Self>,
17552    ) {
17553        if self.minimap_visibility != minimap_visibility {
17554            if minimap_visibility.visible() && self.minimap.is_none() {
17555                let minimap_settings = EditorSettings::get_global(cx).minimap;
17556                self.minimap =
17557                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17558            }
17559            self.minimap_visibility = minimap_visibility;
17560            cx.notify();
17561        }
17562    }
17563
17564    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17565        self.set_show_scrollbars(false, cx);
17566        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17567    }
17568
17569    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17570        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17571    }
17572
17573    /// Normally the text in full mode and auto height editors is padded on the
17574    /// left side by roughly half a character width for improved hit testing.
17575    ///
17576    /// Use this method to disable this for cases where this is not wanted (e.g.
17577    /// if you want to align the editor text with some other text above or below)
17578    /// or if you want to add this padding to single-line editors.
17579    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17580        self.offset_content = offset_content;
17581        cx.notify();
17582    }
17583
17584    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17585        self.show_line_numbers = Some(show_line_numbers);
17586        cx.notify();
17587    }
17588
17589    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17590        self.disable_expand_excerpt_buttons = true;
17591        cx.notify();
17592    }
17593
17594    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17595        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17596        cx.notify();
17597    }
17598
17599    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17600        self.show_code_actions = Some(show_code_actions);
17601        cx.notify();
17602    }
17603
17604    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17605        self.show_runnables = Some(show_runnables);
17606        cx.notify();
17607    }
17608
17609    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17610        self.show_breakpoints = Some(show_breakpoints);
17611        cx.notify();
17612    }
17613
17614    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17615        if self.display_map.read(cx).masked != masked {
17616            self.display_map.update(cx, |map, _| map.masked = masked);
17617        }
17618        cx.notify()
17619    }
17620
17621    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17622        self.show_wrap_guides = Some(show_wrap_guides);
17623        cx.notify();
17624    }
17625
17626    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17627        self.show_indent_guides = Some(show_indent_guides);
17628        cx.notify();
17629    }
17630
17631    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17632        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17633            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17634                if let Some(dir) = file.abs_path(cx).parent() {
17635                    return Some(dir.to_owned());
17636                }
17637            }
17638
17639            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17640                return Some(project_path.path.to_path_buf());
17641            }
17642        }
17643
17644        None
17645    }
17646
17647    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17648        self.active_excerpt(cx)?
17649            .1
17650            .read(cx)
17651            .file()
17652            .and_then(|f| f.as_local())
17653    }
17654
17655    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17656        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17657            let buffer = buffer.read(cx);
17658            if let Some(project_path) = buffer.project_path(cx) {
17659                let project = self.project.as_ref()?.read(cx);
17660                project.absolute_path(&project_path, cx)
17661            } else {
17662                buffer
17663                    .file()
17664                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17665            }
17666        })
17667    }
17668
17669    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17670        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17671            let project_path = buffer.read(cx).project_path(cx)?;
17672            let project = self.project.as_ref()?.read(cx);
17673            let entry = project.entry_for_path(&project_path, cx)?;
17674            let path = entry.path.to_path_buf();
17675            Some(path)
17676        })
17677    }
17678
17679    pub fn reveal_in_finder(
17680        &mut self,
17681        _: &RevealInFileManager,
17682        _window: &mut Window,
17683        cx: &mut Context<Self>,
17684    ) {
17685        if let Some(target) = self.target_file(cx) {
17686            cx.reveal_path(&target.abs_path(cx));
17687        }
17688    }
17689
17690    pub fn copy_path(
17691        &mut self,
17692        _: &zed_actions::workspace::CopyPath,
17693        _window: &mut Window,
17694        cx: &mut Context<Self>,
17695    ) {
17696        if let Some(path) = self.target_file_abs_path(cx) {
17697            if let Some(path) = path.to_str() {
17698                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17699            }
17700        }
17701    }
17702
17703    pub fn copy_relative_path(
17704        &mut self,
17705        _: &zed_actions::workspace::CopyRelativePath,
17706        _window: &mut Window,
17707        cx: &mut Context<Self>,
17708    ) {
17709        if let Some(path) = self.target_file_path(cx) {
17710            if let Some(path) = path.to_str() {
17711                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17712            }
17713        }
17714    }
17715
17716    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17717        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17718            buffer.read(cx).project_path(cx)
17719        } else {
17720            None
17721        }
17722    }
17723
17724    // Returns true if the editor handled a go-to-line request
17725    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17726        maybe!({
17727            let breakpoint_store = self.breakpoint_store.as_ref()?;
17728
17729            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17730            else {
17731                self.clear_row_highlights::<ActiveDebugLine>();
17732                return None;
17733            };
17734
17735            let position = active_stack_frame.position;
17736            let buffer_id = position.buffer_id?;
17737            let snapshot = self
17738                .project
17739                .as_ref()?
17740                .read(cx)
17741                .buffer_for_id(buffer_id, cx)?
17742                .read(cx)
17743                .snapshot();
17744
17745            let mut handled = false;
17746            for (id, ExcerptRange { context, .. }) in
17747                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17748            {
17749                if context.start.cmp(&position, &snapshot).is_ge()
17750                    || context.end.cmp(&position, &snapshot).is_lt()
17751                {
17752                    continue;
17753                }
17754                let snapshot = self.buffer.read(cx).snapshot(cx);
17755                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17756
17757                handled = true;
17758                self.clear_row_highlights::<ActiveDebugLine>();
17759
17760                self.go_to_line::<ActiveDebugLine>(
17761                    multibuffer_anchor,
17762                    Some(cx.theme().colors().editor_debugger_active_line_background),
17763                    window,
17764                    cx,
17765                );
17766
17767                cx.notify();
17768            }
17769
17770            handled.then_some(())
17771        })
17772        .is_some()
17773    }
17774
17775    pub fn copy_file_name_without_extension(
17776        &mut self,
17777        _: &CopyFileNameWithoutExtension,
17778        _: &mut Window,
17779        cx: &mut Context<Self>,
17780    ) {
17781        if let Some(file) = self.target_file(cx) {
17782            if let Some(file_stem) = file.path().file_stem() {
17783                if let Some(name) = file_stem.to_str() {
17784                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17785                }
17786            }
17787        }
17788    }
17789
17790    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17791        if let Some(file) = self.target_file(cx) {
17792            if let Some(file_name) = file.path().file_name() {
17793                if let Some(name) = file_name.to_str() {
17794                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17795                }
17796            }
17797        }
17798    }
17799
17800    pub fn toggle_git_blame(
17801        &mut self,
17802        _: &::git::Blame,
17803        window: &mut Window,
17804        cx: &mut Context<Self>,
17805    ) {
17806        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17807
17808        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17809            self.start_git_blame(true, window, cx);
17810        }
17811
17812        cx.notify();
17813    }
17814
17815    pub fn toggle_git_blame_inline(
17816        &mut self,
17817        _: &ToggleGitBlameInline,
17818        window: &mut Window,
17819        cx: &mut Context<Self>,
17820    ) {
17821        self.toggle_git_blame_inline_internal(true, window, cx);
17822        cx.notify();
17823    }
17824
17825    pub fn open_git_blame_commit(
17826        &mut self,
17827        _: &OpenGitBlameCommit,
17828        window: &mut Window,
17829        cx: &mut Context<Self>,
17830    ) {
17831        self.open_git_blame_commit_internal(window, cx);
17832    }
17833
17834    fn open_git_blame_commit_internal(
17835        &mut self,
17836        window: &mut Window,
17837        cx: &mut Context<Self>,
17838    ) -> Option<()> {
17839        let blame = self.blame.as_ref()?;
17840        let snapshot = self.snapshot(window, cx);
17841        let cursor = self.selections.newest::<Point>(cx).head();
17842        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17843        let blame_entry = blame
17844            .update(cx, |blame, cx| {
17845                blame
17846                    .blame_for_rows(
17847                        &[RowInfo {
17848                            buffer_id: Some(buffer.remote_id()),
17849                            buffer_row: Some(point.row),
17850                            ..Default::default()
17851                        }],
17852                        cx,
17853                    )
17854                    .next()
17855            })
17856            .flatten()?;
17857        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17858        let repo = blame.read(cx).repository(cx)?;
17859        let workspace = self.workspace()?.downgrade();
17860        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17861        None
17862    }
17863
17864    pub fn git_blame_inline_enabled(&self) -> bool {
17865        self.git_blame_inline_enabled
17866    }
17867
17868    pub fn toggle_selection_menu(
17869        &mut self,
17870        _: &ToggleSelectionMenu,
17871        _: &mut Window,
17872        cx: &mut Context<Self>,
17873    ) {
17874        self.show_selection_menu = self
17875            .show_selection_menu
17876            .map(|show_selections_menu| !show_selections_menu)
17877            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17878
17879        cx.notify();
17880    }
17881
17882    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17883        self.show_selection_menu
17884            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17885    }
17886
17887    fn start_git_blame(
17888        &mut self,
17889        user_triggered: bool,
17890        window: &mut Window,
17891        cx: &mut Context<Self>,
17892    ) {
17893        if let Some(project) = self.project.as_ref() {
17894            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17895                return;
17896            };
17897
17898            if buffer.read(cx).file().is_none() {
17899                return;
17900            }
17901
17902            let focused = self.focus_handle(cx).contains_focused(window, cx);
17903
17904            let project = project.clone();
17905            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17906            self.blame_subscription =
17907                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17908            self.blame = Some(blame);
17909        }
17910    }
17911
17912    fn toggle_git_blame_inline_internal(
17913        &mut self,
17914        user_triggered: bool,
17915        window: &mut Window,
17916        cx: &mut Context<Self>,
17917    ) {
17918        if self.git_blame_inline_enabled {
17919            self.git_blame_inline_enabled = false;
17920            self.show_git_blame_inline = false;
17921            self.show_git_blame_inline_delay_task.take();
17922        } else {
17923            self.git_blame_inline_enabled = true;
17924            self.start_git_blame_inline(user_triggered, window, cx);
17925        }
17926
17927        cx.notify();
17928    }
17929
17930    fn start_git_blame_inline(
17931        &mut self,
17932        user_triggered: bool,
17933        window: &mut Window,
17934        cx: &mut Context<Self>,
17935    ) {
17936        self.start_git_blame(user_triggered, window, cx);
17937
17938        if ProjectSettings::get_global(cx)
17939            .git
17940            .inline_blame_delay()
17941            .is_some()
17942        {
17943            self.start_inline_blame_timer(window, cx);
17944        } else {
17945            self.show_git_blame_inline = true
17946        }
17947    }
17948
17949    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17950        self.blame.as_ref()
17951    }
17952
17953    pub fn show_git_blame_gutter(&self) -> bool {
17954        self.show_git_blame_gutter
17955    }
17956
17957    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17958        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17959    }
17960
17961    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17962        self.show_git_blame_inline
17963            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17964            && !self.newest_selection_head_on_empty_line(cx)
17965            && self.has_blame_entries(cx)
17966    }
17967
17968    fn has_blame_entries(&self, cx: &App) -> bool {
17969        self.blame()
17970            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17971    }
17972
17973    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17974        let cursor_anchor = self.selections.newest_anchor().head();
17975
17976        let snapshot = self.buffer.read(cx).snapshot(cx);
17977        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17978
17979        snapshot.line_len(buffer_row) == 0
17980    }
17981
17982    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17983        let buffer_and_selection = maybe!({
17984            let selection = self.selections.newest::<Point>(cx);
17985            let selection_range = selection.range();
17986
17987            let multi_buffer = self.buffer().read(cx);
17988            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17989            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17990
17991            let (buffer, range, _) = if selection.reversed {
17992                buffer_ranges.first()
17993            } else {
17994                buffer_ranges.last()
17995            }?;
17996
17997            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17998                ..text::ToPoint::to_point(&range.end, &buffer).row;
17999            Some((
18000                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18001                selection,
18002            ))
18003        });
18004
18005        let Some((buffer, selection)) = buffer_and_selection else {
18006            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18007        };
18008
18009        let Some(project) = self.project.as_ref() else {
18010            return Task::ready(Err(anyhow!("editor does not have project")));
18011        };
18012
18013        project.update(cx, |project, cx| {
18014            project.get_permalink_to_line(&buffer, selection, cx)
18015        })
18016    }
18017
18018    pub fn copy_permalink_to_line(
18019        &mut self,
18020        _: &CopyPermalinkToLine,
18021        window: &mut Window,
18022        cx: &mut Context<Self>,
18023    ) {
18024        let permalink_task = self.get_permalink_to_line(cx);
18025        let workspace = self.workspace();
18026
18027        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18028            Ok(permalink) => {
18029                cx.update(|_, cx| {
18030                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18031                })
18032                .ok();
18033            }
18034            Err(err) => {
18035                let message = format!("Failed to copy permalink: {err}");
18036
18037                anyhow::Result::<()>::Err(err).log_err();
18038
18039                if let Some(workspace) = workspace {
18040                    workspace
18041                        .update_in(cx, |workspace, _, cx| {
18042                            struct CopyPermalinkToLine;
18043
18044                            workspace.show_toast(
18045                                Toast::new(
18046                                    NotificationId::unique::<CopyPermalinkToLine>(),
18047                                    message,
18048                                ),
18049                                cx,
18050                            )
18051                        })
18052                        .ok();
18053                }
18054            }
18055        })
18056        .detach();
18057    }
18058
18059    pub fn copy_file_location(
18060        &mut self,
18061        _: &CopyFileLocation,
18062        _: &mut Window,
18063        cx: &mut Context<Self>,
18064    ) {
18065        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18066        if let Some(file) = self.target_file(cx) {
18067            if let Some(path) = file.path().to_str() {
18068                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18069            }
18070        }
18071    }
18072
18073    pub fn open_permalink_to_line(
18074        &mut self,
18075        _: &OpenPermalinkToLine,
18076        window: &mut Window,
18077        cx: &mut Context<Self>,
18078    ) {
18079        let permalink_task = self.get_permalink_to_line(cx);
18080        let workspace = self.workspace();
18081
18082        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18083            Ok(permalink) => {
18084                cx.update(|_, cx| {
18085                    cx.open_url(permalink.as_ref());
18086                })
18087                .ok();
18088            }
18089            Err(err) => {
18090                let message = format!("Failed to open permalink: {err}");
18091
18092                anyhow::Result::<()>::Err(err).log_err();
18093
18094                if let Some(workspace) = workspace {
18095                    workspace
18096                        .update(cx, |workspace, cx| {
18097                            struct OpenPermalinkToLine;
18098
18099                            workspace.show_toast(
18100                                Toast::new(
18101                                    NotificationId::unique::<OpenPermalinkToLine>(),
18102                                    message,
18103                                ),
18104                                cx,
18105                            )
18106                        })
18107                        .ok();
18108                }
18109            }
18110        })
18111        .detach();
18112    }
18113
18114    pub fn insert_uuid_v4(
18115        &mut self,
18116        _: &InsertUuidV4,
18117        window: &mut Window,
18118        cx: &mut Context<Self>,
18119    ) {
18120        self.insert_uuid(UuidVersion::V4, window, cx);
18121    }
18122
18123    pub fn insert_uuid_v7(
18124        &mut self,
18125        _: &InsertUuidV7,
18126        window: &mut Window,
18127        cx: &mut Context<Self>,
18128    ) {
18129        self.insert_uuid(UuidVersion::V7, window, cx);
18130    }
18131
18132    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18133        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
18134        self.transact(window, cx, |this, window, cx| {
18135            let edits = this
18136                .selections
18137                .all::<Point>(cx)
18138                .into_iter()
18139                .map(|selection| {
18140                    let uuid = match version {
18141                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18142                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18143                    };
18144
18145                    (selection.range(), uuid.to_string())
18146                });
18147            this.edit(edits, cx);
18148            this.refresh_inline_completion(true, false, window, cx);
18149        });
18150    }
18151
18152    pub fn open_selections_in_multibuffer(
18153        &mut self,
18154        _: &OpenSelectionsInMultibuffer,
18155        window: &mut Window,
18156        cx: &mut Context<Self>,
18157    ) {
18158        let multibuffer = self.buffer.read(cx);
18159
18160        let Some(buffer) = multibuffer.as_singleton() else {
18161            return;
18162        };
18163
18164        let Some(workspace) = self.workspace() else {
18165            return;
18166        };
18167
18168        let locations = self
18169            .selections
18170            .disjoint_anchors()
18171            .iter()
18172            .map(|range| Location {
18173                buffer: buffer.clone(),
18174                range: range.start.text_anchor..range.end.text_anchor,
18175            })
18176            .collect::<Vec<_>>();
18177
18178        let title = multibuffer.title(cx).to_string();
18179
18180        cx.spawn_in(window, async move |_, cx| {
18181            workspace.update_in(cx, |workspace, window, cx| {
18182                Self::open_locations_in_multibuffer(
18183                    workspace,
18184                    locations,
18185                    format!("Selections for '{title}'"),
18186                    false,
18187                    MultibufferSelectionMode::All,
18188                    window,
18189                    cx,
18190                );
18191            })
18192        })
18193        .detach();
18194    }
18195
18196    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18197    /// last highlight added will be used.
18198    ///
18199    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18200    pub fn highlight_rows<T: 'static>(
18201        &mut self,
18202        range: Range<Anchor>,
18203        color: Hsla,
18204        options: RowHighlightOptions,
18205        cx: &mut Context<Self>,
18206    ) {
18207        let snapshot = self.buffer().read(cx).snapshot(cx);
18208        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18209        let ix = row_highlights.binary_search_by(|highlight| {
18210            Ordering::Equal
18211                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18212                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18213        });
18214
18215        if let Err(mut ix) = ix {
18216            let index = post_inc(&mut self.highlight_order);
18217
18218            // If this range intersects with the preceding highlight, then merge it with
18219            // the preceding highlight. Otherwise insert a new highlight.
18220            let mut merged = false;
18221            if ix > 0 {
18222                let prev_highlight = &mut row_highlights[ix - 1];
18223                if prev_highlight
18224                    .range
18225                    .end
18226                    .cmp(&range.start, &snapshot)
18227                    .is_ge()
18228                {
18229                    ix -= 1;
18230                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18231                        prev_highlight.range.end = range.end;
18232                    }
18233                    merged = true;
18234                    prev_highlight.index = index;
18235                    prev_highlight.color = color;
18236                    prev_highlight.options = options;
18237                }
18238            }
18239
18240            if !merged {
18241                row_highlights.insert(
18242                    ix,
18243                    RowHighlight {
18244                        range: range.clone(),
18245                        index,
18246                        color,
18247                        options,
18248                        type_id: TypeId::of::<T>(),
18249                    },
18250                );
18251            }
18252
18253            // If any of the following highlights intersect with this one, merge them.
18254            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18255                let highlight = &row_highlights[ix];
18256                if next_highlight
18257                    .range
18258                    .start
18259                    .cmp(&highlight.range.end, &snapshot)
18260                    .is_le()
18261                {
18262                    if next_highlight
18263                        .range
18264                        .end
18265                        .cmp(&highlight.range.end, &snapshot)
18266                        .is_gt()
18267                    {
18268                        row_highlights[ix].range.end = next_highlight.range.end;
18269                    }
18270                    row_highlights.remove(ix + 1);
18271                } else {
18272                    break;
18273                }
18274            }
18275        }
18276    }
18277
18278    /// Remove any highlighted row ranges of the given type that intersect the
18279    /// given ranges.
18280    pub fn remove_highlighted_rows<T: 'static>(
18281        &mut self,
18282        ranges_to_remove: Vec<Range<Anchor>>,
18283        cx: &mut Context<Self>,
18284    ) {
18285        let snapshot = self.buffer().read(cx).snapshot(cx);
18286        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18287        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18288        row_highlights.retain(|highlight| {
18289            while let Some(range_to_remove) = ranges_to_remove.peek() {
18290                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18291                    Ordering::Less | Ordering::Equal => {
18292                        ranges_to_remove.next();
18293                    }
18294                    Ordering::Greater => {
18295                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18296                            Ordering::Less | Ordering::Equal => {
18297                                return false;
18298                            }
18299                            Ordering::Greater => break,
18300                        }
18301                    }
18302                }
18303            }
18304
18305            true
18306        })
18307    }
18308
18309    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18310    pub fn clear_row_highlights<T: 'static>(&mut self) {
18311        self.highlighted_rows.remove(&TypeId::of::<T>());
18312    }
18313
18314    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18315    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18316        self.highlighted_rows
18317            .get(&TypeId::of::<T>())
18318            .map_or(&[] as &[_], |vec| vec.as_slice())
18319            .iter()
18320            .map(|highlight| (highlight.range.clone(), highlight.color))
18321    }
18322
18323    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18324    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18325    /// Allows to ignore certain kinds of highlights.
18326    pub fn highlighted_display_rows(
18327        &self,
18328        window: &mut Window,
18329        cx: &mut App,
18330    ) -> BTreeMap<DisplayRow, LineHighlight> {
18331        let snapshot = self.snapshot(window, cx);
18332        let mut used_highlight_orders = HashMap::default();
18333        self.highlighted_rows
18334            .iter()
18335            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18336            .fold(
18337                BTreeMap::<DisplayRow, LineHighlight>::new(),
18338                |mut unique_rows, highlight| {
18339                    let start = highlight.range.start.to_display_point(&snapshot);
18340                    let end = highlight.range.end.to_display_point(&snapshot);
18341                    let start_row = start.row().0;
18342                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18343                        && end.column() == 0
18344                    {
18345                        end.row().0.saturating_sub(1)
18346                    } else {
18347                        end.row().0
18348                    };
18349                    for row in start_row..=end_row {
18350                        let used_index =
18351                            used_highlight_orders.entry(row).or_insert(highlight.index);
18352                        if highlight.index >= *used_index {
18353                            *used_index = highlight.index;
18354                            unique_rows.insert(
18355                                DisplayRow(row),
18356                                LineHighlight {
18357                                    include_gutter: highlight.options.include_gutter,
18358                                    border: None,
18359                                    background: highlight.color.into(),
18360                                    type_id: Some(highlight.type_id),
18361                                },
18362                            );
18363                        }
18364                    }
18365                    unique_rows
18366                },
18367            )
18368    }
18369
18370    pub fn highlighted_display_row_for_autoscroll(
18371        &self,
18372        snapshot: &DisplaySnapshot,
18373    ) -> Option<DisplayRow> {
18374        self.highlighted_rows
18375            .values()
18376            .flat_map(|highlighted_rows| highlighted_rows.iter())
18377            .filter_map(|highlight| {
18378                if highlight.options.autoscroll {
18379                    Some(highlight.range.start.to_display_point(snapshot).row())
18380                } else {
18381                    None
18382                }
18383            })
18384            .min()
18385    }
18386
18387    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18388        self.highlight_background::<SearchWithinRange>(
18389            ranges,
18390            |colors| colors.editor_document_highlight_read_background,
18391            cx,
18392        )
18393    }
18394
18395    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18396        self.breadcrumb_header = Some(new_header);
18397    }
18398
18399    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18400        self.clear_background_highlights::<SearchWithinRange>(cx);
18401    }
18402
18403    pub fn highlight_background<T: 'static>(
18404        &mut self,
18405        ranges: &[Range<Anchor>],
18406        color_fetcher: fn(&ThemeColors) -> Hsla,
18407        cx: &mut Context<Self>,
18408    ) {
18409        self.background_highlights
18410            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18411        self.scrollbar_marker_state.dirty = true;
18412        cx.notify();
18413    }
18414
18415    pub fn clear_background_highlights<T: 'static>(
18416        &mut self,
18417        cx: &mut Context<Self>,
18418    ) -> Option<BackgroundHighlight> {
18419        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18420        if !text_highlights.1.is_empty() {
18421            self.scrollbar_marker_state.dirty = true;
18422            cx.notify();
18423        }
18424        Some(text_highlights)
18425    }
18426
18427    pub fn highlight_gutter<T: 'static>(
18428        &mut self,
18429        ranges: impl Into<Vec<Range<Anchor>>>,
18430        color_fetcher: fn(&App) -> Hsla,
18431        cx: &mut Context<Self>,
18432    ) {
18433        self.gutter_highlights
18434            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18435        cx.notify();
18436    }
18437
18438    pub fn clear_gutter_highlights<T: 'static>(
18439        &mut self,
18440        cx: &mut Context<Self>,
18441    ) -> Option<GutterHighlight> {
18442        cx.notify();
18443        self.gutter_highlights.remove(&TypeId::of::<T>())
18444    }
18445
18446    pub fn insert_gutter_highlight<T: 'static>(
18447        &mut self,
18448        range: Range<Anchor>,
18449        color_fetcher: fn(&App) -> Hsla,
18450        cx: &mut Context<Self>,
18451    ) {
18452        let snapshot = self.buffer().read(cx).snapshot(cx);
18453        let mut highlights = self
18454            .gutter_highlights
18455            .remove(&TypeId::of::<T>())
18456            .map(|(_, highlights)| highlights)
18457            .unwrap_or_default();
18458        let ix = highlights.binary_search_by(|highlight| {
18459            Ordering::Equal
18460                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18461                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18462        });
18463        if let Err(ix) = ix {
18464            highlights.insert(ix, range);
18465        }
18466        self.gutter_highlights
18467            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18468    }
18469
18470    pub fn remove_gutter_highlights<T: 'static>(
18471        &mut self,
18472        ranges_to_remove: Vec<Range<Anchor>>,
18473        cx: &mut Context<Self>,
18474    ) {
18475        let snapshot = self.buffer().read(cx).snapshot(cx);
18476        let Some((color_fetcher, mut gutter_highlights)) =
18477            self.gutter_highlights.remove(&TypeId::of::<T>())
18478        else {
18479            return;
18480        };
18481        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18482        gutter_highlights.retain(|highlight| {
18483            while let Some(range_to_remove) = ranges_to_remove.peek() {
18484                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18485                    Ordering::Less | Ordering::Equal => {
18486                        ranges_to_remove.next();
18487                    }
18488                    Ordering::Greater => {
18489                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18490                            Ordering::Less | Ordering::Equal => {
18491                                return false;
18492                            }
18493                            Ordering::Greater => break,
18494                        }
18495                    }
18496                }
18497            }
18498
18499            true
18500        });
18501        self.gutter_highlights
18502            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18503    }
18504
18505    #[cfg(feature = "test-support")]
18506    pub fn all_text_background_highlights(
18507        &self,
18508        window: &mut Window,
18509        cx: &mut Context<Self>,
18510    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18511        let snapshot = self.snapshot(window, cx);
18512        let buffer = &snapshot.buffer_snapshot;
18513        let start = buffer.anchor_before(0);
18514        let end = buffer.anchor_after(buffer.len());
18515        let theme = cx.theme().colors();
18516        self.background_highlights_in_range(start..end, &snapshot, theme)
18517    }
18518
18519    #[cfg(feature = "test-support")]
18520    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18521        let snapshot = self.buffer().read(cx).snapshot(cx);
18522
18523        let highlights = self
18524            .background_highlights
18525            .get(&TypeId::of::<items::BufferSearchHighlights>());
18526
18527        if let Some((_color, ranges)) = highlights {
18528            ranges
18529                .iter()
18530                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18531                .collect_vec()
18532        } else {
18533            vec![]
18534        }
18535    }
18536
18537    fn document_highlights_for_position<'a>(
18538        &'a self,
18539        position: Anchor,
18540        buffer: &'a MultiBufferSnapshot,
18541    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18542        let read_highlights = self
18543            .background_highlights
18544            .get(&TypeId::of::<DocumentHighlightRead>())
18545            .map(|h| &h.1);
18546        let write_highlights = self
18547            .background_highlights
18548            .get(&TypeId::of::<DocumentHighlightWrite>())
18549            .map(|h| &h.1);
18550        let left_position = position.bias_left(buffer);
18551        let right_position = position.bias_right(buffer);
18552        read_highlights
18553            .into_iter()
18554            .chain(write_highlights)
18555            .flat_map(move |ranges| {
18556                let start_ix = match ranges.binary_search_by(|probe| {
18557                    let cmp = probe.end.cmp(&left_position, buffer);
18558                    if cmp.is_ge() {
18559                        Ordering::Greater
18560                    } else {
18561                        Ordering::Less
18562                    }
18563                }) {
18564                    Ok(i) | Err(i) => i,
18565                };
18566
18567                ranges[start_ix..]
18568                    .iter()
18569                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18570            })
18571    }
18572
18573    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18574        self.background_highlights
18575            .get(&TypeId::of::<T>())
18576            .map_or(false, |(_, highlights)| !highlights.is_empty())
18577    }
18578
18579    pub fn background_highlights_in_range(
18580        &self,
18581        search_range: Range<Anchor>,
18582        display_snapshot: &DisplaySnapshot,
18583        theme: &ThemeColors,
18584    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18585        let mut results = Vec::new();
18586        for (color_fetcher, ranges) in self.background_highlights.values() {
18587            let color = color_fetcher(theme);
18588            let start_ix = match ranges.binary_search_by(|probe| {
18589                let cmp = probe
18590                    .end
18591                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18592                if cmp.is_gt() {
18593                    Ordering::Greater
18594                } else {
18595                    Ordering::Less
18596                }
18597            }) {
18598                Ok(i) | Err(i) => i,
18599            };
18600            for range in &ranges[start_ix..] {
18601                if range
18602                    .start
18603                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18604                    .is_ge()
18605                {
18606                    break;
18607                }
18608
18609                let start = range.start.to_display_point(display_snapshot);
18610                let end = range.end.to_display_point(display_snapshot);
18611                results.push((start..end, color))
18612            }
18613        }
18614        results
18615    }
18616
18617    pub fn background_highlight_row_ranges<T: 'static>(
18618        &self,
18619        search_range: Range<Anchor>,
18620        display_snapshot: &DisplaySnapshot,
18621        count: usize,
18622    ) -> Vec<RangeInclusive<DisplayPoint>> {
18623        let mut results = Vec::new();
18624        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18625            return vec![];
18626        };
18627
18628        let start_ix = match ranges.binary_search_by(|probe| {
18629            let cmp = probe
18630                .end
18631                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18632            if cmp.is_gt() {
18633                Ordering::Greater
18634            } else {
18635                Ordering::Less
18636            }
18637        }) {
18638            Ok(i) | Err(i) => i,
18639        };
18640        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18641            if let (Some(start_display), Some(end_display)) = (start, end) {
18642                results.push(
18643                    start_display.to_display_point(display_snapshot)
18644                        ..=end_display.to_display_point(display_snapshot),
18645                );
18646            }
18647        };
18648        let mut start_row: Option<Point> = None;
18649        let mut end_row: Option<Point> = None;
18650        if ranges.len() > count {
18651            return Vec::new();
18652        }
18653        for range in &ranges[start_ix..] {
18654            if range
18655                .start
18656                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18657                .is_ge()
18658            {
18659                break;
18660            }
18661            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18662            if let Some(current_row) = &end_row {
18663                if end.row == current_row.row {
18664                    continue;
18665                }
18666            }
18667            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18668            if start_row.is_none() {
18669                assert_eq!(end_row, None);
18670                start_row = Some(start);
18671                end_row = Some(end);
18672                continue;
18673            }
18674            if let Some(current_end) = end_row.as_mut() {
18675                if start.row > current_end.row + 1 {
18676                    push_region(start_row, end_row);
18677                    start_row = Some(start);
18678                    end_row = Some(end);
18679                } else {
18680                    // Merge two hunks.
18681                    *current_end = end;
18682                }
18683            } else {
18684                unreachable!();
18685            }
18686        }
18687        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18688        push_region(start_row, end_row);
18689        results
18690    }
18691
18692    pub fn gutter_highlights_in_range(
18693        &self,
18694        search_range: Range<Anchor>,
18695        display_snapshot: &DisplaySnapshot,
18696        cx: &App,
18697    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18698        let mut results = Vec::new();
18699        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18700            let color = color_fetcher(cx);
18701            let start_ix = match ranges.binary_search_by(|probe| {
18702                let cmp = probe
18703                    .end
18704                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18705                if cmp.is_gt() {
18706                    Ordering::Greater
18707                } else {
18708                    Ordering::Less
18709                }
18710            }) {
18711                Ok(i) | Err(i) => i,
18712            };
18713            for range in &ranges[start_ix..] {
18714                if range
18715                    .start
18716                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18717                    .is_ge()
18718                {
18719                    break;
18720                }
18721
18722                let start = range.start.to_display_point(display_snapshot);
18723                let end = range.end.to_display_point(display_snapshot);
18724                results.push((start..end, color))
18725            }
18726        }
18727        results
18728    }
18729
18730    /// Get the text ranges corresponding to the redaction query
18731    pub fn redacted_ranges(
18732        &self,
18733        search_range: Range<Anchor>,
18734        display_snapshot: &DisplaySnapshot,
18735        cx: &App,
18736    ) -> Vec<Range<DisplayPoint>> {
18737        display_snapshot
18738            .buffer_snapshot
18739            .redacted_ranges(search_range, |file| {
18740                if let Some(file) = file {
18741                    file.is_private()
18742                        && EditorSettings::get(
18743                            Some(SettingsLocation {
18744                                worktree_id: file.worktree_id(cx),
18745                                path: file.path().as_ref(),
18746                            }),
18747                            cx,
18748                        )
18749                        .redact_private_values
18750                } else {
18751                    false
18752                }
18753            })
18754            .map(|range| {
18755                range.start.to_display_point(display_snapshot)
18756                    ..range.end.to_display_point(display_snapshot)
18757            })
18758            .collect()
18759    }
18760
18761    pub fn highlight_text<T: 'static>(
18762        &mut self,
18763        ranges: Vec<Range<Anchor>>,
18764        style: HighlightStyle,
18765        cx: &mut Context<Self>,
18766    ) {
18767        self.display_map.update(cx, |map, _| {
18768            map.highlight_text(TypeId::of::<T>(), ranges, style)
18769        });
18770        cx.notify();
18771    }
18772
18773    pub(crate) fn highlight_inlays<T: 'static>(
18774        &mut self,
18775        highlights: Vec<InlayHighlight>,
18776        style: HighlightStyle,
18777        cx: &mut Context<Self>,
18778    ) {
18779        self.display_map.update(cx, |map, _| {
18780            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18781        });
18782        cx.notify();
18783    }
18784
18785    pub fn text_highlights<'a, T: 'static>(
18786        &'a self,
18787        cx: &'a App,
18788    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18789        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18790    }
18791
18792    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18793        let cleared = self
18794            .display_map
18795            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18796        if cleared {
18797            cx.notify();
18798        }
18799    }
18800
18801    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18802        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18803            && self.focus_handle.is_focused(window)
18804    }
18805
18806    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18807        self.show_cursor_when_unfocused = is_enabled;
18808        cx.notify();
18809    }
18810
18811    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18812        cx.notify();
18813    }
18814
18815    fn on_debug_session_event(
18816        &mut self,
18817        _session: Entity<Session>,
18818        event: &SessionEvent,
18819        cx: &mut Context<Self>,
18820    ) {
18821        match event {
18822            SessionEvent::InvalidateInlineValue => {
18823                self.refresh_inline_values(cx);
18824            }
18825            _ => {}
18826        }
18827    }
18828
18829    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18830        let Some(project) = self.project.clone() else {
18831            return;
18832        };
18833
18834        if !self.inline_value_cache.enabled {
18835            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18836            self.splice_inlays(&inlays, Vec::new(), cx);
18837            return;
18838        }
18839
18840        let current_execution_position = self
18841            .highlighted_rows
18842            .get(&TypeId::of::<ActiveDebugLine>())
18843            .and_then(|lines| lines.last().map(|line| line.range.start));
18844
18845        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18846            let inline_values = editor
18847                .update(cx, |editor, cx| {
18848                    let Some(current_execution_position) = current_execution_position else {
18849                        return Some(Task::ready(Ok(Vec::new())));
18850                    };
18851
18852                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18853                        let snapshot = buffer.snapshot(cx);
18854
18855                        let excerpt = snapshot.excerpt_containing(
18856                            current_execution_position..current_execution_position,
18857                        )?;
18858
18859                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18860                    })?;
18861
18862                    let range =
18863                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18864
18865                    project.inline_values(buffer, range, cx)
18866                })
18867                .ok()
18868                .flatten()?
18869                .await
18870                .context("refreshing debugger inlays")
18871                .log_err()?;
18872
18873            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18874
18875            for (buffer_id, inline_value) in inline_values
18876                .into_iter()
18877                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18878            {
18879                buffer_inline_values
18880                    .entry(buffer_id)
18881                    .or_default()
18882                    .push(inline_value);
18883            }
18884
18885            editor
18886                .update(cx, |editor, cx| {
18887                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18888                    let mut new_inlays = Vec::default();
18889
18890                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18891                        let buffer_id = buffer_snapshot.remote_id();
18892                        buffer_inline_values
18893                            .get(&buffer_id)
18894                            .into_iter()
18895                            .flatten()
18896                            .for_each(|hint| {
18897                                let inlay = Inlay::debugger_hint(
18898                                    post_inc(&mut editor.next_inlay_id),
18899                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18900                                    hint.text(),
18901                                );
18902
18903                                new_inlays.push(inlay);
18904                            });
18905                    }
18906
18907                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18908                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18909
18910                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18911                })
18912                .ok()?;
18913            Some(())
18914        });
18915    }
18916
18917    fn on_buffer_event(
18918        &mut self,
18919        multibuffer: &Entity<MultiBuffer>,
18920        event: &multi_buffer::Event,
18921        window: &mut Window,
18922        cx: &mut Context<Self>,
18923    ) {
18924        match event {
18925            multi_buffer::Event::Edited {
18926                singleton_buffer_edited,
18927                edited_buffer,
18928            } => {
18929                self.scrollbar_marker_state.dirty = true;
18930                self.active_indent_guides_state.dirty = true;
18931                self.refresh_active_diagnostics(cx);
18932                self.refresh_code_actions(window, cx);
18933                self.refresh_selected_text_highlights(true, window, cx);
18934                refresh_matching_bracket_highlights(self, window, cx);
18935                if self.has_active_inline_completion() {
18936                    self.update_visible_inline_completion(window, cx);
18937                }
18938                if let Some(project) = self.project.as_ref() {
18939                    if let Some(edited_buffer) = edited_buffer {
18940                        project.update(cx, |project, cx| {
18941                            self.registered_buffers
18942                                .entry(edited_buffer.read(cx).remote_id())
18943                                .or_insert_with(|| {
18944                                    project
18945                                        .register_buffer_with_language_servers(&edited_buffer, cx)
18946                                });
18947                        });
18948                        if edited_buffer.read(cx).file().is_some() {
18949                            self.pull_diagnostics(
18950                                Some(edited_buffer.read(cx).remote_id()),
18951                                window,
18952                                cx,
18953                            );
18954                        }
18955                    }
18956                }
18957                cx.emit(EditorEvent::BufferEdited);
18958                cx.emit(SearchEvent::MatchesInvalidated);
18959                if *singleton_buffer_edited {
18960                    if let Some(buffer) = edited_buffer {
18961                        if buffer.read(cx).file().is_none() {
18962                            cx.emit(EditorEvent::TitleChanged);
18963                        }
18964                    }
18965                    if let Some(project) = &self.project {
18966                        #[allow(clippy::mutable_key_type)]
18967                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18968                            multibuffer
18969                                .all_buffers()
18970                                .into_iter()
18971                                .filter_map(|buffer| {
18972                                    buffer.update(cx, |buffer, cx| {
18973                                        let language = buffer.language()?;
18974                                        let should_discard = project.update(cx, |project, cx| {
18975                                            project.is_local()
18976                                                && !project.has_language_servers_for(buffer, cx)
18977                                        });
18978                                        should_discard.not().then_some(language.clone())
18979                                    })
18980                                })
18981                                .collect::<HashSet<_>>()
18982                        });
18983                        if !languages_affected.is_empty() {
18984                            self.refresh_inlay_hints(
18985                                InlayHintRefreshReason::BufferEdited(languages_affected),
18986                                cx,
18987                            );
18988                        }
18989                    }
18990                }
18991
18992                let Some(project) = &self.project else { return };
18993                let (telemetry, is_via_ssh) = {
18994                    let project = project.read(cx);
18995                    let telemetry = project.client().telemetry().clone();
18996                    let is_via_ssh = project.is_via_ssh();
18997                    (telemetry, is_via_ssh)
18998                };
18999                refresh_linked_ranges(self, window, cx);
19000                telemetry.log_edit_event("editor", is_via_ssh);
19001            }
19002            multi_buffer::Event::ExcerptsAdded {
19003                buffer,
19004                predecessor,
19005                excerpts,
19006            } => {
19007                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19008                let buffer_id = buffer.read(cx).remote_id();
19009                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19010                    if let Some(project) = &self.project {
19011                        update_uncommitted_diff_for_buffer(
19012                            cx.entity(),
19013                            project,
19014                            [buffer.clone()],
19015                            self.buffer.clone(),
19016                            cx,
19017                        )
19018                        .detach();
19019                    }
19020                }
19021                cx.emit(EditorEvent::ExcerptsAdded {
19022                    buffer: buffer.clone(),
19023                    predecessor: *predecessor,
19024                    excerpts: excerpts.clone(),
19025                });
19026                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19027            }
19028            multi_buffer::Event::ExcerptsRemoved {
19029                ids,
19030                removed_buffer_ids,
19031            } => {
19032                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19033                let buffer = self.buffer.read(cx);
19034                self.registered_buffers
19035                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19036                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19037                cx.emit(EditorEvent::ExcerptsRemoved {
19038                    ids: ids.clone(),
19039                    removed_buffer_ids: removed_buffer_ids.clone(),
19040                })
19041            }
19042            multi_buffer::Event::ExcerptsEdited {
19043                excerpt_ids,
19044                buffer_ids,
19045            } => {
19046                self.display_map.update(cx, |map, cx| {
19047                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19048                });
19049                cx.emit(EditorEvent::ExcerptsEdited {
19050                    ids: excerpt_ids.clone(),
19051                })
19052            }
19053            multi_buffer::Event::ExcerptsExpanded { ids } => {
19054                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19055                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19056            }
19057            multi_buffer::Event::Reparsed(buffer_id) => {
19058                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19059                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19060
19061                cx.emit(EditorEvent::Reparsed(*buffer_id));
19062            }
19063            multi_buffer::Event::DiffHunksToggled => {
19064                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19065            }
19066            multi_buffer::Event::LanguageChanged(buffer_id) => {
19067                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19068                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19069                cx.emit(EditorEvent::Reparsed(*buffer_id));
19070                cx.notify();
19071            }
19072            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19073            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19074            multi_buffer::Event::FileHandleChanged
19075            | multi_buffer::Event::Reloaded
19076            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19077            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19078            multi_buffer::Event::DiagnosticsUpdated => {
19079                self.update_diagnostics_state(window, cx);
19080            }
19081            _ => {}
19082        };
19083    }
19084
19085    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19086        self.refresh_active_diagnostics(cx);
19087        self.refresh_inline_diagnostics(true, window, cx);
19088        self.scrollbar_marker_state.dirty = true;
19089        cx.notify();
19090    }
19091
19092    pub fn start_temporary_diff_override(&mut self) {
19093        self.load_diff_task.take();
19094        self.temporary_diff_override = true;
19095    }
19096
19097    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19098        self.temporary_diff_override = false;
19099        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19100        self.buffer.update(cx, |buffer, cx| {
19101            buffer.set_all_diff_hunks_collapsed(cx);
19102        });
19103
19104        if let Some(project) = self.project.clone() {
19105            self.load_diff_task = Some(
19106                update_uncommitted_diff_for_buffer(
19107                    cx.entity(),
19108                    &project,
19109                    self.buffer.read(cx).all_buffers(),
19110                    self.buffer.clone(),
19111                    cx,
19112                )
19113                .shared(),
19114            );
19115        }
19116    }
19117
19118    fn on_display_map_changed(
19119        &mut self,
19120        _: Entity<DisplayMap>,
19121        _: &mut Window,
19122        cx: &mut Context<Self>,
19123    ) {
19124        cx.notify();
19125    }
19126
19127    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19128        let new_severity = if self.diagnostics_enabled() {
19129            EditorSettings::get_global(cx)
19130                .diagnostics_max_severity
19131                .unwrap_or(DiagnosticSeverity::Hint)
19132        } else {
19133            DiagnosticSeverity::Off
19134        };
19135        self.set_max_diagnostics_severity(new_severity, cx);
19136        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19137        self.update_edit_prediction_settings(cx);
19138        self.refresh_inline_completion(true, false, window, cx);
19139        self.refresh_inlay_hints(
19140            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19141                self.selections.newest_anchor().head(),
19142                &self.buffer.read(cx).snapshot(cx),
19143                cx,
19144            )),
19145            cx,
19146        );
19147
19148        let old_cursor_shape = self.cursor_shape;
19149
19150        {
19151            let editor_settings = EditorSettings::get_global(cx);
19152            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19153            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19154            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19155            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19156            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19157        }
19158
19159        if old_cursor_shape != self.cursor_shape {
19160            cx.emit(EditorEvent::CursorShapeChanged);
19161        }
19162
19163        let project_settings = ProjectSettings::get_global(cx);
19164        self.serialize_dirty_buffers =
19165            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19166
19167        if self.mode.is_full() {
19168            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19169            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19170            if self.show_inline_diagnostics != show_inline_diagnostics {
19171                self.show_inline_diagnostics = show_inline_diagnostics;
19172                self.refresh_inline_diagnostics(false, window, cx);
19173            }
19174
19175            if self.git_blame_inline_enabled != inline_blame_enabled {
19176                self.toggle_git_blame_inline_internal(false, window, cx);
19177            }
19178
19179            let minimap_settings = EditorSettings::get_global(cx).minimap;
19180            if self.minimap_visibility != MinimapVisibility::Disabled {
19181                if self.minimap_visibility.settings_visibility()
19182                    != minimap_settings.minimap_enabled()
19183                {
19184                    self.set_minimap_visibility(
19185                        MinimapVisibility::for_mode(self.mode(), cx),
19186                        window,
19187                        cx,
19188                    );
19189                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19190                    minimap_entity.update(cx, |minimap_editor, cx| {
19191                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19192                    })
19193                }
19194            }
19195        }
19196
19197        cx.notify();
19198    }
19199
19200    pub fn set_searchable(&mut self, searchable: bool) {
19201        self.searchable = searchable;
19202    }
19203
19204    pub fn searchable(&self) -> bool {
19205        self.searchable
19206    }
19207
19208    fn open_proposed_changes_editor(
19209        &mut self,
19210        _: &OpenProposedChangesEditor,
19211        window: &mut Window,
19212        cx: &mut Context<Self>,
19213    ) {
19214        let Some(workspace) = self.workspace() else {
19215            cx.propagate();
19216            return;
19217        };
19218
19219        let selections = self.selections.all::<usize>(cx);
19220        let multi_buffer = self.buffer.read(cx);
19221        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19222        let mut new_selections_by_buffer = HashMap::default();
19223        for selection in selections {
19224            for (buffer, range, _) in
19225                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19226            {
19227                let mut range = range.to_point(buffer);
19228                range.start.column = 0;
19229                range.end.column = buffer.line_len(range.end.row);
19230                new_selections_by_buffer
19231                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19232                    .or_insert(Vec::new())
19233                    .push(range)
19234            }
19235        }
19236
19237        let proposed_changes_buffers = new_selections_by_buffer
19238            .into_iter()
19239            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19240            .collect::<Vec<_>>();
19241        let proposed_changes_editor = cx.new(|cx| {
19242            ProposedChangesEditor::new(
19243                "Proposed changes",
19244                proposed_changes_buffers,
19245                self.project.clone(),
19246                window,
19247                cx,
19248            )
19249        });
19250
19251        window.defer(cx, move |window, cx| {
19252            workspace.update(cx, |workspace, cx| {
19253                workspace.active_pane().update(cx, |pane, cx| {
19254                    pane.add_item(
19255                        Box::new(proposed_changes_editor),
19256                        true,
19257                        true,
19258                        None,
19259                        window,
19260                        cx,
19261                    );
19262                });
19263            });
19264        });
19265    }
19266
19267    pub fn open_excerpts_in_split(
19268        &mut self,
19269        _: &OpenExcerptsSplit,
19270        window: &mut Window,
19271        cx: &mut Context<Self>,
19272    ) {
19273        self.open_excerpts_common(None, true, window, cx)
19274    }
19275
19276    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19277        self.open_excerpts_common(None, false, window, cx)
19278    }
19279
19280    fn open_excerpts_common(
19281        &mut self,
19282        jump_data: Option<JumpData>,
19283        split: bool,
19284        window: &mut Window,
19285        cx: &mut Context<Self>,
19286    ) {
19287        let Some(workspace) = self.workspace() else {
19288            cx.propagate();
19289            return;
19290        };
19291
19292        if self.buffer.read(cx).is_singleton() {
19293            cx.propagate();
19294            return;
19295        }
19296
19297        let mut new_selections_by_buffer = HashMap::default();
19298        match &jump_data {
19299            Some(JumpData::MultiBufferPoint {
19300                excerpt_id,
19301                position,
19302                anchor,
19303                line_offset_from_top,
19304            }) => {
19305                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19306                if let Some(buffer) = multi_buffer_snapshot
19307                    .buffer_id_for_excerpt(*excerpt_id)
19308                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19309                {
19310                    let buffer_snapshot = buffer.read(cx).snapshot();
19311                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19312                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19313                    } else {
19314                        buffer_snapshot.clip_point(*position, Bias::Left)
19315                    };
19316                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19317                    new_selections_by_buffer.insert(
19318                        buffer,
19319                        (
19320                            vec![jump_to_offset..jump_to_offset],
19321                            Some(*line_offset_from_top),
19322                        ),
19323                    );
19324                }
19325            }
19326            Some(JumpData::MultiBufferRow {
19327                row,
19328                line_offset_from_top,
19329            }) => {
19330                let point = MultiBufferPoint::new(row.0, 0);
19331                if let Some((buffer, buffer_point, _)) =
19332                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19333                {
19334                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19335                    new_selections_by_buffer
19336                        .entry(buffer)
19337                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19338                        .0
19339                        .push(buffer_offset..buffer_offset)
19340                }
19341            }
19342            None => {
19343                let selections = self.selections.all::<usize>(cx);
19344                let multi_buffer = self.buffer.read(cx);
19345                for selection in selections {
19346                    for (snapshot, range, _, anchor) in multi_buffer
19347                        .snapshot(cx)
19348                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19349                    {
19350                        if let Some(anchor) = anchor {
19351                            // selection is in a deleted hunk
19352                            let Some(buffer_id) = anchor.buffer_id else {
19353                                continue;
19354                            };
19355                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19356                                continue;
19357                            };
19358                            let offset = text::ToOffset::to_offset(
19359                                &anchor.text_anchor,
19360                                &buffer_handle.read(cx).snapshot(),
19361                            );
19362                            let range = offset..offset;
19363                            new_selections_by_buffer
19364                                .entry(buffer_handle)
19365                                .or_insert((Vec::new(), None))
19366                                .0
19367                                .push(range)
19368                        } else {
19369                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19370                            else {
19371                                continue;
19372                            };
19373                            new_selections_by_buffer
19374                                .entry(buffer_handle)
19375                                .or_insert((Vec::new(), None))
19376                                .0
19377                                .push(range)
19378                        }
19379                    }
19380                }
19381            }
19382        }
19383
19384        new_selections_by_buffer
19385            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19386
19387        if new_selections_by_buffer.is_empty() {
19388            return;
19389        }
19390
19391        // We defer the pane interaction because we ourselves are a workspace item
19392        // and activating a new item causes the pane to call a method on us reentrantly,
19393        // which panics if we're on the stack.
19394        window.defer(cx, move |window, cx| {
19395            workspace.update(cx, |workspace, cx| {
19396                let pane = if split {
19397                    workspace.adjacent_pane(window, cx)
19398                } else {
19399                    workspace.active_pane().clone()
19400                };
19401
19402                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19403                    let editor = buffer
19404                        .read(cx)
19405                        .file()
19406                        .is_none()
19407                        .then(|| {
19408                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19409                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19410                            // Instead, we try to activate the existing editor in the pane first.
19411                            let (editor, pane_item_index) =
19412                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19413                                    let editor = item.downcast::<Editor>()?;
19414                                    let singleton_buffer =
19415                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19416                                    if singleton_buffer == buffer {
19417                                        Some((editor, i))
19418                                    } else {
19419                                        None
19420                                    }
19421                                })?;
19422                            pane.update(cx, |pane, cx| {
19423                                pane.activate_item(pane_item_index, true, true, window, cx)
19424                            });
19425                            Some(editor)
19426                        })
19427                        .flatten()
19428                        .unwrap_or_else(|| {
19429                            workspace.open_project_item::<Self>(
19430                                pane.clone(),
19431                                buffer,
19432                                true,
19433                                true,
19434                                window,
19435                                cx,
19436                            )
19437                        });
19438
19439                    editor.update(cx, |editor, cx| {
19440                        let autoscroll = match scroll_offset {
19441                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19442                            None => Autoscroll::newest(),
19443                        };
19444                        let nav_history = editor.nav_history.take();
19445                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19446                            s.select_ranges(ranges);
19447                        });
19448                        editor.nav_history = nav_history;
19449                    });
19450                }
19451            })
19452        });
19453    }
19454
19455    // For now, don't allow opening excerpts in buffers that aren't backed by
19456    // regular project files.
19457    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19458        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19459    }
19460
19461    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19462        let snapshot = self.buffer.read(cx).read(cx);
19463        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19464        Some(
19465            ranges
19466                .iter()
19467                .map(move |range| {
19468                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19469                })
19470                .collect(),
19471        )
19472    }
19473
19474    fn selection_replacement_ranges(
19475        &self,
19476        range: Range<OffsetUtf16>,
19477        cx: &mut App,
19478    ) -> Vec<Range<OffsetUtf16>> {
19479        let selections = self.selections.all::<OffsetUtf16>(cx);
19480        let newest_selection = selections
19481            .iter()
19482            .max_by_key(|selection| selection.id)
19483            .unwrap();
19484        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19485        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19486        let snapshot = self.buffer.read(cx).read(cx);
19487        selections
19488            .into_iter()
19489            .map(|mut selection| {
19490                selection.start.0 =
19491                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19492                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19493                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19494                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19495            })
19496            .collect()
19497    }
19498
19499    fn report_editor_event(
19500        &self,
19501        event_type: &'static str,
19502        file_extension: Option<String>,
19503        cx: &App,
19504    ) {
19505        if cfg!(any(test, feature = "test-support")) {
19506            return;
19507        }
19508
19509        let Some(project) = &self.project else { return };
19510
19511        // If None, we are in a file without an extension
19512        let file = self
19513            .buffer
19514            .read(cx)
19515            .as_singleton()
19516            .and_then(|b| b.read(cx).file());
19517        let file_extension = file_extension.or(file
19518            .as_ref()
19519            .and_then(|file| Path::new(file.file_name(cx)).extension())
19520            .and_then(|e| e.to_str())
19521            .map(|a| a.to_string()));
19522
19523        let vim_mode = vim_enabled(cx);
19524
19525        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19526        let copilot_enabled = edit_predictions_provider
19527            == language::language_settings::EditPredictionProvider::Copilot;
19528        let copilot_enabled_for_language = self
19529            .buffer
19530            .read(cx)
19531            .language_settings(cx)
19532            .show_edit_predictions;
19533
19534        let project = project.read(cx);
19535        telemetry::event!(
19536            event_type,
19537            file_extension,
19538            vim_mode,
19539            copilot_enabled,
19540            copilot_enabled_for_language,
19541            edit_predictions_provider,
19542            is_via_ssh = project.is_via_ssh(),
19543        );
19544    }
19545
19546    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19547    /// with each line being an array of {text, highlight} objects.
19548    fn copy_highlight_json(
19549        &mut self,
19550        _: &CopyHighlightJson,
19551        window: &mut Window,
19552        cx: &mut Context<Self>,
19553    ) {
19554        #[derive(Serialize)]
19555        struct Chunk<'a> {
19556            text: String,
19557            highlight: Option<&'a str>,
19558        }
19559
19560        let snapshot = self.buffer.read(cx).snapshot(cx);
19561        let range = self
19562            .selected_text_range(false, window, cx)
19563            .and_then(|selection| {
19564                if selection.range.is_empty() {
19565                    None
19566                } else {
19567                    Some(selection.range)
19568                }
19569            })
19570            .unwrap_or_else(|| 0..snapshot.len());
19571
19572        let chunks = snapshot.chunks(range, true);
19573        let mut lines = Vec::new();
19574        let mut line: VecDeque<Chunk> = VecDeque::new();
19575
19576        let Some(style) = self.style.as_ref() else {
19577            return;
19578        };
19579
19580        for chunk in chunks {
19581            let highlight = chunk
19582                .syntax_highlight_id
19583                .and_then(|id| id.name(&style.syntax));
19584            let mut chunk_lines = chunk.text.split('\n').peekable();
19585            while let Some(text) = chunk_lines.next() {
19586                let mut merged_with_last_token = false;
19587                if let Some(last_token) = line.back_mut() {
19588                    if last_token.highlight == highlight {
19589                        last_token.text.push_str(text);
19590                        merged_with_last_token = true;
19591                    }
19592                }
19593
19594                if !merged_with_last_token {
19595                    line.push_back(Chunk {
19596                        text: text.into(),
19597                        highlight,
19598                    });
19599                }
19600
19601                if chunk_lines.peek().is_some() {
19602                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19603                        line.pop_front();
19604                    }
19605                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19606                        line.pop_back();
19607                    }
19608
19609                    lines.push(mem::take(&mut line));
19610                }
19611            }
19612        }
19613
19614        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19615            return;
19616        };
19617        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19618    }
19619
19620    pub fn open_context_menu(
19621        &mut self,
19622        _: &OpenContextMenu,
19623        window: &mut Window,
19624        cx: &mut Context<Self>,
19625    ) {
19626        self.request_autoscroll(Autoscroll::newest(), cx);
19627        let position = self.selections.newest_display(cx).start;
19628        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19629    }
19630
19631    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19632        &self.inlay_hint_cache
19633    }
19634
19635    pub fn replay_insert_event(
19636        &mut self,
19637        text: &str,
19638        relative_utf16_range: Option<Range<isize>>,
19639        window: &mut Window,
19640        cx: &mut Context<Self>,
19641    ) {
19642        if !self.input_enabled {
19643            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19644            return;
19645        }
19646        if let Some(relative_utf16_range) = relative_utf16_range {
19647            let selections = self.selections.all::<OffsetUtf16>(cx);
19648            self.change_selections(None, window, cx, |s| {
19649                let new_ranges = selections.into_iter().map(|range| {
19650                    let start = OffsetUtf16(
19651                        range
19652                            .head()
19653                            .0
19654                            .saturating_add_signed(relative_utf16_range.start),
19655                    );
19656                    let end = OffsetUtf16(
19657                        range
19658                            .head()
19659                            .0
19660                            .saturating_add_signed(relative_utf16_range.end),
19661                    );
19662                    start..end
19663                });
19664                s.select_ranges(new_ranges);
19665            });
19666        }
19667
19668        self.handle_input(text, window, cx);
19669    }
19670
19671    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19672        let Some(provider) = self.semantics_provider.as_ref() else {
19673            return false;
19674        };
19675
19676        let mut supports = false;
19677        self.buffer().update(cx, |this, cx| {
19678            this.for_each_buffer(|buffer| {
19679                supports |= provider.supports_inlay_hints(buffer, cx);
19680            });
19681        });
19682
19683        supports
19684    }
19685
19686    pub fn is_focused(&self, window: &Window) -> bool {
19687        self.focus_handle.is_focused(window)
19688    }
19689
19690    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19691        cx.emit(EditorEvent::Focused);
19692
19693        if let Some(descendant) = self
19694            .last_focused_descendant
19695            .take()
19696            .and_then(|descendant| descendant.upgrade())
19697        {
19698            window.focus(&descendant);
19699        } else {
19700            if let Some(blame) = self.blame.as_ref() {
19701                blame.update(cx, GitBlame::focus)
19702            }
19703
19704            self.blink_manager.update(cx, BlinkManager::enable);
19705            self.show_cursor_names(window, cx);
19706            self.buffer.update(cx, |buffer, cx| {
19707                buffer.finalize_last_transaction(cx);
19708                if self.leader_id.is_none() {
19709                    buffer.set_active_selections(
19710                        &self.selections.disjoint_anchors(),
19711                        self.selections.line_mode,
19712                        self.cursor_shape,
19713                        cx,
19714                    );
19715                }
19716            });
19717        }
19718    }
19719
19720    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19721        cx.emit(EditorEvent::FocusedIn)
19722    }
19723
19724    fn handle_focus_out(
19725        &mut self,
19726        event: FocusOutEvent,
19727        _window: &mut Window,
19728        cx: &mut Context<Self>,
19729    ) {
19730        if event.blurred != self.focus_handle {
19731            self.last_focused_descendant = Some(event.blurred);
19732        }
19733        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19734    }
19735
19736    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19737        self.blink_manager.update(cx, BlinkManager::disable);
19738        self.buffer
19739            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19740
19741        if let Some(blame) = self.blame.as_ref() {
19742            blame.update(cx, GitBlame::blur)
19743        }
19744        if !self.hover_state.focused(window, cx) {
19745            hide_hover(self, cx);
19746        }
19747        if !self
19748            .context_menu
19749            .borrow()
19750            .as_ref()
19751            .is_some_and(|context_menu| context_menu.focused(window, cx))
19752        {
19753            self.hide_context_menu(window, cx);
19754        }
19755        self.discard_inline_completion(false, cx);
19756        cx.emit(EditorEvent::Blurred);
19757        cx.notify();
19758    }
19759
19760    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19761        let mut pending: String = window
19762            .pending_input_keystrokes()
19763            .into_iter()
19764            .flatten()
19765            .filter_map(|keystroke| {
19766                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19767                    keystroke.key_char.clone()
19768                } else {
19769                    None
19770                }
19771            })
19772            .collect();
19773
19774        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19775            pending = "".to_string();
19776        }
19777
19778        let existing_pending = self
19779            .text_highlights::<PendingInput>(cx)
19780            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
19781        if existing_pending.is_none() && pending.is_empty() {
19782            return;
19783        }
19784        let transaction =
19785            self.transact(window, cx, |this, window, cx| {
19786                let selections = this.selections.all::<usize>(cx);
19787                let edits = selections
19788                    .iter()
19789                    .map(|selection| (selection.end..selection.end, pending.clone()));
19790                this.edit(edits, cx);
19791                this.change_selections(None, window, cx, |s| {
19792                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19793                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19794                    }));
19795                });
19796                if let Some(existing_ranges) = existing_pending {
19797                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19798                    this.edit(edits, cx);
19799                }
19800            });
19801
19802        let snapshot = self.snapshot(window, cx);
19803        let ranges = self
19804            .selections
19805            .all::<usize>(cx)
19806            .into_iter()
19807            .map(|selection| {
19808                snapshot.buffer_snapshot.anchor_after(selection.end)
19809                    ..snapshot
19810                        .buffer_snapshot
19811                        .anchor_before(selection.end + pending.len())
19812            })
19813            .collect();
19814
19815        if pending.is_empty() {
19816            self.clear_highlights::<PendingInput>(cx);
19817        } else {
19818            self.highlight_text::<PendingInput>(
19819                ranges,
19820                HighlightStyle {
19821                    underline: Some(UnderlineStyle {
19822                        thickness: px(1.),
19823                        color: None,
19824                        wavy: false,
19825                    }),
19826                    ..Default::default()
19827                },
19828                cx,
19829            );
19830        }
19831
19832        self.ime_transaction = self.ime_transaction.or(transaction);
19833        if let Some(transaction) = self.ime_transaction {
19834            self.buffer.update(cx, |buffer, cx| {
19835                buffer.group_until_transaction(transaction, cx);
19836            });
19837        }
19838
19839        if self.text_highlights::<PendingInput>(cx).is_none() {
19840            self.ime_transaction.take();
19841        }
19842    }
19843
19844    pub fn register_action_renderer(
19845        &mut self,
19846        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
19847    ) -> Subscription {
19848        let id = self.next_editor_action_id.post_inc();
19849        self.editor_actions
19850            .borrow_mut()
19851            .insert(id, Box::new(listener));
19852
19853        let editor_actions = self.editor_actions.clone();
19854        Subscription::new(move || {
19855            editor_actions.borrow_mut().remove(&id);
19856        })
19857    }
19858
19859    pub fn register_action<A: Action>(
19860        &mut self,
19861        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19862    ) -> Subscription {
19863        let id = self.next_editor_action_id.post_inc();
19864        let listener = Arc::new(listener);
19865        self.editor_actions.borrow_mut().insert(
19866            id,
19867            Box::new(move |_, window, _| {
19868                let listener = listener.clone();
19869                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19870                    let action = action.downcast_ref().unwrap();
19871                    if phase == DispatchPhase::Bubble {
19872                        listener(action, window, cx)
19873                    }
19874                })
19875            }),
19876        );
19877
19878        let editor_actions = self.editor_actions.clone();
19879        Subscription::new(move || {
19880            editor_actions.borrow_mut().remove(&id);
19881        })
19882    }
19883
19884    pub fn file_header_size(&self) -> u32 {
19885        FILE_HEADER_HEIGHT
19886    }
19887
19888    pub fn restore(
19889        &mut self,
19890        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19891        window: &mut Window,
19892        cx: &mut Context<Self>,
19893    ) {
19894        let workspace = self.workspace();
19895        let project = self.project.as_ref();
19896        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19897            let mut tasks = Vec::new();
19898            for (buffer_id, changes) in revert_changes {
19899                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19900                    buffer.update(cx, |buffer, cx| {
19901                        buffer.edit(
19902                            changes
19903                                .into_iter()
19904                                .map(|(range, text)| (range, text.to_string())),
19905                            None,
19906                            cx,
19907                        );
19908                    });
19909
19910                    if let Some(project) =
19911                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19912                    {
19913                        project.update(cx, |project, cx| {
19914                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19915                        })
19916                    }
19917                }
19918            }
19919            tasks
19920        });
19921        cx.spawn_in(window, async move |_, cx| {
19922            for (buffer, task) in save_tasks {
19923                let result = task.await;
19924                if result.is_err() {
19925                    let Some(path) = buffer
19926                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19927                        .ok()
19928                    else {
19929                        continue;
19930                    };
19931                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19932                        let Some(task) = cx
19933                            .update_window_entity(&workspace, |workspace, window, cx| {
19934                                workspace
19935                                    .open_path_preview(path, None, false, false, false, window, cx)
19936                            })
19937                            .ok()
19938                        else {
19939                            continue;
19940                        };
19941                        task.await.log_err();
19942                    }
19943                }
19944            }
19945        })
19946        .detach();
19947        self.change_selections(None, window, cx, |selections| selections.refresh());
19948    }
19949
19950    pub fn to_pixel_point(
19951        &self,
19952        source: multi_buffer::Anchor,
19953        editor_snapshot: &EditorSnapshot,
19954        window: &mut Window,
19955    ) -> Option<gpui::Point<Pixels>> {
19956        let source_point = source.to_display_point(editor_snapshot);
19957        self.display_to_pixel_point(source_point, editor_snapshot, window)
19958    }
19959
19960    pub fn display_to_pixel_point(
19961        &self,
19962        source: DisplayPoint,
19963        editor_snapshot: &EditorSnapshot,
19964        window: &mut Window,
19965    ) -> Option<gpui::Point<Pixels>> {
19966        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19967        let text_layout_details = self.text_layout_details(window);
19968        let scroll_top = text_layout_details
19969            .scroll_anchor
19970            .scroll_position(editor_snapshot)
19971            .y;
19972
19973        if source.row().as_f32() < scroll_top.floor() {
19974            return None;
19975        }
19976        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19977        let source_y = line_height * (source.row().as_f32() - scroll_top);
19978        Some(gpui::Point::new(source_x, source_y))
19979    }
19980
19981    pub fn has_visible_completions_menu(&self) -> bool {
19982        !self.edit_prediction_preview_is_active()
19983            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19984                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19985            })
19986    }
19987
19988    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19989        if self.mode.is_minimap() {
19990            return;
19991        }
19992        self.addons
19993            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19994    }
19995
19996    pub fn unregister_addon<T: Addon>(&mut self) {
19997        self.addons.remove(&std::any::TypeId::of::<T>());
19998    }
19999
20000    pub fn addon<T: Addon>(&self) -> Option<&T> {
20001        let type_id = std::any::TypeId::of::<T>();
20002        self.addons
20003            .get(&type_id)
20004            .and_then(|item| item.to_any().downcast_ref::<T>())
20005    }
20006
20007    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20008        let type_id = std::any::TypeId::of::<T>();
20009        self.addons
20010            .get_mut(&type_id)
20011            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20012    }
20013
20014    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20015        let text_layout_details = self.text_layout_details(window);
20016        let style = &text_layout_details.editor_style;
20017        let font_id = window.text_system().resolve_font(&style.text.font());
20018        let font_size = style.text.font_size.to_pixels(window.rem_size());
20019        let line_height = style.text.line_height_in_pixels(window.rem_size());
20020        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20021
20022        gpui::Size::new(em_width, line_height)
20023    }
20024
20025    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20026        self.load_diff_task.clone()
20027    }
20028
20029    fn read_metadata_from_db(
20030        &mut self,
20031        item_id: u64,
20032        workspace_id: WorkspaceId,
20033        window: &mut Window,
20034        cx: &mut Context<Editor>,
20035    ) {
20036        if self.is_singleton(cx)
20037            && !self.mode.is_minimap()
20038            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20039        {
20040            let buffer_snapshot = OnceCell::new();
20041
20042            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20043                if !folds.is_empty() {
20044                    let snapshot =
20045                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20046                    self.fold_ranges(
20047                        folds
20048                            .into_iter()
20049                            .map(|(start, end)| {
20050                                snapshot.clip_offset(start, Bias::Left)
20051                                    ..snapshot.clip_offset(end, Bias::Right)
20052                            })
20053                            .collect(),
20054                        false,
20055                        window,
20056                        cx,
20057                    );
20058                }
20059            }
20060
20061            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20062                if !selections.is_empty() {
20063                    let snapshot =
20064                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20065                    // skip adding the initial selection to selection history
20066                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20067                    self.change_selections(None, window, cx, |s| {
20068                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20069                            snapshot.clip_offset(start, Bias::Left)
20070                                ..snapshot.clip_offset(end, Bias::Right)
20071                        }));
20072                    });
20073                    self.selection_history.mode = SelectionHistoryMode::Normal;
20074                }
20075            };
20076        }
20077
20078        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20079    }
20080}
20081
20082fn vim_enabled(cx: &App) -> bool {
20083    cx.global::<SettingsStore>()
20084        .raw_user_settings()
20085        .get("vim_mode")
20086        == Some(&serde_json::Value::Bool(true))
20087}
20088
20089fn process_completion_for_edit(
20090    completion: &Completion,
20091    intent: CompletionIntent,
20092    buffer: &Entity<Buffer>,
20093    cursor_position: &text::Anchor,
20094    cx: &mut Context<Editor>,
20095) -> CompletionEdit {
20096    let buffer = buffer.read(cx);
20097    let buffer_snapshot = buffer.snapshot();
20098    let (snippet, new_text) = if completion.is_snippet() {
20099        // Workaround for typescript language server issues so that methods don't expand within
20100        // strings and functions with type expressions. The previous point is used because the query
20101        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20102        let mut snippet_source = completion.new_text.clone();
20103        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20104        previous_point.column = previous_point.column.saturating_sub(1);
20105        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20106            if scope.prefers_label_for_snippet_in_completion() {
20107                if let Some(label) = completion.label() {
20108                    if matches!(
20109                        completion.kind(),
20110                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20111                    ) {
20112                        snippet_source = label;
20113                    }
20114                }
20115            }
20116        }
20117        match Snippet::parse(&snippet_source).log_err() {
20118            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20119            None => (None, completion.new_text.clone()),
20120        }
20121    } else {
20122        (None, completion.new_text.clone())
20123    };
20124
20125    let mut range_to_replace = {
20126        let replace_range = &completion.replace_range;
20127        if let CompletionSource::Lsp {
20128            insert_range: Some(insert_range),
20129            ..
20130        } = &completion.source
20131        {
20132            debug_assert_eq!(
20133                insert_range.start, replace_range.start,
20134                "insert_range and replace_range should start at the same position"
20135            );
20136            debug_assert!(
20137                insert_range
20138                    .start
20139                    .cmp(&cursor_position, &buffer_snapshot)
20140                    .is_le(),
20141                "insert_range should start before or at cursor position"
20142            );
20143            debug_assert!(
20144                replace_range
20145                    .start
20146                    .cmp(&cursor_position, &buffer_snapshot)
20147                    .is_le(),
20148                "replace_range should start before or at cursor position"
20149            );
20150            debug_assert!(
20151                insert_range
20152                    .end
20153                    .cmp(&cursor_position, &buffer_snapshot)
20154                    .is_le(),
20155                "insert_range should end before or at cursor position"
20156            );
20157
20158            let should_replace = match intent {
20159                CompletionIntent::CompleteWithInsert => false,
20160                CompletionIntent::CompleteWithReplace => true,
20161                CompletionIntent::Complete | CompletionIntent::Compose => {
20162                    let insert_mode =
20163                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20164                            .completions
20165                            .lsp_insert_mode;
20166                    match insert_mode {
20167                        LspInsertMode::Insert => false,
20168                        LspInsertMode::Replace => true,
20169                        LspInsertMode::ReplaceSubsequence => {
20170                            let mut text_to_replace = buffer.chars_for_range(
20171                                buffer.anchor_before(replace_range.start)
20172                                    ..buffer.anchor_after(replace_range.end),
20173                            );
20174                            let mut current_needle = text_to_replace.next();
20175                            for haystack_ch in completion.label.text.chars() {
20176                                if let Some(needle_ch) = current_needle {
20177                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20178                                        current_needle = text_to_replace.next();
20179                                    }
20180                                }
20181                            }
20182                            current_needle.is_none()
20183                        }
20184                        LspInsertMode::ReplaceSuffix => {
20185                            if replace_range
20186                                .end
20187                                .cmp(&cursor_position, &buffer_snapshot)
20188                                .is_gt()
20189                            {
20190                                let range_after_cursor = *cursor_position..replace_range.end;
20191                                let text_after_cursor = buffer
20192                                    .text_for_range(
20193                                        buffer.anchor_before(range_after_cursor.start)
20194                                            ..buffer.anchor_after(range_after_cursor.end),
20195                                    )
20196                                    .collect::<String>()
20197                                    .to_ascii_lowercase();
20198                                completion
20199                                    .label
20200                                    .text
20201                                    .to_ascii_lowercase()
20202                                    .ends_with(&text_after_cursor)
20203                            } else {
20204                                true
20205                            }
20206                        }
20207                    }
20208                }
20209            };
20210
20211            if should_replace {
20212                replace_range.clone()
20213            } else {
20214                insert_range.clone()
20215            }
20216        } else {
20217            replace_range.clone()
20218        }
20219    };
20220
20221    if range_to_replace
20222        .end
20223        .cmp(&cursor_position, &buffer_snapshot)
20224        .is_lt()
20225    {
20226        range_to_replace.end = *cursor_position;
20227    }
20228
20229    CompletionEdit {
20230        new_text,
20231        replace_range: range_to_replace.to_offset(&buffer),
20232        snippet,
20233    }
20234}
20235
20236struct CompletionEdit {
20237    new_text: String,
20238    replace_range: Range<usize>,
20239    snippet: Option<Snippet>,
20240}
20241
20242fn insert_extra_newline_brackets(
20243    buffer: &MultiBufferSnapshot,
20244    range: Range<usize>,
20245    language: &language::LanguageScope,
20246) -> bool {
20247    let leading_whitespace_len = buffer
20248        .reversed_chars_at(range.start)
20249        .take_while(|c| c.is_whitespace() && *c != '\n')
20250        .map(|c| c.len_utf8())
20251        .sum::<usize>();
20252    let trailing_whitespace_len = buffer
20253        .chars_at(range.end)
20254        .take_while(|c| c.is_whitespace() && *c != '\n')
20255        .map(|c| c.len_utf8())
20256        .sum::<usize>();
20257    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20258
20259    language.brackets().any(|(pair, enabled)| {
20260        let pair_start = pair.start.trim_end();
20261        let pair_end = pair.end.trim_start();
20262
20263        enabled
20264            && pair.newline
20265            && buffer.contains_str_at(range.end, pair_end)
20266            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20267    })
20268}
20269
20270fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20271    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20272        [(buffer, range, _)] => (*buffer, range.clone()),
20273        _ => return false,
20274    };
20275    let pair = {
20276        let mut result: Option<BracketMatch> = None;
20277
20278        for pair in buffer
20279            .all_bracket_ranges(range.clone())
20280            .filter(move |pair| {
20281                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20282            })
20283        {
20284            let len = pair.close_range.end - pair.open_range.start;
20285
20286            if let Some(existing) = &result {
20287                let existing_len = existing.close_range.end - existing.open_range.start;
20288                if len > existing_len {
20289                    continue;
20290                }
20291            }
20292
20293            result = Some(pair);
20294        }
20295
20296        result
20297    };
20298    let Some(pair) = pair else {
20299        return false;
20300    };
20301    pair.newline_only
20302        && buffer
20303            .chars_for_range(pair.open_range.end..range.start)
20304            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20305            .all(|c| c.is_whitespace() && c != '\n')
20306}
20307
20308fn update_uncommitted_diff_for_buffer(
20309    editor: Entity<Editor>,
20310    project: &Entity<Project>,
20311    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20312    buffer: Entity<MultiBuffer>,
20313    cx: &mut App,
20314) -> Task<()> {
20315    let mut tasks = Vec::new();
20316    project.update(cx, |project, cx| {
20317        for buffer in buffers {
20318            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20319                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20320            }
20321        }
20322    });
20323    cx.spawn(async move |cx| {
20324        let diffs = future::join_all(tasks).await;
20325        if editor
20326            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20327            .unwrap_or(false)
20328        {
20329            return;
20330        }
20331
20332        buffer
20333            .update(cx, |buffer, cx| {
20334                for diff in diffs.into_iter().flatten() {
20335                    buffer.add_diff(diff, cx);
20336                }
20337            })
20338            .ok();
20339    })
20340}
20341
20342fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20343    let tab_size = tab_size.get() as usize;
20344    let mut width = offset;
20345
20346    for ch in text.chars() {
20347        width += if ch == '\t' {
20348            tab_size - (width % tab_size)
20349        } else {
20350            1
20351        };
20352    }
20353
20354    width - offset
20355}
20356
20357#[cfg(test)]
20358mod tests {
20359    use super::*;
20360
20361    #[test]
20362    fn test_string_size_with_expanded_tabs() {
20363        let nz = |val| NonZeroU32::new(val).unwrap();
20364        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20365        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20366        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20367        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20368        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20369        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20370        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20371        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20372    }
20373}
20374
20375/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20376struct WordBreakingTokenizer<'a> {
20377    input: &'a str,
20378}
20379
20380impl<'a> WordBreakingTokenizer<'a> {
20381    fn new(input: &'a str) -> Self {
20382        Self { input }
20383    }
20384}
20385
20386fn is_char_ideographic(ch: char) -> bool {
20387    use unicode_script::Script::*;
20388    use unicode_script::UnicodeScript;
20389    matches!(ch.script(), Han | Tangut | Yi)
20390}
20391
20392fn is_grapheme_ideographic(text: &str) -> bool {
20393    text.chars().any(is_char_ideographic)
20394}
20395
20396fn is_grapheme_whitespace(text: &str) -> bool {
20397    text.chars().any(|x| x.is_whitespace())
20398}
20399
20400fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20401    text.chars().next().map_or(false, |ch| {
20402        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20403    })
20404}
20405
20406#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20407enum WordBreakToken<'a> {
20408    Word { token: &'a str, grapheme_len: usize },
20409    InlineWhitespace { token: &'a str, grapheme_len: usize },
20410    Newline,
20411}
20412
20413impl<'a> Iterator for WordBreakingTokenizer<'a> {
20414    /// Yields a span, the count of graphemes in the token, and whether it was
20415    /// whitespace. Note that it also breaks at word boundaries.
20416    type Item = WordBreakToken<'a>;
20417
20418    fn next(&mut self) -> Option<Self::Item> {
20419        use unicode_segmentation::UnicodeSegmentation;
20420        if self.input.is_empty() {
20421            return None;
20422        }
20423
20424        let mut iter = self.input.graphemes(true).peekable();
20425        let mut offset = 0;
20426        let mut grapheme_len = 0;
20427        if let Some(first_grapheme) = iter.next() {
20428            let is_newline = first_grapheme == "\n";
20429            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20430            offset += first_grapheme.len();
20431            grapheme_len += 1;
20432            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20433                if let Some(grapheme) = iter.peek().copied() {
20434                    if should_stay_with_preceding_ideograph(grapheme) {
20435                        offset += grapheme.len();
20436                        grapheme_len += 1;
20437                    }
20438                }
20439            } else {
20440                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20441                let mut next_word_bound = words.peek().copied();
20442                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20443                    next_word_bound = words.next();
20444                }
20445                while let Some(grapheme) = iter.peek().copied() {
20446                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20447                        break;
20448                    };
20449                    if is_grapheme_whitespace(grapheme) != is_whitespace
20450                        || (grapheme == "\n") != is_newline
20451                    {
20452                        break;
20453                    };
20454                    offset += grapheme.len();
20455                    grapheme_len += 1;
20456                    iter.next();
20457                }
20458            }
20459            let token = &self.input[..offset];
20460            self.input = &self.input[offset..];
20461            if token == "\n" {
20462                Some(WordBreakToken::Newline)
20463            } else if is_whitespace {
20464                Some(WordBreakToken::InlineWhitespace {
20465                    token,
20466                    grapheme_len,
20467                })
20468            } else {
20469                Some(WordBreakToken::Word {
20470                    token,
20471                    grapheme_len,
20472                })
20473            }
20474        } else {
20475            None
20476        }
20477    }
20478}
20479
20480#[test]
20481fn test_word_breaking_tokenizer() {
20482    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20483        ("", &[]),
20484        ("  ", &[whitespace("  ", 2)]),
20485        ("Ʒ", &[word("Ʒ", 1)]),
20486        ("Ǽ", &[word("Ǽ", 1)]),
20487        ("", &[word("", 1)]),
20488        ("⋑⋑", &[word("⋑⋑", 2)]),
20489        (
20490            "原理,进而",
20491            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20492        ),
20493        (
20494            "hello world",
20495            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20496        ),
20497        (
20498            "hello, world",
20499            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20500        ),
20501        (
20502            "  hello world",
20503            &[
20504                whitespace("  ", 2),
20505                word("hello", 5),
20506                whitespace(" ", 1),
20507                word("world", 5),
20508            ],
20509        ),
20510        (
20511            "这是什么 \n 钢笔",
20512            &[
20513                word("", 1),
20514                word("", 1),
20515                word("", 1),
20516                word("", 1),
20517                whitespace(" ", 1),
20518                newline(),
20519                whitespace(" ", 1),
20520                word("", 1),
20521                word("", 1),
20522            ],
20523        ),
20524        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20525    ];
20526
20527    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20528        WordBreakToken::Word {
20529            token,
20530            grapheme_len,
20531        }
20532    }
20533
20534    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20535        WordBreakToken::InlineWhitespace {
20536            token,
20537            grapheme_len,
20538        }
20539    }
20540
20541    fn newline() -> WordBreakToken<'static> {
20542        WordBreakToken::Newline
20543    }
20544
20545    for (input, result) in tests {
20546        assert_eq!(
20547            WordBreakingTokenizer::new(input)
20548                .collect::<Vec<_>>()
20549                .as_slice(),
20550            *result,
20551        );
20552    }
20553}
20554
20555fn wrap_with_prefix(
20556    line_prefix: String,
20557    unwrapped_text: String,
20558    wrap_column: usize,
20559    tab_size: NonZeroU32,
20560    preserve_existing_whitespace: bool,
20561) -> String {
20562    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20563    let mut wrapped_text = String::new();
20564    let mut current_line = line_prefix.clone();
20565
20566    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20567    let mut current_line_len = line_prefix_len;
20568    let mut in_whitespace = false;
20569    for token in tokenizer {
20570        let have_preceding_whitespace = in_whitespace;
20571        match token {
20572            WordBreakToken::Word {
20573                token,
20574                grapheme_len,
20575            } => {
20576                in_whitespace = false;
20577                if current_line_len + grapheme_len > wrap_column
20578                    && current_line_len != line_prefix_len
20579                {
20580                    wrapped_text.push_str(current_line.trim_end());
20581                    wrapped_text.push('\n');
20582                    current_line.truncate(line_prefix.len());
20583                    current_line_len = line_prefix_len;
20584                }
20585                current_line.push_str(token);
20586                current_line_len += grapheme_len;
20587            }
20588            WordBreakToken::InlineWhitespace {
20589                mut token,
20590                mut grapheme_len,
20591            } => {
20592                in_whitespace = true;
20593                if have_preceding_whitespace && !preserve_existing_whitespace {
20594                    continue;
20595                }
20596                if !preserve_existing_whitespace {
20597                    token = " ";
20598                    grapheme_len = 1;
20599                }
20600                if current_line_len + grapheme_len > wrap_column {
20601                    wrapped_text.push_str(current_line.trim_end());
20602                    wrapped_text.push('\n');
20603                    current_line.truncate(line_prefix.len());
20604                    current_line_len = line_prefix_len;
20605                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20606                    current_line.push_str(token);
20607                    current_line_len += grapheme_len;
20608                }
20609            }
20610            WordBreakToken::Newline => {
20611                in_whitespace = true;
20612                if preserve_existing_whitespace {
20613                    wrapped_text.push_str(current_line.trim_end());
20614                    wrapped_text.push('\n');
20615                    current_line.truncate(line_prefix.len());
20616                    current_line_len = line_prefix_len;
20617                } else if have_preceding_whitespace {
20618                    continue;
20619                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20620                {
20621                    wrapped_text.push_str(current_line.trim_end());
20622                    wrapped_text.push('\n');
20623                    current_line.truncate(line_prefix.len());
20624                    current_line_len = line_prefix_len;
20625                } else if current_line_len != line_prefix_len {
20626                    current_line.push(' ');
20627                    current_line_len += 1;
20628                }
20629            }
20630        }
20631    }
20632
20633    if !current_line.is_empty() {
20634        wrapped_text.push_str(&current_line);
20635    }
20636    wrapped_text
20637}
20638
20639#[test]
20640fn test_wrap_with_prefix() {
20641    assert_eq!(
20642        wrap_with_prefix(
20643            "# ".to_string(),
20644            "abcdefg".to_string(),
20645            4,
20646            NonZeroU32::new(4).unwrap(),
20647            false,
20648        ),
20649        "# abcdefg"
20650    );
20651    assert_eq!(
20652        wrap_with_prefix(
20653            "".to_string(),
20654            "\thello world".to_string(),
20655            8,
20656            NonZeroU32::new(4).unwrap(),
20657            false,
20658        ),
20659        "hello\nworld"
20660    );
20661    assert_eq!(
20662        wrap_with_prefix(
20663            "// ".to_string(),
20664            "xx \nyy zz aa bb cc".to_string(),
20665            12,
20666            NonZeroU32::new(4).unwrap(),
20667            false,
20668        ),
20669        "// xx yy zz\n// aa bb cc"
20670    );
20671    assert_eq!(
20672        wrap_with_prefix(
20673            String::new(),
20674            "这是什么 \n 钢笔".to_string(),
20675            3,
20676            NonZeroU32::new(4).unwrap(),
20677            false,
20678        ),
20679        "这是什\n么 钢\n"
20680    );
20681}
20682
20683pub trait CollaborationHub {
20684    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20685    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20686    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20687}
20688
20689impl CollaborationHub for Entity<Project> {
20690    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20691        self.read(cx).collaborators()
20692    }
20693
20694    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20695        self.read(cx).user_store().read(cx).participant_indices()
20696    }
20697
20698    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20699        let this = self.read(cx);
20700        let user_ids = this.collaborators().values().map(|c| c.user_id);
20701        this.user_store().read(cx).participant_names(user_ids, cx)
20702    }
20703}
20704
20705pub trait SemanticsProvider {
20706    fn hover(
20707        &self,
20708        buffer: &Entity<Buffer>,
20709        position: text::Anchor,
20710        cx: &mut App,
20711    ) -> Option<Task<Vec<project::Hover>>>;
20712
20713    fn inline_values(
20714        &self,
20715        buffer_handle: Entity<Buffer>,
20716        range: Range<text::Anchor>,
20717        cx: &mut App,
20718    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20719
20720    fn inlay_hints(
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 resolve_inlay_hint(
20728        &self,
20729        hint: InlayHint,
20730        buffer_handle: Entity<Buffer>,
20731        server_id: LanguageServerId,
20732        cx: &mut App,
20733    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20734
20735    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20736
20737    fn document_highlights(
20738        &self,
20739        buffer: &Entity<Buffer>,
20740        position: text::Anchor,
20741        cx: &mut App,
20742    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20743
20744    fn definitions(
20745        &self,
20746        buffer: &Entity<Buffer>,
20747        position: text::Anchor,
20748        kind: GotoDefinitionKind,
20749        cx: &mut App,
20750    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20751
20752    fn range_for_rename(
20753        &self,
20754        buffer: &Entity<Buffer>,
20755        position: text::Anchor,
20756        cx: &mut App,
20757    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20758
20759    fn perform_rename(
20760        &self,
20761        buffer: &Entity<Buffer>,
20762        position: text::Anchor,
20763        new_name: String,
20764        cx: &mut App,
20765    ) -> Option<Task<Result<ProjectTransaction>>>;
20766
20767    fn pull_diagnostics_for_buffer(
20768        &self,
20769        buffer: Entity<Buffer>,
20770        cx: &mut App,
20771    ) -> Task<anyhow::Result<()>>;
20772}
20773
20774pub trait CompletionProvider {
20775    fn completions(
20776        &self,
20777        excerpt_id: ExcerptId,
20778        buffer: &Entity<Buffer>,
20779        buffer_position: text::Anchor,
20780        trigger: CompletionContext,
20781        window: &mut Window,
20782        cx: &mut Context<Editor>,
20783    ) -> Task<Result<Vec<CompletionResponse>>>;
20784
20785    fn resolve_completions(
20786        &self,
20787        _buffer: Entity<Buffer>,
20788        _completion_indices: Vec<usize>,
20789        _completions: Rc<RefCell<Box<[Completion]>>>,
20790        _cx: &mut Context<Editor>,
20791    ) -> Task<Result<bool>> {
20792        Task::ready(Ok(false))
20793    }
20794
20795    fn apply_additional_edits_for_completion(
20796        &self,
20797        _buffer: Entity<Buffer>,
20798        _completions: Rc<RefCell<Box<[Completion]>>>,
20799        _completion_index: usize,
20800        _push_to_history: bool,
20801        _cx: &mut Context<Editor>,
20802    ) -> Task<Result<Option<language::Transaction>>> {
20803        Task::ready(Ok(None))
20804    }
20805
20806    fn is_completion_trigger(
20807        &self,
20808        buffer: &Entity<Buffer>,
20809        position: language::Anchor,
20810        text: &str,
20811        trigger_in_words: bool,
20812        menu_is_open: bool,
20813        cx: &mut Context<Editor>,
20814    ) -> bool;
20815
20816    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20817
20818    fn sort_completions(&self) -> bool {
20819        true
20820    }
20821
20822    fn filter_completions(&self) -> bool {
20823        true
20824    }
20825}
20826
20827pub trait CodeActionProvider {
20828    fn id(&self) -> Arc<str>;
20829
20830    fn code_actions(
20831        &self,
20832        buffer: &Entity<Buffer>,
20833        range: Range<text::Anchor>,
20834        window: &mut Window,
20835        cx: &mut App,
20836    ) -> Task<Result<Vec<CodeAction>>>;
20837
20838    fn apply_code_action(
20839        &self,
20840        buffer_handle: Entity<Buffer>,
20841        action: CodeAction,
20842        excerpt_id: ExcerptId,
20843        push_to_history: bool,
20844        window: &mut Window,
20845        cx: &mut App,
20846    ) -> Task<Result<ProjectTransaction>>;
20847}
20848
20849impl CodeActionProvider for Entity<Project> {
20850    fn id(&self) -> Arc<str> {
20851        "project".into()
20852    }
20853
20854    fn code_actions(
20855        &self,
20856        buffer: &Entity<Buffer>,
20857        range: Range<text::Anchor>,
20858        _window: &mut Window,
20859        cx: &mut App,
20860    ) -> Task<Result<Vec<CodeAction>>> {
20861        self.update(cx, |project, cx| {
20862            let code_lens = project.code_lens(buffer, range.clone(), cx);
20863            let code_actions = project.code_actions(buffer, range, None, cx);
20864            cx.background_spawn(async move {
20865                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20866                Ok(code_lens
20867                    .context("code lens fetch")?
20868                    .into_iter()
20869                    .chain(code_actions.context("code action fetch")?)
20870                    .collect())
20871            })
20872        })
20873    }
20874
20875    fn apply_code_action(
20876        &self,
20877        buffer_handle: Entity<Buffer>,
20878        action: CodeAction,
20879        _excerpt_id: ExcerptId,
20880        push_to_history: bool,
20881        _window: &mut Window,
20882        cx: &mut App,
20883    ) -> Task<Result<ProjectTransaction>> {
20884        self.update(cx, |project, cx| {
20885            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20886        })
20887    }
20888}
20889
20890fn snippet_completions(
20891    project: &Project,
20892    buffer: &Entity<Buffer>,
20893    buffer_position: text::Anchor,
20894    cx: &mut App,
20895) -> Task<Result<CompletionResponse>> {
20896    let languages = buffer.read(cx).languages_at(buffer_position);
20897    let snippet_store = project.snippets().read(cx);
20898
20899    let scopes: Vec<_> = languages
20900        .iter()
20901        .filter_map(|language| {
20902            let language_name = language.lsp_id();
20903            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20904
20905            if snippets.is_empty() {
20906                None
20907            } else {
20908                Some((language.default_scope(), snippets))
20909            }
20910        })
20911        .collect();
20912
20913    if scopes.is_empty() {
20914        return Task::ready(Ok(CompletionResponse {
20915            completions: vec![],
20916            is_incomplete: false,
20917        }));
20918    }
20919
20920    let snapshot = buffer.read(cx).text_snapshot();
20921    let chars: String = snapshot
20922        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20923        .collect();
20924    let executor = cx.background_executor().clone();
20925
20926    cx.background_spawn(async move {
20927        let mut is_incomplete = false;
20928        let mut completions: Vec<Completion> = Vec::new();
20929        for (scope, snippets) in scopes.into_iter() {
20930            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20931            let mut last_word = chars
20932                .chars()
20933                .take_while(|c| classifier.is_word(*c))
20934                .collect::<String>();
20935            last_word = last_word.chars().rev().collect();
20936
20937            if last_word.is_empty() {
20938                return Ok(CompletionResponse {
20939                    completions: vec![],
20940                    is_incomplete: true,
20941                });
20942            }
20943
20944            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20945            let to_lsp = |point: &text::Anchor| {
20946                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20947                point_to_lsp(end)
20948            };
20949            let lsp_end = to_lsp(&buffer_position);
20950
20951            let candidates = snippets
20952                .iter()
20953                .enumerate()
20954                .flat_map(|(ix, snippet)| {
20955                    snippet
20956                        .prefix
20957                        .iter()
20958                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20959                })
20960                .collect::<Vec<StringMatchCandidate>>();
20961
20962            const MAX_RESULTS: usize = 100;
20963            let mut matches = fuzzy::match_strings(
20964                &candidates,
20965                &last_word,
20966                last_word.chars().any(|c| c.is_uppercase()),
20967                MAX_RESULTS,
20968                &Default::default(),
20969                executor.clone(),
20970            )
20971            .await;
20972
20973            if matches.len() >= MAX_RESULTS {
20974                is_incomplete = true;
20975            }
20976
20977            // Remove all candidates where the query's start does not match the start of any word in the candidate
20978            if let Some(query_start) = last_word.chars().next() {
20979                matches.retain(|string_match| {
20980                    split_words(&string_match.string).any(|word| {
20981                        // Check that the first codepoint of the word as lowercase matches the first
20982                        // codepoint of the query as lowercase
20983                        word.chars()
20984                            .flat_map(|codepoint| codepoint.to_lowercase())
20985                            .zip(query_start.to_lowercase())
20986                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20987                    })
20988                });
20989            }
20990
20991            let matched_strings = matches
20992                .into_iter()
20993                .map(|m| m.string)
20994                .collect::<HashSet<_>>();
20995
20996            completions.extend(snippets.iter().filter_map(|snippet| {
20997                let matching_prefix = snippet
20998                    .prefix
20999                    .iter()
21000                    .find(|prefix| matched_strings.contains(*prefix))?;
21001                let start = as_offset - last_word.len();
21002                let start = snapshot.anchor_before(start);
21003                let range = start..buffer_position;
21004                let lsp_start = to_lsp(&start);
21005                let lsp_range = lsp::Range {
21006                    start: lsp_start,
21007                    end: lsp_end,
21008                };
21009                Some(Completion {
21010                    replace_range: range,
21011                    new_text: snippet.body.clone(),
21012                    source: CompletionSource::Lsp {
21013                        insert_range: None,
21014                        server_id: LanguageServerId(usize::MAX),
21015                        resolved: true,
21016                        lsp_completion: Box::new(lsp::CompletionItem {
21017                            label: snippet.prefix.first().unwrap().clone(),
21018                            kind: Some(CompletionItemKind::SNIPPET),
21019                            label_details: snippet.description.as_ref().map(|description| {
21020                                lsp::CompletionItemLabelDetails {
21021                                    detail: Some(description.clone()),
21022                                    description: None,
21023                                }
21024                            }),
21025                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21026                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21027                                lsp::InsertReplaceEdit {
21028                                    new_text: snippet.body.clone(),
21029                                    insert: lsp_range,
21030                                    replace: lsp_range,
21031                                },
21032                            )),
21033                            filter_text: Some(snippet.body.clone()),
21034                            sort_text: Some(char::MAX.to_string()),
21035                            ..lsp::CompletionItem::default()
21036                        }),
21037                        lsp_defaults: None,
21038                    },
21039                    label: CodeLabel {
21040                        text: matching_prefix.clone(),
21041                        runs: Vec::new(),
21042                        filter_range: 0..matching_prefix.len(),
21043                    },
21044                    icon_path: None,
21045                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21046                        single_line: snippet.name.clone().into(),
21047                        plain_text: snippet
21048                            .description
21049                            .clone()
21050                            .map(|description| description.into()),
21051                    }),
21052                    insert_text_mode: None,
21053                    confirm: None,
21054                })
21055            }))
21056        }
21057
21058        Ok(CompletionResponse {
21059            completions,
21060            is_incomplete,
21061        })
21062    })
21063}
21064
21065impl CompletionProvider for Entity<Project> {
21066    fn completions(
21067        &self,
21068        _excerpt_id: ExcerptId,
21069        buffer: &Entity<Buffer>,
21070        buffer_position: text::Anchor,
21071        options: CompletionContext,
21072        _window: &mut Window,
21073        cx: &mut Context<Editor>,
21074    ) -> Task<Result<Vec<CompletionResponse>>> {
21075        self.update(cx, |project, cx| {
21076            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21077            let project_completions = project.completions(buffer, buffer_position, options, cx);
21078            cx.background_spawn(async move {
21079                let mut responses = project_completions.await?;
21080                let snippets = snippets.await?;
21081                if !snippets.completions.is_empty() {
21082                    responses.push(snippets);
21083                }
21084                Ok(responses)
21085            })
21086        })
21087    }
21088
21089    fn resolve_completions(
21090        &self,
21091        buffer: Entity<Buffer>,
21092        completion_indices: Vec<usize>,
21093        completions: Rc<RefCell<Box<[Completion]>>>,
21094        cx: &mut Context<Editor>,
21095    ) -> Task<Result<bool>> {
21096        self.update(cx, |project, cx| {
21097            project.lsp_store().update(cx, |lsp_store, cx| {
21098                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21099            })
21100        })
21101    }
21102
21103    fn apply_additional_edits_for_completion(
21104        &self,
21105        buffer: Entity<Buffer>,
21106        completions: Rc<RefCell<Box<[Completion]>>>,
21107        completion_index: usize,
21108        push_to_history: bool,
21109        cx: &mut Context<Editor>,
21110    ) -> Task<Result<Option<language::Transaction>>> {
21111        self.update(cx, |project, cx| {
21112            project.lsp_store().update(cx, |lsp_store, cx| {
21113                lsp_store.apply_additional_edits_for_completion(
21114                    buffer,
21115                    completions,
21116                    completion_index,
21117                    push_to_history,
21118                    cx,
21119                )
21120            })
21121        })
21122    }
21123
21124    fn is_completion_trigger(
21125        &self,
21126        buffer: &Entity<Buffer>,
21127        position: language::Anchor,
21128        text: &str,
21129        trigger_in_words: bool,
21130        menu_is_open: bool,
21131        cx: &mut Context<Editor>,
21132    ) -> bool {
21133        let mut chars = text.chars();
21134        let char = if let Some(char) = chars.next() {
21135            char
21136        } else {
21137            return false;
21138        };
21139        if chars.next().is_some() {
21140            return false;
21141        }
21142
21143        let buffer = buffer.read(cx);
21144        let snapshot = buffer.snapshot();
21145        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21146            return false;
21147        }
21148        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21149        if trigger_in_words && classifier.is_word(char) {
21150            return true;
21151        }
21152
21153        buffer.completion_triggers().contains(text)
21154    }
21155}
21156
21157impl SemanticsProvider for Entity<Project> {
21158    fn hover(
21159        &self,
21160        buffer: &Entity<Buffer>,
21161        position: text::Anchor,
21162        cx: &mut App,
21163    ) -> Option<Task<Vec<project::Hover>>> {
21164        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21165    }
21166
21167    fn document_highlights(
21168        &self,
21169        buffer: &Entity<Buffer>,
21170        position: text::Anchor,
21171        cx: &mut App,
21172    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21173        Some(self.update(cx, |project, cx| {
21174            project.document_highlights(buffer, position, cx)
21175        }))
21176    }
21177
21178    fn definitions(
21179        &self,
21180        buffer: &Entity<Buffer>,
21181        position: text::Anchor,
21182        kind: GotoDefinitionKind,
21183        cx: &mut App,
21184    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21185        Some(self.update(cx, |project, cx| match kind {
21186            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21187            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21188            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21189            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21190        }))
21191    }
21192
21193    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21194        // TODO: make this work for remote projects
21195        self.update(cx, |project, cx| {
21196            if project
21197                .active_debug_session(cx)
21198                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21199            {
21200                return true;
21201            }
21202
21203            buffer.update(cx, |buffer, cx| {
21204                project.any_language_server_supports_inlay_hints(buffer, cx)
21205            })
21206        })
21207    }
21208
21209    fn inline_values(
21210        &self,
21211        buffer_handle: Entity<Buffer>,
21212
21213        range: Range<text::Anchor>,
21214        cx: &mut App,
21215    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21216        self.update(cx, |project, cx| {
21217            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21218
21219            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21220        })
21221    }
21222
21223    fn inlay_hints(
21224        &self,
21225        buffer_handle: Entity<Buffer>,
21226        range: Range<text::Anchor>,
21227        cx: &mut App,
21228    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21229        Some(self.update(cx, |project, cx| {
21230            project.inlay_hints(buffer_handle, range, cx)
21231        }))
21232    }
21233
21234    fn resolve_inlay_hint(
21235        &self,
21236        hint: InlayHint,
21237        buffer_handle: Entity<Buffer>,
21238        server_id: LanguageServerId,
21239        cx: &mut App,
21240    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21241        Some(self.update(cx, |project, cx| {
21242            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21243        }))
21244    }
21245
21246    fn range_for_rename(
21247        &self,
21248        buffer: &Entity<Buffer>,
21249        position: text::Anchor,
21250        cx: &mut App,
21251    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21252        Some(self.update(cx, |project, cx| {
21253            let buffer = buffer.clone();
21254            let task = project.prepare_rename(buffer.clone(), position, cx);
21255            cx.spawn(async move |_, cx| {
21256                Ok(match task.await? {
21257                    PrepareRenameResponse::Success(range) => Some(range),
21258                    PrepareRenameResponse::InvalidPosition => None,
21259                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21260                        // Fallback on using TreeSitter info to determine identifier range
21261                        buffer.read_with(cx, |buffer, _| {
21262                            let snapshot = buffer.snapshot();
21263                            let (range, kind) = snapshot.surrounding_word(position);
21264                            if kind != Some(CharKind::Word) {
21265                                return None;
21266                            }
21267                            Some(
21268                                snapshot.anchor_before(range.start)
21269                                    ..snapshot.anchor_after(range.end),
21270                            )
21271                        })?
21272                    }
21273                })
21274            })
21275        }))
21276    }
21277
21278    fn perform_rename(
21279        &self,
21280        buffer: &Entity<Buffer>,
21281        position: text::Anchor,
21282        new_name: String,
21283        cx: &mut App,
21284    ) -> Option<Task<Result<ProjectTransaction>>> {
21285        Some(self.update(cx, |project, cx| {
21286            project.perform_rename(buffer.clone(), position, new_name, cx)
21287        }))
21288    }
21289
21290    fn pull_diagnostics_for_buffer(
21291        &self,
21292        buffer: Entity<Buffer>,
21293        cx: &mut App,
21294    ) -> Task<anyhow::Result<()>> {
21295        let diagnostics = self.update(cx, |project, cx| {
21296            project
21297                .lsp_store()
21298                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21299        });
21300        let project = self.clone();
21301        cx.spawn(async move |cx| {
21302            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21303            project.update(cx, |project, cx| {
21304                project.lsp_store().update(cx, |lsp_store, cx| {
21305                    for diagnostics_set in diagnostics {
21306                        let LspPullDiagnostics::Response {
21307                            server_id,
21308                            uri,
21309                            diagnostics,
21310                        } = diagnostics_set
21311                        else {
21312                            continue;
21313                        };
21314
21315                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21316                        let disk_based_sources = adapter
21317                            .as_ref()
21318                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21319                            .unwrap_or(&[]);
21320                        match diagnostics {
21321                            PulledDiagnostics::Unchanged { result_id } => {
21322                                lsp_store
21323                                    .merge_diagnostics(
21324                                        server_id,
21325                                        lsp::PublishDiagnosticsParams {
21326                                            uri: uri.clone(),
21327                                            diagnostics: Vec::new(),
21328                                            version: None,
21329                                        },
21330                                        Some(result_id),
21331                                        DiagnosticSourceKind::Pulled,
21332                                        disk_based_sources,
21333                                        |_, _| true,
21334                                        cx,
21335                                    )
21336                                    .log_err();
21337                            }
21338                            PulledDiagnostics::Changed {
21339                                diagnostics,
21340                                result_id,
21341                            } => {
21342                                lsp_store
21343                                    .merge_diagnostics(
21344                                        server_id,
21345                                        lsp::PublishDiagnosticsParams {
21346                                            uri: uri.clone(),
21347                                            diagnostics,
21348                                            version: None,
21349                                        },
21350                                        result_id,
21351                                        DiagnosticSourceKind::Pulled,
21352                                        disk_based_sources,
21353                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21354                                            DiagnosticSourceKind::Pulled => false,
21355                                            DiagnosticSourceKind::Other
21356                                            | DiagnosticSourceKind::Pushed => true,
21357                                        },
21358                                        cx,
21359                                    )
21360                                    .log_err();
21361                            }
21362                        }
21363                    }
21364                })
21365            })
21366        })
21367    }
21368}
21369
21370fn inlay_hint_settings(
21371    location: Anchor,
21372    snapshot: &MultiBufferSnapshot,
21373    cx: &mut Context<Editor>,
21374) -> InlayHintSettings {
21375    let file = snapshot.file_at(location);
21376    let language = snapshot.language_at(location).map(|l| l.name());
21377    language_settings(language, file, cx).inlay_hints
21378}
21379
21380fn consume_contiguous_rows(
21381    contiguous_row_selections: &mut Vec<Selection<Point>>,
21382    selection: &Selection<Point>,
21383    display_map: &DisplaySnapshot,
21384    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21385) -> (MultiBufferRow, MultiBufferRow) {
21386    contiguous_row_selections.push(selection.clone());
21387    let start_row = MultiBufferRow(selection.start.row);
21388    let mut end_row = ending_row(selection, display_map);
21389
21390    while let Some(next_selection) = selections.peek() {
21391        if next_selection.start.row <= end_row.0 {
21392            end_row = ending_row(next_selection, display_map);
21393            contiguous_row_selections.push(selections.next().unwrap().clone());
21394        } else {
21395            break;
21396        }
21397    }
21398    (start_row, end_row)
21399}
21400
21401fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21402    if next_selection.end.column > 0 || next_selection.is_empty() {
21403        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21404    } else {
21405        MultiBufferRow(next_selection.end.row)
21406    }
21407}
21408
21409impl EditorSnapshot {
21410    pub fn remote_selections_in_range<'a>(
21411        &'a self,
21412        range: &'a Range<Anchor>,
21413        collaboration_hub: &dyn CollaborationHub,
21414        cx: &'a App,
21415    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21416        let participant_names = collaboration_hub.user_names(cx);
21417        let participant_indices = collaboration_hub.user_participant_indices(cx);
21418        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21419        let collaborators_by_replica_id = collaborators_by_peer_id
21420            .values()
21421            .map(|collaborator| (collaborator.replica_id, collaborator))
21422            .collect::<HashMap<_, _>>();
21423        self.buffer_snapshot
21424            .selections_in_range(range, false)
21425            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21426                if replica_id == AGENT_REPLICA_ID {
21427                    Some(RemoteSelection {
21428                        replica_id,
21429                        selection,
21430                        cursor_shape,
21431                        line_mode,
21432                        collaborator_id: CollaboratorId::Agent,
21433                        user_name: Some("Agent".into()),
21434                        color: cx.theme().players().agent(),
21435                    })
21436                } else {
21437                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21438                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21439                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21440                    Some(RemoteSelection {
21441                        replica_id,
21442                        selection,
21443                        cursor_shape,
21444                        line_mode,
21445                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21446                        user_name,
21447                        color: if let Some(index) = participant_index {
21448                            cx.theme().players().color_for_participant(index.0)
21449                        } else {
21450                            cx.theme().players().absent()
21451                        },
21452                    })
21453                }
21454            })
21455    }
21456
21457    pub fn hunks_for_ranges(
21458        &self,
21459        ranges: impl IntoIterator<Item = Range<Point>>,
21460    ) -> Vec<MultiBufferDiffHunk> {
21461        let mut hunks = Vec::new();
21462        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21463            HashMap::default();
21464        for query_range in ranges {
21465            let query_rows =
21466                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21467            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21468                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21469            ) {
21470                // Include deleted hunks that are adjacent to the query range, because
21471                // otherwise they would be missed.
21472                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21473                if hunk.status().is_deleted() {
21474                    intersects_range |= hunk.row_range.start == query_rows.end;
21475                    intersects_range |= hunk.row_range.end == query_rows.start;
21476                }
21477                if intersects_range {
21478                    if !processed_buffer_rows
21479                        .entry(hunk.buffer_id)
21480                        .or_default()
21481                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21482                    {
21483                        continue;
21484                    }
21485                    hunks.push(hunk);
21486                }
21487            }
21488        }
21489
21490        hunks
21491    }
21492
21493    fn display_diff_hunks_for_rows<'a>(
21494        &'a self,
21495        display_rows: Range<DisplayRow>,
21496        folded_buffers: &'a HashSet<BufferId>,
21497    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21498        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21499        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21500
21501        self.buffer_snapshot
21502            .diff_hunks_in_range(buffer_start..buffer_end)
21503            .filter_map(|hunk| {
21504                if folded_buffers.contains(&hunk.buffer_id) {
21505                    return None;
21506                }
21507
21508                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21509                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21510
21511                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21512                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21513
21514                let display_hunk = if hunk_display_start.column() != 0 {
21515                    DisplayDiffHunk::Folded {
21516                        display_row: hunk_display_start.row(),
21517                    }
21518                } else {
21519                    let mut end_row = hunk_display_end.row();
21520                    if hunk_display_end.column() > 0 {
21521                        end_row.0 += 1;
21522                    }
21523                    let is_created_file = hunk.is_created_file();
21524                    DisplayDiffHunk::Unfolded {
21525                        status: hunk.status(),
21526                        diff_base_byte_range: hunk.diff_base_byte_range,
21527                        display_row_range: hunk_display_start.row()..end_row,
21528                        multi_buffer_range: Anchor::range_in_buffer(
21529                            hunk.excerpt_id,
21530                            hunk.buffer_id,
21531                            hunk.buffer_range,
21532                        ),
21533                        is_created_file,
21534                    }
21535                };
21536
21537                Some(display_hunk)
21538            })
21539    }
21540
21541    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21542        self.display_snapshot.buffer_snapshot.language_at(position)
21543    }
21544
21545    pub fn is_focused(&self) -> bool {
21546        self.is_focused
21547    }
21548
21549    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21550        self.placeholder_text.as_ref()
21551    }
21552
21553    pub fn scroll_position(&self) -> gpui::Point<f32> {
21554        self.scroll_anchor.scroll_position(&self.display_snapshot)
21555    }
21556
21557    fn gutter_dimensions(
21558        &self,
21559        font_id: FontId,
21560        font_size: Pixels,
21561        max_line_number_width: Pixels,
21562        cx: &App,
21563    ) -> Option<GutterDimensions> {
21564        if !self.show_gutter {
21565            return None;
21566        }
21567
21568        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21569        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21570
21571        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21572            matches!(
21573                ProjectSettings::get_global(cx).git.git_gutter,
21574                Some(GitGutterSetting::TrackedFiles)
21575            )
21576        });
21577        let gutter_settings = EditorSettings::get_global(cx).gutter;
21578        let show_line_numbers = self
21579            .show_line_numbers
21580            .unwrap_or(gutter_settings.line_numbers);
21581        let line_gutter_width = if show_line_numbers {
21582            // Avoid flicker-like gutter resizes when the line number gains another digit by
21583            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21584            let min_width_for_number_on_gutter =
21585                ch_advance * gutter_settings.min_line_number_digits as f32;
21586            max_line_number_width.max(min_width_for_number_on_gutter)
21587        } else {
21588            0.0.into()
21589        };
21590
21591        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21592        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21593
21594        let git_blame_entries_width =
21595            self.git_blame_gutter_max_author_length
21596                .map(|max_author_length| {
21597                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21598                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21599
21600                    /// The number of characters to dedicate to gaps and margins.
21601                    const SPACING_WIDTH: usize = 4;
21602
21603                    let max_char_count = max_author_length.min(renderer.max_author_length())
21604                        + ::git::SHORT_SHA_LENGTH
21605                        + MAX_RELATIVE_TIMESTAMP.len()
21606                        + SPACING_WIDTH;
21607
21608                    ch_advance * max_char_count
21609                });
21610
21611        let is_singleton = self.buffer_snapshot.is_singleton();
21612
21613        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21614        left_padding += if !is_singleton {
21615            ch_width * 4.0
21616        } else if show_runnables || show_breakpoints {
21617            ch_width * 3.0
21618        } else if show_git_gutter && show_line_numbers {
21619            ch_width * 2.0
21620        } else if show_git_gutter || show_line_numbers {
21621            ch_width
21622        } else {
21623            px(0.)
21624        };
21625
21626        let shows_folds = is_singleton && gutter_settings.folds;
21627
21628        let right_padding = if shows_folds && show_line_numbers {
21629            ch_width * 4.0
21630        } else if shows_folds || (!is_singleton && show_line_numbers) {
21631            ch_width * 3.0
21632        } else if show_line_numbers {
21633            ch_width
21634        } else {
21635            px(0.)
21636        };
21637
21638        Some(GutterDimensions {
21639            left_padding,
21640            right_padding,
21641            width: line_gutter_width + left_padding + right_padding,
21642            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21643            git_blame_entries_width,
21644        })
21645    }
21646
21647    pub fn render_crease_toggle(
21648        &self,
21649        buffer_row: MultiBufferRow,
21650        row_contains_cursor: bool,
21651        editor: Entity<Editor>,
21652        window: &mut Window,
21653        cx: &mut App,
21654    ) -> Option<AnyElement> {
21655        let folded = self.is_line_folded(buffer_row);
21656        let mut is_foldable = false;
21657
21658        if let Some(crease) = self
21659            .crease_snapshot
21660            .query_row(buffer_row, &self.buffer_snapshot)
21661        {
21662            is_foldable = true;
21663            match crease {
21664                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21665                    if let Some(render_toggle) = render_toggle {
21666                        let toggle_callback =
21667                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21668                                if folded {
21669                                    editor.update(cx, |editor, cx| {
21670                                        editor.fold_at(buffer_row, window, cx)
21671                                    });
21672                                } else {
21673                                    editor.update(cx, |editor, cx| {
21674                                        editor.unfold_at(buffer_row, window, cx)
21675                                    });
21676                                }
21677                            });
21678                        return Some((render_toggle)(
21679                            buffer_row,
21680                            folded,
21681                            toggle_callback,
21682                            window,
21683                            cx,
21684                        ));
21685                    }
21686                }
21687            }
21688        }
21689
21690        is_foldable |= self.starts_indent(buffer_row);
21691
21692        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21693            Some(
21694                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21695                    .toggle_state(folded)
21696                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21697                        if folded {
21698                            this.unfold_at(buffer_row, window, cx);
21699                        } else {
21700                            this.fold_at(buffer_row, window, cx);
21701                        }
21702                    }))
21703                    .into_any_element(),
21704            )
21705        } else {
21706            None
21707        }
21708    }
21709
21710    pub fn render_crease_trailer(
21711        &self,
21712        buffer_row: MultiBufferRow,
21713        window: &mut Window,
21714        cx: &mut App,
21715    ) -> Option<AnyElement> {
21716        let folded = self.is_line_folded(buffer_row);
21717        if let Crease::Inline { render_trailer, .. } = self
21718            .crease_snapshot
21719            .query_row(buffer_row, &self.buffer_snapshot)?
21720        {
21721            let render_trailer = render_trailer.as_ref()?;
21722            Some(render_trailer(buffer_row, folded, window, cx))
21723        } else {
21724            None
21725        }
21726    }
21727}
21728
21729impl Deref for EditorSnapshot {
21730    type Target = DisplaySnapshot;
21731
21732    fn deref(&self) -> &Self::Target {
21733        &self.display_snapshot
21734    }
21735}
21736
21737#[derive(Clone, Debug, PartialEq, Eq)]
21738pub enum EditorEvent {
21739    InputIgnored {
21740        text: Arc<str>,
21741    },
21742    InputHandled {
21743        utf16_range_to_replace: Option<Range<isize>>,
21744        text: Arc<str>,
21745    },
21746    ExcerptsAdded {
21747        buffer: Entity<Buffer>,
21748        predecessor: ExcerptId,
21749        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21750    },
21751    ExcerptsRemoved {
21752        ids: Vec<ExcerptId>,
21753        removed_buffer_ids: Vec<BufferId>,
21754    },
21755    BufferFoldToggled {
21756        ids: Vec<ExcerptId>,
21757        folded: bool,
21758    },
21759    ExcerptsEdited {
21760        ids: Vec<ExcerptId>,
21761    },
21762    ExcerptsExpanded {
21763        ids: Vec<ExcerptId>,
21764    },
21765    BufferEdited,
21766    Edited {
21767        transaction_id: clock::Lamport,
21768    },
21769    Reparsed(BufferId),
21770    Focused,
21771    FocusedIn,
21772    Blurred,
21773    DirtyChanged,
21774    Saved,
21775    TitleChanged,
21776    DiffBaseChanged,
21777    SelectionsChanged {
21778        local: bool,
21779    },
21780    ScrollPositionChanged {
21781        local: bool,
21782        autoscroll: bool,
21783    },
21784    Closed,
21785    TransactionUndone {
21786        transaction_id: clock::Lamport,
21787    },
21788    TransactionBegun {
21789        transaction_id: clock::Lamport,
21790    },
21791    Reloaded,
21792    CursorShapeChanged,
21793    PushedToNavHistory {
21794        anchor: Anchor,
21795        is_deactivate: bool,
21796    },
21797}
21798
21799impl EventEmitter<EditorEvent> for Editor {}
21800
21801impl Focusable for Editor {
21802    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21803        self.focus_handle.clone()
21804    }
21805}
21806
21807impl Render for Editor {
21808    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21809        let settings = ThemeSettings::get_global(cx);
21810
21811        let mut text_style = match self.mode {
21812            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21813                color: cx.theme().colors().editor_foreground,
21814                font_family: settings.ui_font.family.clone(),
21815                font_features: settings.ui_font.features.clone(),
21816                font_fallbacks: settings.ui_font.fallbacks.clone(),
21817                font_size: rems(0.875).into(),
21818                font_weight: settings.ui_font.weight,
21819                line_height: relative(settings.buffer_line_height.value()),
21820                ..Default::default()
21821            },
21822            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21823                color: cx.theme().colors().editor_foreground,
21824                font_family: settings.buffer_font.family.clone(),
21825                font_features: settings.buffer_font.features.clone(),
21826                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21827                font_size: settings.buffer_font_size(cx).into(),
21828                font_weight: settings.buffer_font.weight,
21829                line_height: relative(settings.buffer_line_height.value()),
21830                ..Default::default()
21831            },
21832        };
21833        if let Some(text_style_refinement) = &self.text_style_refinement {
21834            text_style.refine(text_style_refinement)
21835        }
21836
21837        let background = match self.mode {
21838            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21839            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21840            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21841            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21842        };
21843
21844        EditorElement::new(
21845            &cx.entity(),
21846            EditorStyle {
21847                background,
21848                local_player: cx.theme().players().local(),
21849                text: text_style,
21850                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21851                syntax: cx.theme().syntax().clone(),
21852                status: cx.theme().status().clone(),
21853                inlay_hints_style: make_inlay_hints_style(cx),
21854                inline_completion_styles: make_suggestion_styles(cx),
21855                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21856                show_underlines: !self.mode.is_minimap(),
21857            },
21858        )
21859    }
21860}
21861
21862impl EntityInputHandler for Editor {
21863    fn text_for_range(
21864        &mut self,
21865        range_utf16: Range<usize>,
21866        adjusted_range: &mut Option<Range<usize>>,
21867        _: &mut Window,
21868        cx: &mut Context<Self>,
21869    ) -> Option<String> {
21870        let snapshot = self.buffer.read(cx).read(cx);
21871        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21872        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21873        if (start.0..end.0) != range_utf16 {
21874            adjusted_range.replace(start.0..end.0);
21875        }
21876        Some(snapshot.text_for_range(start..end).collect())
21877    }
21878
21879    fn selected_text_range(
21880        &mut self,
21881        ignore_disabled_input: bool,
21882        _: &mut Window,
21883        cx: &mut Context<Self>,
21884    ) -> Option<UTF16Selection> {
21885        // Prevent the IME menu from appearing when holding down an alphabetic key
21886        // while input is disabled.
21887        if !ignore_disabled_input && !self.input_enabled {
21888            return None;
21889        }
21890
21891        let selection = self.selections.newest::<OffsetUtf16>(cx);
21892        let range = selection.range();
21893
21894        Some(UTF16Selection {
21895            range: range.start.0..range.end.0,
21896            reversed: selection.reversed,
21897        })
21898    }
21899
21900    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21901        let snapshot = self.buffer.read(cx).read(cx);
21902        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21903        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21904    }
21905
21906    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21907        self.clear_highlights::<InputComposition>(cx);
21908        self.ime_transaction.take();
21909    }
21910
21911    fn replace_text_in_range(
21912        &mut self,
21913        range_utf16: Option<Range<usize>>,
21914        text: &str,
21915        window: &mut Window,
21916        cx: &mut Context<Self>,
21917    ) {
21918        if !self.input_enabled {
21919            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21920            return;
21921        }
21922
21923        self.transact(window, cx, |this, window, cx| {
21924            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21925                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21926                Some(this.selection_replacement_ranges(range_utf16, cx))
21927            } else {
21928                this.marked_text_ranges(cx)
21929            };
21930
21931            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21932                let newest_selection_id = this.selections.newest_anchor().id;
21933                this.selections
21934                    .all::<OffsetUtf16>(cx)
21935                    .iter()
21936                    .zip(ranges_to_replace.iter())
21937                    .find_map(|(selection, range)| {
21938                        if selection.id == newest_selection_id {
21939                            Some(
21940                                (range.start.0 as isize - selection.head().0 as isize)
21941                                    ..(range.end.0 as isize - selection.head().0 as isize),
21942                            )
21943                        } else {
21944                            None
21945                        }
21946                    })
21947            });
21948
21949            cx.emit(EditorEvent::InputHandled {
21950                utf16_range_to_replace: range_to_replace,
21951                text: text.into(),
21952            });
21953
21954            if let Some(new_selected_ranges) = new_selected_ranges {
21955                this.change_selections(None, window, cx, |selections| {
21956                    selections.select_ranges(new_selected_ranges)
21957                });
21958                this.backspace(&Default::default(), window, cx);
21959            }
21960
21961            this.handle_input(text, window, cx);
21962        });
21963
21964        if let Some(transaction) = self.ime_transaction {
21965            self.buffer.update(cx, |buffer, cx| {
21966                buffer.group_until_transaction(transaction, cx);
21967            });
21968        }
21969
21970        self.unmark_text(window, cx);
21971    }
21972
21973    fn replace_and_mark_text_in_range(
21974        &mut self,
21975        range_utf16: Option<Range<usize>>,
21976        text: &str,
21977        new_selected_range_utf16: Option<Range<usize>>,
21978        window: &mut Window,
21979        cx: &mut Context<Self>,
21980    ) {
21981        if !self.input_enabled {
21982            return;
21983        }
21984
21985        let transaction = self.transact(window, cx, |this, window, cx| {
21986            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21987                let snapshot = this.buffer.read(cx).read(cx);
21988                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21989                    for marked_range in &mut marked_ranges {
21990                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21991                        marked_range.start.0 += relative_range_utf16.start;
21992                        marked_range.start =
21993                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21994                        marked_range.end =
21995                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21996                    }
21997                }
21998                Some(marked_ranges)
21999            } else if let Some(range_utf16) = range_utf16 {
22000                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22001                Some(this.selection_replacement_ranges(range_utf16, cx))
22002            } else {
22003                None
22004            };
22005
22006            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22007                let newest_selection_id = this.selections.newest_anchor().id;
22008                this.selections
22009                    .all::<OffsetUtf16>(cx)
22010                    .iter()
22011                    .zip(ranges_to_replace.iter())
22012                    .find_map(|(selection, range)| {
22013                        if selection.id == newest_selection_id {
22014                            Some(
22015                                (range.start.0 as isize - selection.head().0 as isize)
22016                                    ..(range.end.0 as isize - selection.head().0 as isize),
22017                            )
22018                        } else {
22019                            None
22020                        }
22021                    })
22022            });
22023
22024            cx.emit(EditorEvent::InputHandled {
22025                utf16_range_to_replace: range_to_replace,
22026                text: text.into(),
22027            });
22028
22029            if let Some(ranges) = ranges_to_replace {
22030                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22031            }
22032
22033            let marked_ranges = {
22034                let snapshot = this.buffer.read(cx).read(cx);
22035                this.selections
22036                    .disjoint_anchors()
22037                    .iter()
22038                    .map(|selection| {
22039                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22040                    })
22041                    .collect::<Vec<_>>()
22042            };
22043
22044            if text.is_empty() {
22045                this.unmark_text(window, cx);
22046            } else {
22047                this.highlight_text::<InputComposition>(
22048                    marked_ranges.clone(),
22049                    HighlightStyle {
22050                        underline: Some(UnderlineStyle {
22051                            thickness: px(1.),
22052                            color: None,
22053                            wavy: false,
22054                        }),
22055                        ..Default::default()
22056                    },
22057                    cx,
22058                );
22059            }
22060
22061            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22062            let use_autoclose = this.use_autoclose;
22063            let use_auto_surround = this.use_auto_surround;
22064            this.set_use_autoclose(false);
22065            this.set_use_auto_surround(false);
22066            this.handle_input(text, window, cx);
22067            this.set_use_autoclose(use_autoclose);
22068            this.set_use_auto_surround(use_auto_surround);
22069
22070            if let Some(new_selected_range) = new_selected_range_utf16 {
22071                let snapshot = this.buffer.read(cx).read(cx);
22072                let new_selected_ranges = marked_ranges
22073                    .into_iter()
22074                    .map(|marked_range| {
22075                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22076                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22077                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22078                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22079                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22080                    })
22081                    .collect::<Vec<_>>();
22082
22083                drop(snapshot);
22084                this.change_selections(None, window, cx, |selections| {
22085                    selections.select_ranges(new_selected_ranges)
22086                });
22087            }
22088        });
22089
22090        self.ime_transaction = self.ime_transaction.or(transaction);
22091        if let Some(transaction) = self.ime_transaction {
22092            self.buffer.update(cx, |buffer, cx| {
22093                buffer.group_until_transaction(transaction, cx);
22094            });
22095        }
22096
22097        if self.text_highlights::<InputComposition>(cx).is_none() {
22098            self.ime_transaction.take();
22099        }
22100    }
22101
22102    fn bounds_for_range(
22103        &mut self,
22104        range_utf16: Range<usize>,
22105        element_bounds: gpui::Bounds<Pixels>,
22106        window: &mut Window,
22107        cx: &mut Context<Self>,
22108    ) -> Option<gpui::Bounds<Pixels>> {
22109        let text_layout_details = self.text_layout_details(window);
22110        let gpui::Size {
22111            width: em_width,
22112            height: line_height,
22113        } = self.character_size(window);
22114
22115        let snapshot = self.snapshot(window, cx);
22116        let scroll_position = snapshot.scroll_position();
22117        let scroll_left = scroll_position.x * em_width;
22118
22119        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22120        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22121            + self.gutter_dimensions.width
22122            + self.gutter_dimensions.margin;
22123        let y = line_height * (start.row().as_f32() - scroll_position.y);
22124
22125        Some(Bounds {
22126            origin: element_bounds.origin + point(x, y),
22127            size: size(em_width, line_height),
22128        })
22129    }
22130
22131    fn character_index_for_point(
22132        &mut self,
22133        point: gpui::Point<Pixels>,
22134        _window: &mut Window,
22135        _cx: &mut Context<Self>,
22136    ) -> Option<usize> {
22137        let position_map = self.last_position_map.as_ref()?;
22138        if !position_map.text_hitbox.contains(&point) {
22139            return None;
22140        }
22141        let display_point = position_map.point_for_position(point).previous_valid;
22142        let anchor = position_map
22143            .snapshot
22144            .display_point_to_anchor(display_point, Bias::Left);
22145        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22146        Some(utf16_offset.0)
22147    }
22148}
22149
22150trait SelectionExt {
22151    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22152    fn spanned_rows(
22153        &self,
22154        include_end_if_at_line_start: bool,
22155        map: &DisplaySnapshot,
22156    ) -> Range<MultiBufferRow>;
22157}
22158
22159impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22160    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22161        let start = self
22162            .start
22163            .to_point(&map.buffer_snapshot)
22164            .to_display_point(map);
22165        let end = self
22166            .end
22167            .to_point(&map.buffer_snapshot)
22168            .to_display_point(map);
22169        if self.reversed {
22170            end..start
22171        } else {
22172            start..end
22173        }
22174    }
22175
22176    fn spanned_rows(
22177        &self,
22178        include_end_if_at_line_start: bool,
22179        map: &DisplaySnapshot,
22180    ) -> Range<MultiBufferRow> {
22181        let start = self.start.to_point(&map.buffer_snapshot);
22182        let mut end = self.end.to_point(&map.buffer_snapshot);
22183        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22184            end.row -= 1;
22185        }
22186
22187        let buffer_start = map.prev_line_boundary(start).0;
22188        let buffer_end = map.next_line_boundary(end).0;
22189        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22190    }
22191}
22192
22193impl<T: InvalidationRegion> InvalidationStack<T> {
22194    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22195    where
22196        S: Clone + ToOffset,
22197    {
22198        while let Some(region) = self.last() {
22199            let all_selections_inside_invalidation_ranges =
22200                if selections.len() == region.ranges().len() {
22201                    selections
22202                        .iter()
22203                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22204                        .all(|(selection, invalidation_range)| {
22205                            let head = selection.head().to_offset(buffer);
22206                            invalidation_range.start <= head && invalidation_range.end >= head
22207                        })
22208                } else {
22209                    false
22210                };
22211
22212            if all_selections_inside_invalidation_ranges {
22213                break;
22214            } else {
22215                self.pop();
22216            }
22217        }
22218    }
22219}
22220
22221impl<T> Default for InvalidationStack<T> {
22222    fn default() -> Self {
22223        Self(Default::default())
22224    }
22225}
22226
22227impl<T> Deref for InvalidationStack<T> {
22228    type Target = Vec<T>;
22229
22230    fn deref(&self) -> &Self::Target {
22231        &self.0
22232    }
22233}
22234
22235impl<T> DerefMut for InvalidationStack<T> {
22236    fn deref_mut(&mut self) -> &mut Self::Target {
22237        &mut self.0
22238    }
22239}
22240
22241impl InvalidationRegion for SnippetState {
22242    fn ranges(&self) -> &[Range<Anchor>] {
22243        &self.ranges[self.active_index]
22244    }
22245}
22246
22247fn inline_completion_edit_text(
22248    current_snapshot: &BufferSnapshot,
22249    edits: &[(Range<Anchor>, String)],
22250    edit_preview: &EditPreview,
22251    include_deletions: bool,
22252    cx: &App,
22253) -> HighlightedText {
22254    let edits = edits
22255        .iter()
22256        .map(|(anchor, text)| {
22257            (
22258                anchor.start.text_anchor..anchor.end.text_anchor,
22259                text.clone(),
22260            )
22261        })
22262        .collect::<Vec<_>>();
22263
22264    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22265}
22266
22267pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22268    match severity {
22269        lsp::DiagnosticSeverity::ERROR => colors.error,
22270        lsp::DiagnosticSeverity::WARNING => colors.warning,
22271        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22272        lsp::DiagnosticSeverity::HINT => colors.info,
22273        _ => colors.ignored,
22274    }
22275}
22276
22277pub fn styled_runs_for_code_label<'a>(
22278    label: &'a CodeLabel,
22279    syntax_theme: &'a theme::SyntaxTheme,
22280) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22281    let fade_out = HighlightStyle {
22282        fade_out: Some(0.35),
22283        ..Default::default()
22284    };
22285
22286    let mut prev_end = label.filter_range.end;
22287    label
22288        .runs
22289        .iter()
22290        .enumerate()
22291        .flat_map(move |(ix, (range, highlight_id))| {
22292            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22293                style
22294            } else {
22295                return Default::default();
22296            };
22297            let mut muted_style = style;
22298            muted_style.highlight(fade_out);
22299
22300            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22301            if range.start >= label.filter_range.end {
22302                if range.start > prev_end {
22303                    runs.push((prev_end..range.start, fade_out));
22304                }
22305                runs.push((range.clone(), muted_style));
22306            } else if range.end <= label.filter_range.end {
22307                runs.push((range.clone(), style));
22308            } else {
22309                runs.push((range.start..label.filter_range.end, style));
22310                runs.push((label.filter_range.end..range.end, muted_style));
22311            }
22312            prev_end = cmp::max(prev_end, range.end);
22313
22314            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22315                runs.push((prev_end..label.text.len(), fade_out));
22316            }
22317
22318            runs
22319        })
22320}
22321
22322pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22323    let mut prev_index = 0;
22324    let mut prev_codepoint: Option<char> = None;
22325    text.char_indices()
22326        .chain([(text.len(), '\0')])
22327        .filter_map(move |(index, codepoint)| {
22328            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22329            let is_boundary = index == text.len()
22330                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22331                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22332            if is_boundary {
22333                let chunk = &text[prev_index..index];
22334                prev_index = index;
22335                Some(chunk)
22336            } else {
22337                None
22338            }
22339        })
22340}
22341
22342pub trait RangeToAnchorExt: Sized {
22343    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22344
22345    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22346        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22347        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22348    }
22349}
22350
22351impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22352    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22353        let start_offset = self.start.to_offset(snapshot);
22354        let end_offset = self.end.to_offset(snapshot);
22355        if start_offset == end_offset {
22356            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22357        } else {
22358            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22359        }
22360    }
22361}
22362
22363pub trait RowExt {
22364    fn as_f32(&self) -> f32;
22365
22366    fn next_row(&self) -> Self;
22367
22368    fn previous_row(&self) -> Self;
22369
22370    fn minus(&self, other: Self) -> u32;
22371}
22372
22373impl RowExt for DisplayRow {
22374    fn as_f32(&self) -> f32 {
22375        self.0 as f32
22376    }
22377
22378    fn next_row(&self) -> Self {
22379        Self(self.0 + 1)
22380    }
22381
22382    fn previous_row(&self) -> Self {
22383        Self(self.0.saturating_sub(1))
22384    }
22385
22386    fn minus(&self, other: Self) -> u32 {
22387        self.0 - other.0
22388    }
22389}
22390
22391impl RowExt for MultiBufferRow {
22392    fn as_f32(&self) -> f32 {
22393        self.0 as f32
22394    }
22395
22396    fn next_row(&self) -> Self {
22397        Self(self.0 + 1)
22398    }
22399
22400    fn previous_row(&self) -> Self {
22401        Self(self.0.saturating_sub(1))
22402    }
22403
22404    fn minus(&self, other: Self) -> u32 {
22405        self.0 - other.0
22406    }
22407}
22408
22409trait RowRangeExt {
22410    type Row;
22411
22412    fn len(&self) -> usize;
22413
22414    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22415}
22416
22417impl RowRangeExt for Range<MultiBufferRow> {
22418    type Row = MultiBufferRow;
22419
22420    fn len(&self) -> usize {
22421        (self.end.0 - self.start.0) as usize
22422    }
22423
22424    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22425        (self.start.0..self.end.0).map(MultiBufferRow)
22426    }
22427}
22428
22429impl RowRangeExt for Range<DisplayRow> {
22430    type Row = DisplayRow;
22431
22432    fn len(&self) -> usize {
22433        (self.end.0 - self.start.0) as usize
22434    }
22435
22436    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22437        (self.start.0..self.end.0).map(DisplayRow)
22438    }
22439}
22440
22441/// If select range has more than one line, we
22442/// just point the cursor to range.start.
22443fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22444    if range.start.row == range.end.row {
22445        range
22446    } else {
22447        range.start..range.start
22448    }
22449}
22450pub struct KillRing(ClipboardItem);
22451impl Global for KillRing {}
22452
22453const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22454
22455enum BreakpointPromptEditAction {
22456    Log,
22457    Condition,
22458    HitCondition,
22459}
22460
22461struct BreakpointPromptEditor {
22462    pub(crate) prompt: Entity<Editor>,
22463    editor: WeakEntity<Editor>,
22464    breakpoint_anchor: Anchor,
22465    breakpoint: Breakpoint,
22466    edit_action: BreakpointPromptEditAction,
22467    block_ids: HashSet<CustomBlockId>,
22468    editor_margins: Arc<Mutex<EditorMargins>>,
22469    _subscriptions: Vec<Subscription>,
22470}
22471
22472impl BreakpointPromptEditor {
22473    const MAX_LINES: u8 = 4;
22474
22475    fn new(
22476        editor: WeakEntity<Editor>,
22477        breakpoint_anchor: Anchor,
22478        breakpoint: Breakpoint,
22479        edit_action: BreakpointPromptEditAction,
22480        window: &mut Window,
22481        cx: &mut Context<Self>,
22482    ) -> Self {
22483        let base_text = match edit_action {
22484            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22485            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22486            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22487        }
22488        .map(|msg| msg.to_string())
22489        .unwrap_or_default();
22490
22491        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22492        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22493
22494        let prompt = cx.new(|cx| {
22495            let mut prompt = Editor::new(
22496                EditorMode::AutoHeight {
22497                    max_lines: Self::MAX_LINES as usize,
22498                },
22499                buffer,
22500                None,
22501                window,
22502                cx,
22503            );
22504            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22505            prompt.set_show_cursor_when_unfocused(false, cx);
22506            prompt.set_placeholder_text(
22507                match edit_action {
22508                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22509                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22510                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22511                },
22512                cx,
22513            );
22514
22515            prompt
22516        });
22517
22518        Self {
22519            prompt,
22520            editor,
22521            breakpoint_anchor,
22522            breakpoint,
22523            edit_action,
22524            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22525            block_ids: Default::default(),
22526            _subscriptions: vec![],
22527        }
22528    }
22529
22530    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22531        self.block_ids.extend(block_ids)
22532    }
22533
22534    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22535        if let Some(editor) = self.editor.upgrade() {
22536            let message = self
22537                .prompt
22538                .read(cx)
22539                .buffer
22540                .read(cx)
22541                .as_singleton()
22542                .expect("A multi buffer in breakpoint prompt isn't possible")
22543                .read(cx)
22544                .as_rope()
22545                .to_string();
22546
22547            editor.update(cx, |editor, cx| {
22548                editor.edit_breakpoint_at_anchor(
22549                    self.breakpoint_anchor,
22550                    self.breakpoint.clone(),
22551                    match self.edit_action {
22552                        BreakpointPromptEditAction::Log => {
22553                            BreakpointEditAction::EditLogMessage(message.into())
22554                        }
22555                        BreakpointPromptEditAction::Condition => {
22556                            BreakpointEditAction::EditCondition(message.into())
22557                        }
22558                        BreakpointPromptEditAction::HitCondition => {
22559                            BreakpointEditAction::EditHitCondition(message.into())
22560                        }
22561                    },
22562                    cx,
22563                );
22564
22565                editor.remove_blocks(self.block_ids.clone(), None, cx);
22566                cx.focus_self(window);
22567            });
22568        }
22569    }
22570
22571    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22572        self.editor
22573            .update(cx, |editor, cx| {
22574                editor.remove_blocks(self.block_ids.clone(), None, cx);
22575                window.focus(&editor.focus_handle);
22576            })
22577            .log_err();
22578    }
22579
22580    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22581        let settings = ThemeSettings::get_global(cx);
22582        let text_style = TextStyle {
22583            color: if self.prompt.read(cx).read_only(cx) {
22584                cx.theme().colors().text_disabled
22585            } else {
22586                cx.theme().colors().text
22587            },
22588            font_family: settings.buffer_font.family.clone(),
22589            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22590            font_size: settings.buffer_font_size(cx).into(),
22591            font_weight: settings.buffer_font.weight,
22592            line_height: relative(settings.buffer_line_height.value()),
22593            ..Default::default()
22594        };
22595        EditorElement::new(
22596            &self.prompt,
22597            EditorStyle {
22598                background: cx.theme().colors().editor_background,
22599                local_player: cx.theme().players().local(),
22600                text: text_style,
22601                ..Default::default()
22602            },
22603        )
22604    }
22605}
22606
22607impl Render for BreakpointPromptEditor {
22608    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22609        let editor_margins = *self.editor_margins.lock();
22610        let gutter_dimensions = editor_margins.gutter;
22611        h_flex()
22612            .key_context("Editor")
22613            .bg(cx.theme().colors().editor_background)
22614            .border_y_1()
22615            .border_color(cx.theme().status().info_border)
22616            .size_full()
22617            .py(window.line_height() / 2.5)
22618            .on_action(cx.listener(Self::confirm))
22619            .on_action(cx.listener(Self::cancel))
22620            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22621            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22622    }
22623}
22624
22625impl Focusable for BreakpointPromptEditor {
22626    fn focus_handle(&self, cx: &App) -> FocusHandle {
22627        self.prompt.focus_handle(cx)
22628    }
22629}
22630
22631fn all_edits_insertions_or_deletions(
22632    edits: &Vec<(Range<Anchor>, String)>,
22633    snapshot: &MultiBufferSnapshot,
22634) -> bool {
22635    let mut all_insertions = true;
22636    let mut all_deletions = true;
22637
22638    for (range, new_text) in edits.iter() {
22639        let range_is_empty = range.to_offset(&snapshot).is_empty();
22640        let text_is_empty = new_text.is_empty();
22641
22642        if range_is_empty != text_is_empty {
22643            if range_is_empty {
22644                all_deletions = false;
22645            } else {
22646                all_insertions = false;
22647            }
22648        } else {
22649            return false;
22650        }
22651
22652        if !all_insertions && !all_deletions {
22653            return false;
22654        }
22655    }
22656    all_insertions || all_deletions
22657}
22658
22659struct MissingEditPredictionKeybindingTooltip;
22660
22661impl Render for MissingEditPredictionKeybindingTooltip {
22662    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22663        ui::tooltip_container(window, cx, |container, _, cx| {
22664            container
22665                .flex_shrink_0()
22666                .max_w_80()
22667                .min_h(rems_from_px(124.))
22668                .justify_between()
22669                .child(
22670                    v_flex()
22671                        .flex_1()
22672                        .text_ui_sm(cx)
22673                        .child(Label::new("Conflict with Accept Keybinding"))
22674                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22675                )
22676                .child(
22677                    h_flex()
22678                        .pb_1()
22679                        .gap_1()
22680                        .items_end()
22681                        .w_full()
22682                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22683                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22684                        }))
22685                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22686                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22687                        })),
22688                )
22689        })
22690    }
22691}
22692
22693#[derive(Debug, Clone, Copy, PartialEq)]
22694pub struct LineHighlight {
22695    pub background: Background,
22696    pub border: Option<gpui::Hsla>,
22697    pub include_gutter: bool,
22698    pub type_id: Option<TypeId>,
22699}
22700
22701fn render_diff_hunk_controls(
22702    row: u32,
22703    status: &DiffHunkStatus,
22704    hunk_range: Range<Anchor>,
22705    is_created_file: bool,
22706    line_height: Pixels,
22707    editor: &Entity<Editor>,
22708    _window: &mut Window,
22709    cx: &mut App,
22710) -> AnyElement {
22711    h_flex()
22712        .h(line_height)
22713        .mr_1()
22714        .gap_1()
22715        .px_0p5()
22716        .pb_1()
22717        .border_x_1()
22718        .border_b_1()
22719        .border_color(cx.theme().colors().border_variant)
22720        .rounded_b_lg()
22721        .bg(cx.theme().colors().editor_background)
22722        .gap_1()
22723        .block_mouse_except_scroll()
22724        .shadow_md()
22725        .child(if status.has_secondary_hunk() {
22726            Button::new(("stage", row as u64), "Stage")
22727                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22728                .tooltip({
22729                    let focus_handle = editor.focus_handle(cx);
22730                    move |window, cx| {
22731                        Tooltip::for_action_in(
22732                            "Stage Hunk",
22733                            &::git::ToggleStaged,
22734                            &focus_handle,
22735                            window,
22736                            cx,
22737                        )
22738                    }
22739                })
22740                .on_click({
22741                    let editor = editor.clone();
22742                    move |_event, _window, cx| {
22743                        editor.update(cx, |editor, cx| {
22744                            editor.stage_or_unstage_diff_hunks(
22745                                true,
22746                                vec![hunk_range.start..hunk_range.start],
22747                                cx,
22748                            );
22749                        });
22750                    }
22751                })
22752        } else {
22753            Button::new(("unstage", row as u64), "Unstage")
22754                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22755                .tooltip({
22756                    let focus_handle = editor.focus_handle(cx);
22757                    move |window, cx| {
22758                        Tooltip::for_action_in(
22759                            "Unstage Hunk",
22760                            &::git::ToggleStaged,
22761                            &focus_handle,
22762                            window,
22763                            cx,
22764                        )
22765                    }
22766                })
22767                .on_click({
22768                    let editor = editor.clone();
22769                    move |_event, _window, cx| {
22770                        editor.update(cx, |editor, cx| {
22771                            editor.stage_or_unstage_diff_hunks(
22772                                false,
22773                                vec![hunk_range.start..hunk_range.start],
22774                                cx,
22775                            );
22776                        });
22777                    }
22778                })
22779        })
22780        .child(
22781            Button::new(("restore", row as u64), "Restore")
22782                .tooltip({
22783                    let focus_handle = editor.focus_handle(cx);
22784                    move |window, cx| {
22785                        Tooltip::for_action_in(
22786                            "Restore Hunk",
22787                            &::git::Restore,
22788                            &focus_handle,
22789                            window,
22790                            cx,
22791                        )
22792                    }
22793                })
22794                .on_click({
22795                    let editor = editor.clone();
22796                    move |_event, window, cx| {
22797                        editor.update(cx, |editor, cx| {
22798                            let snapshot = editor.snapshot(window, cx);
22799                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22800                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22801                        });
22802                    }
22803                })
22804                .disabled(is_created_file),
22805        )
22806        .when(
22807            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22808            |el| {
22809                el.child(
22810                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22811                        .shape(IconButtonShape::Square)
22812                        .icon_size(IconSize::Small)
22813                        // .disabled(!has_multiple_hunks)
22814                        .tooltip({
22815                            let focus_handle = editor.focus_handle(cx);
22816                            move |window, cx| {
22817                                Tooltip::for_action_in(
22818                                    "Next Hunk",
22819                                    &GoToHunk,
22820                                    &focus_handle,
22821                                    window,
22822                                    cx,
22823                                )
22824                            }
22825                        })
22826                        .on_click({
22827                            let editor = editor.clone();
22828                            move |_event, window, cx| {
22829                                editor.update(cx, |editor, cx| {
22830                                    let snapshot = editor.snapshot(window, cx);
22831                                    let position =
22832                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22833                                    editor.go_to_hunk_before_or_after_position(
22834                                        &snapshot,
22835                                        position,
22836                                        Direction::Next,
22837                                        window,
22838                                        cx,
22839                                    );
22840                                    editor.expand_selected_diff_hunks(cx);
22841                                });
22842                            }
22843                        }),
22844                )
22845                .child(
22846                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22847                        .shape(IconButtonShape::Square)
22848                        .icon_size(IconSize::Small)
22849                        // .disabled(!has_multiple_hunks)
22850                        .tooltip({
22851                            let focus_handle = editor.focus_handle(cx);
22852                            move |window, cx| {
22853                                Tooltip::for_action_in(
22854                                    "Previous Hunk",
22855                                    &GoToPreviousHunk,
22856                                    &focus_handle,
22857                                    window,
22858                                    cx,
22859                                )
22860                            }
22861                        })
22862                        .on_click({
22863                            let editor = editor.clone();
22864                            move |_event, window, cx| {
22865                                editor.update(cx, |editor, cx| {
22866                                    let snapshot = editor.snapshot(window, cx);
22867                                    let point =
22868                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22869                                    editor.go_to_hunk_before_or_after_position(
22870                                        &snapshot,
22871                                        point,
22872                                        Direction::Prev,
22873                                        window,
22874                                        cx,
22875                                    );
22876                                    editor.expand_selected_diff_hunks(cx);
22877                                });
22878                            }
22879                        }),
22880                )
22881            },
22882        )
22883        .into_any_element()
22884}